Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ repos:
- id: check-added-large-files
args: [ '--maxkb=1024' ]
- id: detect-private-key
- id: end-of-file-fixer
- id: mixed-line-ending
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.16.9
Expand All @@ -39,24 +38,25 @@ repos:
hooks:
- id: uv-lock
name: Update uv lockfile
args:
- --upgrade
- id: uv-sync
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v2.3.1
hooks:
- id: mypy
name: Static type checking with mypy
# The hook runs in its own virtualenv, so it needs every package the
# checked code imports, including the optional backends.
additional_dependencies:
- types-redis
- types-requests
- types-PyYAML
- types-orjson
- fastapi>=0.110.0
- starlette>=0.36.0
- pydantic>=2.0.0
- pytest>=8.0.0
- pytest-asyncio>=0.23.0
- fastapi>=0.110.0
- starlette>=0.36.0
- types-aiofiles
- redis>=5.3.0
- types-redis
- orjson
- types-orjson
- pymemcache>=4.0.0
- PyJWT>=2.9.0
args: [--strict]
exclude: ^(docs/|scripts/)
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Four non-abstract atomic primitives live on the base class with non-atomic fallb

### Code Quality Rules

- Ruff is configured with `extend-select = ['ALL']` with specific ignores (see `pyproject.toml`). Notable: E501 (line length), B008 (function calls in defaults), FBT001/FBT002 (boolean args — intentional for Cache-Control API).
- Ruff is configured with `extend-select = ['ALL']` with specific ignores (see `pyproject.toml`). Notable: E501 (line length), FBT001/FBT002 (boolean args — intentional for Cache-Control API). `fastapi.Depends` is allowed in argument defaults via `flake8-bugbear.extend-immutable-calls` rather than ignoring B008.
- mypy runs in strict mode on the package (not tests).
- pydocstring convention is Google style.
- Forward references are mostly quoted annotations with `TYPE_CHECKING` imports; only a couple of modules use `from __future__ import annotations`.
Expand Down
3 changes: 3 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ uv run pre-commit run --all-files
The hooks cover the standard pre-commit-hooks checks, `ruff` (with `--fix`) and
`ruff-format`, `typos`, `uv-lock`/`uv-sync`, and strict `mypy` (excluding
`docs/` and `scripts/`). They run automatically on `git commit`. If any checks fail, fix the issues and try committing again.
`uv-lock` only re-resolves the lockfile when `pyproject.toml` changed; it does not
upgrade pinned versions. Upgrades come from Renovate or an explicit
`uv lock --upgrade`.

pre-commit only sees the files you touched. The **Lint** workflow checks the
whole tree; run the same commands before pushing:
Expand Down
4 changes: 2 additions & 2 deletions fastapi_cachex/backends/memcached.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ def __init__(
"""
try:
from pymemcache import HashClient
except ImportError:
except ImportError as exc:
msg = "pymemcache is not installed. Install it with the extra: pip install 'fastapi-cachex[memcached]'"
raise CacheXError(msg)
raise CacheXError(msg) from exc

# Pooled connections have no ordering guarantee between each other, so
# every write waits for the server's acknowledgement; otherwise a
Expand Down
4 changes: 2 additions & 2 deletions fastapi_cachex/backends/redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ def __init__(
# builtins.__import__("redis") can simulate absence reliably.
import redis # noqa: F401
from redis.asyncio import Redis as AsyncRedis
except ImportError:
except ImportError as exc:
msg = (
"redis[hiredis] is not installed. Please install it with "
"'pip install \"redis[hiredis]\"' "
)
raise CacheXError(msg)
raise CacheXError(msg) from exc

_warn_if_not_utf8(encoding)

Expand Down
2 changes: 1 addition & 1 deletion fastapi_cachex/session/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ async def send_wrapper(message: Message) -> None:

await self.app(scope, receive, send_wrapper)

async def _persist( # noqa: PLR0913
async def _persist( # noqa: PLR0913, PLR0917
self,
session: _RequestSession,
headers: MutableHeaders,
Expand Down
27 changes: 17 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,18 @@ ignore = [
"E501",
"ANN401",
"COM812", # redundant rule, use formatter to fix
"B008", # do not perform function calls in argument defaults
"B904", # Allow raising exceptions without from e, for HTTPException
"FBT001", "FBT002", # Boolean arguments are part of Cache-Control API design
"S105", # false-positive on token_format strings
"C901", # allow slightly complex session flow
"CPY001", # no copyright header convention in this project (stabilized in ruff 0.16)
"PLR0917", # backend constructors take many positional options; keyword-only would break the API
]
preview = true
explicit-preview-rules = true
extend-select = ['ALL']

[tool.ruff.lint.flake8-bugbear]
# FastAPI dependency markers are meant to be called in argument defaults.
extend-immutable-calls = ["fastapi.Depends"]

[tool.ruff.lint.isort]
force-single-line = true

Expand All @@ -115,6 +115,7 @@ keep-runtime-typing = true
"tests/**" = [
"D",
"S101",
"S105",
"S106",
"ARG",
"ANN",
Expand All @@ -130,10 +131,14 @@ keep-runtime-typing = true
"S101", # Internal invariant guard, not a validation shortcut
]
"fastapi_cachex/backends/memcached.py" = ["PLC0415"] # Optional dependency
"fastapi_cachex/backends/redis.py" = ["PLR0913", "PLC0415"] # Optional dependency, Redis config
"fastapi_cachex/lock.py" = ["PLR0913"] # Configurable lock parameters
"fastapi_cachex/proxy.py" = ["PLW0603"] # Global backend management by design
"fastapi_cachex/session/manager.py" = ["PLR0915"] # Session/security validation branches needed
# PLR0917: these constructors take many positional options; making them
# keyword-only would break the public API.
"fastapi_cachex/backends/redis.py" = ["PLR0913", "PLR0917", "PLC0415"] # Optional dependency, Redis config
"fastapi_cachex/lock.py" = ["PLR0913", "PLR0917"] # Configurable lock parameters
"fastapi_cachex/session/manager.py" = [
"PLR0915", # Session/security validation branches needed
"S105", # token_format = "simple" / "jwt" is not a password
]

[tool.ruff.format]
docstring-code-format = true
Expand All @@ -158,8 +163,10 @@ exclude_lines = [
"if TYPE_CHECKING:",
"raise NotImplementedError",
"if __name__ == .__main__.:",
"pass",
"\\.\\.\\.",
# Anchored: a bare "pass" or "..." would also exclude any line (and the
# block it opens) containing "password", "bypass" or "Field(...".
"^\\s*pass\\s*(#.*)?$",
"^\\s*\\.\\.\\.\\s*(#.*)?$",
]
fail_under = 90
show_missing = true
Expand Down
Loading