[project] name = "fastapi-420" version = "1.0.1" description = "Enhance Your Calm - Advanced Rate Limiting & DDoS Protection for FastAPI" readme = "README.md" license = {text = "MIT"} requires-python = ">=3.14" keywords = ["fastapi", "rate-limiting", "ddos", "security", "api", "420"] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Framework :: FastAPI", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Internet :: WWW/HTTP", "Topic :: Security", "Typing :: Typed", ] dependencies = [ "fastapi[standard]>=0.129.0", "pydantic>=2.12.5,<3.0.0", "pydantic-settings>=2.13.0", "redis>=7.2.0", "pyjwt>=2.11.0", ] [project.optional-dependencies] dev = [ "pytest>=9.0.2", "pytest-asyncio>=1.3.0", "pytest-cov>=7.0.0", "httpx>=0.28.1", "fakeredis>=2.34.0", "time-machine>=3.2.0", "asgi-lifespan>=2.1.0", "mypy>=1.19.1", "types-redis>=4.6.0.20241004", "ruff>=0.15.1", "pylint>=4.0.4", "pylint-pydantic>=0.4.1", "pylint-per-file-ignores>=3.2.0", "pre-commit>=4.5.1", ] [project.urls] Homepage = "https://github.com/CarterPerez-dev/Cybersecurity-Projects" Documentation = "https://github.com/CarterPerez-dev/Cybersecurity-Projects/blob/main/PROJECTS/advanced/api-rate-limiter/examples/USAGE.md" Repository = "https://github.com/CarterPerez-dev/Cybersecurity-Projects/tree/main/PROJECTS/advanced/api-rate-limiter" Issues = "https://github.com/CarterPerez-dev/Cybersecurity-Projects/issues" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["src/fastapi_420"] [tool.ruff] target-version = "py314" line-length = 88 src = ["src"] exclude = ["alembic"] [tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes "B", # flake8-bugbear "C4", # flake8-comprehensions "UP", # pyupgrade "ARG", # flake8-unused-arguments "SIM", # flake8-simplify "PTH", # flake8-use-pathlib "RUF", # ruff-specific "ASYNC", # flake8-async "S", # flake8-bandit (security) "N", # pep8-naming ] ignore = [ "E501", # line too long (formatter handles this) "B008", # function call in default argument (FastAPI Depends) "S101", # assert usage (needed for tests) "S104", # 0.0.0.0 binding (intentional for Docker) "S105", # "bearer" token_type is not a password "ARG001", # unused function argument (common in FastAPI deps) "E712", # == False is REQUIRED for SQLAlchemy WHERE clauses "N999", # PascalCase module names (intentional: Base.py, User.py) "N818", # exception naming convention (style preference) "UP046", # Generic[T] syntax (keep for compatibility) "RUF005", # list concatenation style (preference) ] [tool.ruff.lint.per-file-ignores] [tool.mypy] python_version = "3.14" strict = true warn_return_any = true warn_unused_ignores = true disallow_untyped_defs = true disallow_incomplete_defs = true plugins = ["pydantic.mypy"] exclude = ["alembic", ".venv", "venv"] [[tool.mypy.overrides]] module = ["tests.*", "conftest"] ignore_errors = true [[tool.mypy.overrides]] module = ["core.logging"] disable_error_code = ["no-any-return"] [[tool.mypy.overrides]] module = [ "uuid6", "structlog", "structlog.*", "pwdlib", "slowapi", "slowapi.*", ] ignore_missing_imports = true [tool.pydantic-mypy] init_forbid_extra = true init_typed = true warn_required_dynamic_aliases = true [tool.pylint.main] py-version = "3.14" jobs = 4 load-plugins = [ "pylint_pydantic", "pylint_per_file_ignores", ] persistent = true ignore = [ "alembic", "venv", ".venv", "__pycache__", "build", "dist", ".git", ".pytest_cache", ".mypy_cache", ".ruff_cache", ] ignore-paths = [ "^alembic/.*", "^venv/.*", "^.venv/.*", "^build/.*", "^dist/.*", ] [tool.pylint.messages_control] disable = [ "C0103", # invalid-name "C0116", # missing-function-docstring (we use minimal docs) "C0121", # singleton-comparison (== False required for SQLAlchemy) "C0301", # line-too-long "C0302", # too-many-lines "C0303", # trailing-whitespace "C0304", # final-newline-missing "C0305", # trailing-newlines "C0411", # wrong-import-order "C0412", # ungrouped-imports (style preference) "E0401", # import-error (uuid6/structlog/pwdlib not found by pylint) "E0611", # no-name-in-module (false positive for config re-exports) "E1102", # not-callable (false positive for SQLAlchemy func.now/count) "E1136", # unsubscriptable-object (false positive for generics) "R0801", # similar-lines "R0901", # too-many-ancestors (SQLAlchemy inheritance) "R0903", # too-few-public-methods "R0917", # too-many-positional-arguments (FastAPI patterns) "W0611", # unused-import (handled by ruff, config.py re-exports) "W0612", # unused-variable (handled by ruff) "W0613", # unused-argument (handled by ruff) "W0621", # redefined-outer-name (FastAPI route/param naming) "W0622", # redefined-builtin "W0718", # broad-exception-caught (intentional in health/rate-limit) ] [tool.pylint.format] max-line-length = 95 [tool.pylint.design] max-args = 12 max-attributes = 10 max-branches = 15 max-locals = 20 max-statements = 55 [tool.pytest.ini_options] asyncio_mode = "auto" asyncio_default_fixture_loop_scope = "function" testpaths = ["tests"] addopts = "-ra -q" filterwarnings = [ "ignore::DeprecationWarning", ] [tool.coverage.run] branch = true source = ["src"] [tool.coverage.report] exclude_lines = [ "pragma: no cover", "if TYPE_CHECKING:", "raise NotImplementedError", ] [tool.ty.src] include = ["src", "tests"] exclude = ["alembic/versions/**", ".venv/**"] respect-ignore-files = true [tool.ty.environment] python-version = "3.14" root = ["./src"] python = "./.venv" [tool.ty.rules] possibly-missing-attribute = "error" possibly-missing-import = "error" unused-ignore-comment = "warn" redundant-cast = "warn" undefined-reveal = "warn"