Wye — это облегченная библиотека ASGI.
Вы должны установить сервер ASGI: uvicorn, daphne, или hypercorn.
pip install uvicorn
Принимает какой-то текст или байты и возвращает в формате который вы укажите
в аргументе media_type
from wye import Response
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = Response('Hello, world!', media_type='text/plain')
await response(receive, send)
Принимает какой-то текст или байты и возвращает данные в формате text/html
from wye import HTMLResponse
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = HTMLResponse('<html><body><h1>Hello, world!</h1></body></html>')
await response(receive, send)
Принимает какой-то текст или байты и возвращает данные в формате text/plain
from wye import PlainTextResponse
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = PlainTextResponse('Hello, world!')
await response(receive, send)
Принимает какой-то словарь (Dict
) и возвращает данные в формате application/json
from wye import JSONResponse
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = JSONResponse({"data": "Hello, world!"})
await response(receive, send)
Принимает какой-то генератор и возвращает данные в формате который вы укажите
from wye import StreamingResponse
async def generator():
for num in range(1, 11):
yield str(num)
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = StreamingResponse(generator, media_type = "text/plain")
await response(receive, send)
Принимает название файла и возвращает файл
from wye import FileResponse
class App:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, receive, send):
response = FileResponse("example_file.txt", path = "folder/example")
await response(receive, send)
WebSocket, который выполняет ту же роль, что и HTTP-запрос, но позволяет отправлять и получать данные в сеансе веб-сокета.
from starlette import WebSocket
class App:
def __init__(self, scope):
self.scope = scope
async def __call__(self, receive, send):
session = WebSocket(self.scope, receive=receive, send=send)
await session.accept()
await session.send_text('Hello, socket!')
await session.close()
await session.accept(subprotocol=None)
await session.send_text(data)
await session.send_bytes(data)
await session.send_json(data)
await session.receive_text()
await session.receive_bytes()
await session.receive_json()
await session.close(code=1000)
from wye import (
Router, Path, PlainTextResponse
)
class Home:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, recieve, send):
response = PlainTextResponse(content = "Home")
await response(recieve, send)
class About:
def __init__(self, scope) -> None:
self.scope = scope
async def __call__(self, recieve, send):
response = PlainTextResponse(content = "About")
await response(recieve, send)
app = Router([
Path(path = "/home", app = Home),
Path(path = "/about", app = About)
])
from wye import (
Wye, PlainTextResponse, FileResponse
)
app = Wye()
@app.route("/")
async def home(request):
return PlainTextResponse("home")
@app.route(
"/test",
response_class = PlainTextResponse
)
async def test(request):
return "home"
@app.route("/about")
async def about(request):
return FileResponse("about.pdf")
-
.add_route(path, func, methods=["GET"])
- добавить маршрут Функция должна принимать параметрrequest
и возвращатьResponse
, example:func(request, **kwargs) -> response
-
.route(path, *, response_class)
- Добавить маршрут Функция должна принимать параметрrequest
и возвращатьOptional[Response]
, example:func(request, **kwargs) -> Optional[response]
Форматдекоратор
Аргументы:
path: str
- путьresponse_class: Type[Response]
- класс ответа
-
add_websocket_route(path, route)
- Добавить маршрут сеанса веб-сокета. Функция должна быть сопрограмой. Сигнатура:func(session, **kwargs)
-
.websocket_route(path)
- Добавить маршрут WebSocket, формат декоратора. -
.mount(path)
- Монтировать приложениеWye
config
(str
) - название файла конфигурации (будет искать в корневом каталоге вашего проекта) Все данные прочитанные из файла будут записываться в глобальный стейт приложенияWye
Пример:
📦 main_app
┣ 📜 app.py
┗ 📜 config.ini
📜 config.ini
:
[example]
example_1 = 10
example_2 = False
example_3 = "example"
example_4 = 3.14
[default]
example_1 = ["example", "example", "example"]
📜 app.py
:
from wye import Wye
app = Wye(config = "config.ini")
app.state["example"]["example_1"]
from wye import (
Wye, PlainTextResponse, StaticFiles
)
app = Wye()
app.mount("/static", app = StaticFiles(directory = "static"))
app.mount("/example", app = StaticFiles(directory = "example"))
@app.route("/")
async def home(request):
return PlainTextResponse("home")
Разбор следующей файловой структуры:
📦 main_app
┣ 📜 __init__.py
┣ 📜 app.py
┣ 📂 app_search
┃ ┃ ┣ 📜 __init__.py
┃ ┃ ┣ 📜 app.py
┃ ┃ ┗ ...
┃ ┗ ...
┗ ...
файл 📦 main_app > 📂 app_search > 📜 app.py
from wye import (
Wye, StaticFiles
)
app = Wye()
app.mount("/static", StaticFiles("static"))
файл 📦 main_app > 📜 app.py
from wye import (
Wye, StaticFiles
)
from app_search.app import app as app_search
app = Wye()
app.mount("/app_search", app_search)
При монтирование приложений, в которых находятся приложение StaticFiles
лучше указывать путь названием таким, которое содержит сама папка, в данном случае app_search
. Так Wye
поймёт где искать файл
Запрос, который принимет ваш обработчик:
from wye import Request
Сигнатура: Request(scope, receive=None)
Request.url
- получить url, по которому был запросRequest.method
- получить методRequest.query_params
- получить данные строки запросы
await Request.body()
- Тело запроса в байтахawait Request.json()
- Тело запроса, проанализированное какJSON
Вы также можете получить данные через async for
:
async def app(receive, send):
request = Request(scope, receive)
body = b''
async for chunk in request.stream():
body += chunk
from wye import URL
Сигнатура: URL(url: str | bytes)
Request.url
- получить url, по которому был запросRequest.url.query_string
- получить строку запросаRequest.url.path
- получить путь, по которому был сделанRequest.url.scheme
- получить протоколRequest.url.netloc
- получить сетевое расположение
from wye import Headers
Сигнатура: Headers(raw_headers = None)
Request.headers
- получить HeadersRequest.headers.values()
- получить значенияRequest.headers.keys()
- получить ключиRequest.headers.items()
- получить список заголовковRequest.headers.get(key)
- получить заголовок(название, значение)
from wye import QueryParams
Сигнатура: Headers(raw_params = None)
Request.query_params
- получить QueryParamsRequest.query_params.values()
- получить значенияRequest.query_params.keys()
- получить ключиRequest.query_params.items()
- получить список паметры строкиRequest.query_params.get(key)
- получить параметр строки(название, значение)
src
- wye/serializers
lib
- wye/lib/serializers
from wye.serializers import Serializer
Пример:
from wye.serializers import Serializer
from wye.serializers import fields
class Serializer1(Serializer):
param_1: int = fields.INT(default=10, alias="param1")
param_2: str = fields.STR(alias="param2")
param_3: float = fields.FLOAT()
param_4: bool = fields.BOOL(alias="param4")
class Serializer2(Serializer):
param_1: Serializer_1 = fields.SERIALIZER(alias="param1")
param_2: int = fields.INT(alias="param2")
param_3: list = fields.LIST(alias="param3", fill_type=int)
class Serializer3(Serializer2):
param_3: Serializer2 = fields.SERIALIZER(alias="param3")
param_4: int = fields.INT(alias="param4")
Методы:
.is_validate(json: Union[Dict[str, Any], List[Dict[str, Any]]])
- Провалидировать обьекты. ВозвращаетTuple[bool, Union[Dict[str, Any], List[Dict[str, Any]]]]
from wye.serializers import build_json
build_json(json: Union[Dict[str, Any], List[Dict[str, Any]]], serializer: Type[Serializer])
- Собираетjson
по правилам из объектовdict
. ВозвращаетUnion[Dict[str, Any], List[Dict[str, Any]]]
from wye.serializers import build_json_from_object
build_json_from_object(objects: Union[Type, List[Type]], serializer: Type[Serializer])
- Собираетjson
по правилам из объектов. ВозвращаетUnion[Dict[str, Any], List[Dict[str, Any]]]
from wye.serializers import fields
Следующие аргументы:
default: Any
- дефолтное значение, работает если поле необязательное (param_1: Optional[int]
), по умолчаниюNone
alias: str
- публичное имя поля, по умолчаниюNone
required: bool
- обязательный ли параметрvalidators: Callable[[Any], Any]
- валидаторы, принимают один параметр, пример:from wye.serializers import Serializer from wye.serializers import fields def validator(value): return value * 10 class Serializer2(Serializer): param_1: int = fields.INT(validators=[validator])
max_length: int
- для строковых значений это добавляет соответствующую проверкуmin_length: int
- для строковых значений это добавляет соответствующую проверкуgt: Union[int, float]
- для числовых значений (int, float) добавляет проверкубольше чем
ge: Union[int, float]
- для числовых значений это добавляет проверкубольше или равно
lt: Union[int, float]
- для числовых значений это добавляет проверкуменьше чем
le: Union[int, float]
- для числовых значений это добавляет проверкуменьше или равно
fill_type: Union[int, list, dict, float, set, frozenset, tuple, bool, Type[Serializer]]
- тип заполнения (этот аргумент имеется только вfields.LIST
,fields.LIST_SERIALIZERS
)fill_types: Iterable[int, list, dict, float, set, frozenset, tuple, bool]
- тип заполнения (этот аргумент имеется только вfields.TUPLE
)
- Типы:
fields.BOOL
- Булевое значениеfields.STR
- Строкаfields.INT
- Целочисленное числоfields.FLOAT
- Число с плавающей точкойfields.SERIALIZER
- Вложенный сериализаторfields.BYTES
- байтыfields.LIST
- массив (имеет один тип заполнения)fields.TUPLE
- кортеж (имеет несколько типов заполнения)fields.LIST_SERIALIZERS
- вложенный сериализатор