[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "bangui-backend" version = "0.9.0" description = "BanGUI backend — fail2ban web management interface" requires-python = ">=3.12" dependencies = [ "fastapi>=0.115.0", "uvicorn[standard]>=0.32.0", "pydantic>=2.9.0", "pydantic-settings>=2.6.0", "aiosqlite>=0.20.0", "aiohttp>=3.11.0", "apscheduler>=3.10,<4.0", "structlog>=24.4.0", "bcrypt>=4.2.0", "geoip2>=4.8.0", ] [project.optional-dependencies] dev = [ "pytest>=8.3.0", "pytest-asyncio>=0.24.0", "httpx>=0.27.0", "ruff>=0.8.0", "mypy>=1.13.0", "pytest-cov>=6.0.0", "pytest-mock>=3.14.0", ] [tool.hatch.build.targets.wheel] packages = ["app"] [tool.ruff] line-length = 120 target-version = "py312" [tool.ruff.lint] select = ["E", "F", "W", "I", "N", "UP", "B", "C4", "SIM", "TCH"] ignore = ["B008"] # FastAPI uses function calls in default arguments (Depends) [tool.ruff.lint.per-file-ignores] # sys.path manipulation before stdlib imports is intentional in test helpers # pytest evaluates fixture type annotations at runtime, so TC001/TC002/TC003 are false-positives "tests/**" = ["E402", "TC001", "TC002", "TC003"] "app/routers/**" = ["TC001", "TC002"] # FastAPI evaluates Depends() type aliases at runtime via get_type_hints() [tool.ruff.format] quote-style = "double" [tool.mypy] python_version = "3.12" strict = true plugins = ["pydantic.mypy"] [tool.pytest.ini_options] asyncio_mode = "auto" pythonpath = [".", "../fail2ban-master"] testpaths = ["tests"] addopts = "--cov=app --cov-report=term-missing"