[project] name = "v2x-server" version = "0.1.0" description = "FastAPI service backed by MySQL with Keycloak-issued OIDC authentication." readme = "README.md" requires-python = ">=3.13" dependencies = [ "fastapi>=0.115", "uvicorn[standard]>=0.32", "gunicorn>=23.0", "sqlalchemy[asyncio]>=2.0.36", "asyncmy>=0.2.10", "alembic>=1.14", "pydantic>=2.10", "pydantic-settings>=2.7", "pyjwt[crypto]>=2.10", "httpx>=0.28", "python-json-logger>=3.2", ] [dependency-groups] dev = [ "pytest>=8.3", "pytest-asyncio>=0.25", "pytest-cov>=6.0", "mypy>=1.14", "ruff>=0.9", "pre-commit>=4.0", "types-pyyaml>=6.0", ] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/v2x_server"] [tool.uv] default-groups = ["dev"] [tool.ruff] line-length = 100 target-version = "py313" src = ["src", "tests"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "I", # isort "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade "ASYNC",# flake8-async "S", # flake8-bandit "T20", # flake8-print "SIM", # flake8-simplify "RUF", ] ignore = [ "S101", # assert is fine (pytest) ] [tool.ruff.lint.per-file-ignores] "tests/**" = ["S105", "S106"] # hardcoded test credentials are expected "migrations/**" = ["I001"] [tool.mypy] python_version = "3.13" strict = true warn_unreachable = true plugins = ["pydantic.mypy"] mypy_path = "src" packages = ["v2x_server"] [[tool.mypy.overrides]] module = ["asyncmy.*", "alembic.*"] ignore_missing_imports = true [tool.pytest.ini_options] asyncio_mode = "auto" # Must match the test loop scope (function). If fixtures run on a session loop # while tests run on a per-function loop, asyncmy's loop-bound futures raise # "attached to a different loop". aiosqlite hides this; MySQL does not. asyncio_default_fixture_loop_scope = "function" testpaths = ["tests"] addopts = "-ra --strict-markers" filterwarnings = ["error"] [tool.coverage.run] source = ["src/v2x_server"] branch = true