feat(): format & proper startup (make main async for uvicorn to inherit current asyncio event loop)

This commit is contained in:
doas root
2025-11-10 23:19:51 +03:00
parent 5ca3e72834
commit 08a2ae6456
5 changed files with 809 additions and 309 deletions
+3 -2
View File
@@ -13,6 +13,7 @@ dependencies = [
"argon2_cffi==23.1.0", "argon2_cffi==23.1.0",
"cryptography==46.0.3", "cryptography==46.0.3",
"httpx==0.28.1", "httpx==0.28.1",
"psycopg[binary]>=3.2.12",
] ]
[dependency-groups] [dependency-groups]
@@ -37,7 +38,7 @@ tests = [
dev = [ dev = [
{ include-group = "tests" }, { include-group = "tests" },
{ include-group = "linters" }, { include-group = "linters" },
{ include-group = "migrations"}, { include-group = "migrations" },
] ]
[project.scripts] [project.scripts]
@@ -138,7 +139,7 @@ ignore = [
"PLR6301", # do not require classmethod / staticmethod when self not used "PLR6301", # do not require classmethod / staticmethod when self not used
"TRY003", # long exception messages from `tryceratops` "TRY003", # long exception messages from `tryceratops`
] ]
external = [ "WPS" ] external = ["WPS"]
[tool.ruff.lint.per-file-ignores] [tool.ruff.lint.per-file-ignores]
"tests/*.py" = [ "tests/*.py" = [
+7
View File
@@ -1,3 +1,5 @@
import asyncio
import sys
from logging.config import fileConfig from logging.config import fileConfig
import os import os
from pathlib import Path from pathlib import Path
@@ -7,6 +9,9 @@ from sqlalchemy import pool
from alembic import context from alembic import context
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
from template_project.web_api.configuration import load_configuration from template_project.web_api.configuration import load_configuration
# this is the Alembic Config object, which provides # this is the Alembic Config object, which provides
@@ -23,11 +28,13 @@ if config.config_file_name is not None:
# from myapp import mymodel # from myapp import mymodel
# target_metadata = mymodel.Base.metadata # target_metadata = mymodel.Base.metadata
from template_project.adapters.data_gateways.tables import meta_data from template_project.adapters.data_gateways.tables import meta_data
target_metadata = meta_data target_metadata = meta_data
configuration = load_configuration(Path(os.environ["CONFIGURATION_PATH"])) configuration = load_configuration(Path(os.environ["CONFIGURATION_PATH"]))
config.set_main_option("sqlalchemy.url", configuration.database.url.get_value()) config.set_main_option("sqlalchemy.url", configuration.database.url.get_value())
# other values from the config, defined by the needs of env.py, # other values from the config, defined by the needs of env.py,
# can be acquired: # can be acquired:
# my_important_option = config.get_main_option("my_important_option") # my_important_option = config.get_main_option("my_important_option")
+9 -8
View File
@@ -1,6 +1,7 @@
import argparse import argparse
import asyncio import asyncio
import os import os
import selectors
import sys import sys
from collections.abc import AsyncIterator from collections.abc import AsyncIterator
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
@@ -70,27 +71,27 @@ def make_asgi_application(
return app return app
def _main( async def _main(
configuration_path: Path, configuration_path: Path,
) -> None: ) -> None:
configuration = load_configuration(configuration_path) configuration = load_configuration(configuration_path)
ioc = make_ioc(configuration) ioc = make_ioc(configuration)
asgi_application = make_asgi_application(ioc) asgi_application = make_asgi_application(ioc)
uvicorn.run( config = uvicorn.Config(
asgi_application, app=asgi_application,
port=configuration.server.port,
host=configuration.server.host, host=configuration.server.host,
port=configuration.server.port,
log_config=LOG_CONFIG, log_config=LOG_CONFIG,
access_log=configuration.server.access_log, access_log=configuration.server.access_log,
) )
server = uvicorn.Server(config)
await server.serve()
def main() -> None: def main() -> None:
if sys.platform == "win32": if sys.platform == "win32":
from asyncio import WindowsSelectorEventLoopPolicy # noqa: PLC0415 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
arg_parser = argparse.ArgumentParser() arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("configuration", default=None) arg_parser.add_argument("configuration", default=None)
@@ -103,7 +104,7 @@ def main() -> None:
"pass the path to the config or specify it in the environment variables `CONFIGURATION_PATH`", "pass the path to the config or specify it in the environment variables `CONFIGURATION_PATH`",
) )
_main(Path(configuration_path)) asyncio.run(_main(Path(configuration_path)))
if __name__ == "__main__": if __name__ == "__main__":
@@ -1,3 +1,5 @@
import asyncio
from dishka import FromDishka from dishka import FromDishka
from dishka.integrations.fastapi import DishkaRoute from dishka.integrations.fastapi import DishkaRoute
from fastapi import APIRouter from fastapi import APIRouter
Generated
+727 -238
View File
File diff suppressed because it is too large Load Diff