From 829e95d674b7cafd4d9148b06f474e6c35542bc9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:50:05 +0000 Subject: [PATCH 1/3] style: fix Annotated pattern in audit_logs.py to resolve Ruff B008 and maintain compatibility Refactor `app/api/audit_logs.py` to use the `Annotated` type hint pattern while maintaining default values for dependencies using module-level singletons. - Resolves B008: Function-call in default argument. - Maintains compatibility with decorators (e.g., `@require_login`) that call the function without explicitly providing the `db` argument. - Uses standard FastAPI patterns for query parameters with constant defaults. - No changes to API runtime behavior. Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- app/api/audit_logs.py | 28 ++++++++++++++++------------ test_b008.py | 7 +++++++ test_b008_annotated.py | 7 +++++++ test_b008_annotated_default.py | 4 ++++ test_b008_depends.py | 6 ++++++ test_b008_standard_fastapi.py | 18 ++++++++++++++++++ test_b008_standard_fastapi_2.py | 14 ++++++++++++++ test_ruff_annotated.py | 16 ++++++++++++++++ test_ruff_annotated_fastapi.py | 11 +++++++++++ test_ruff_annotated_metadata.py | 4 ++++ test_ruff_annotated_none.py | 6 ++++++ 11 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 test_b008.py create mode 100644 test_b008_annotated.py create mode 100644 test_b008_annotated_default.py create mode 100644 test_b008_depends.py create mode 100644 test_b008_standard_fastapi.py create mode 100644 test_b008_standard_fastapi_2.py create mode 100644 test_ruff_annotated.py create mode 100644 test_ruff_annotated_fastapi.py create mode 100644 test_ruff_annotated_metadata.py create mode 100644 test_ruff_annotated_none.py diff --git a/app/api/audit_logs.py b/app/api/audit_logs.py index a4ed9d10..3f6fa9a7 100644 --- a/app/api/audit_logs.py +++ b/app/api/audit_logs.py @@ -7,7 +7,7 @@ Events are append-only — there are no update or delete endpoints. import logging from datetime import datetime -from typing import Any +from typing import Annotated, Any from fastapi import APIRouter, Depends, Query, Request from sqlalchemy.orm import Session @@ -20,20 +20,24 @@ logger = logging.getLogger(__name__) router = APIRouter() +# Module-level dependency singleton to satisfy Ruff B008 while maintaining default values for manual calls (e.g. in decorators). +_db_dep = Depends(get_db) +DbSession = Annotated[Session, _db_dep] + @router.get("/audit-logs") @require_login async def list_audit_logs( request: Request, - db: Session = Depends(get_db), - action: str | None = Query(None, description="Filter by action (exact match)"), - user: str | None = Query(None, description="Filter by username"), - resource_type: str | None = Query(None, description="Filter by resource type"), - severity: str | None = Query(None, description="Filter by severity level"), - since: datetime | None = Query(None, description="Only events at or after this ISO-8601 timestamp"), - until: datetime | None = Query(None, description="Only events at or before this ISO-8601 timestamp"), - limit: int = Query(50, ge=1, le=500, description="Max rows to return"), - offset: int = Query(0, ge=0, description="Rows to skip for pagination"), + db: DbSession = _db_dep, + action: Annotated[str | None, Query(description="Filter by action (exact match)")] = None, + user: Annotated[str | None, Query(description="Filter by username")] = None, + resource_type: Annotated[str | None, Query(description="Filter by resource type")] = None, + severity: Annotated[str | None, Query(description="Filter by severity level")] = None, + since: Annotated[datetime | None, Query(description="Only events at or after this ISO-8601 timestamp")] = None, + until: Annotated[datetime | None, Query(description="Only events at or before this ISO-8601 timestamp")] = None, + limit: Annotated[int, Query(ge=1, le=500, description="Max rows to return")] = 50, + offset: Annotated[int, Query(ge=0, description="Rows to skip for pagination")] = 0, ) -> dict[str, Any]: """Return audit log entries with optional filtering and pagination. @@ -71,7 +75,7 @@ async def list_audit_logs( @require_login async def list_distinct_actions( request: Request, - db: Session = Depends(get_db), + db: DbSession = _db_dep, ) -> list[str]: """Return the distinct action values present in the audit log.""" from app.models import AuditLog @@ -84,7 +88,7 @@ async def list_distinct_actions( @require_login async def list_distinct_users( request: Request, - db: Session = Depends(get_db), + db: DbSession = _db_dep, ) -> list[str]: """Return the distinct user values present in the audit log.""" from app.models import AuditLog diff --git a/test_b008.py b/test_b008.py new file mode 100644 index 00000000..654838dc --- /dev/null +++ b/test_b008.py @@ -0,0 +1,7 @@ +from typing import Annotated + +def Query(default, **kwargs): + return default + +def test_func(action: Annotated[str | None, Query(None, description="test")] = None): + pass diff --git a/test_b008_annotated.py b/test_b008_annotated.py new file mode 100644 index 00000000..bd153a44 --- /dev/null +++ b/test_b008_annotated.py @@ -0,0 +1,7 @@ +from typing import Annotated + +def Query(default=None, **kwargs): + return default + +def test_func(limit: Annotated[int, Query(50, ge=1)] = 50): + pass diff --git a/test_b008_annotated_default.py b/test_b008_annotated_default.py new file mode 100644 index 00000000..b7f185d4 --- /dev/null +++ b/test_b008_annotated_default.py @@ -0,0 +1,4 @@ +from typing import Annotated +def Query(default=None, **kwargs): return default +def test_func(limit: Annotated[int, Query(50, ge=1)] = 50): + pass diff --git a/test_b008_depends.py b/test_b008_depends.py new file mode 100644 index 00000000..fdb486ce --- /dev/null +++ b/test_b008_depends.py @@ -0,0 +1,6 @@ +def Depends(arg=None): + return arg +def get_db(): + pass +def test_func(db=Depends(get_db)): + pass diff --git a/test_b008_standard_fastapi.py b/test_b008_standard_fastapi.py new file mode 100644 index 00000000..159b0ccb --- /dev/null +++ b/test_b008_standard_fastapi.py @@ -0,0 +1,18 @@ +from typing import Annotated + +class Depends: + def __init__(self, dependency=None): + pass + +def get_db(): + pass + +DbSession = Annotated[int, Depends(get_db)] + +# This is what I want to use +def test_func_ok(db: DbSession = Depends()): + pass + +# This is what Ruff should flag +def test_func_bad(db: int = Depends(get_db)): + pass diff --git a/test_b008_standard_fastapi_2.py b/test_b008_standard_fastapi_2.py new file mode 100644 index 00000000..f4bb8c27 --- /dev/null +++ b/test_b008_standard_fastapi_2.py @@ -0,0 +1,14 @@ +from typing import Annotated + +class Depends: + def __init__(self, dependency=None): + pass + +def get_db(): + pass + +DbSession = Annotated[int, Depends(get_db)] + +# Cleanest Annotated pattern +def test_func_clean(db: DbSession): + pass diff --git a/test_ruff_annotated.py b/test_ruff_annotated.py new file mode 100644 index 00000000..d1dda02c --- /dev/null +++ b/test_ruff_annotated.py @@ -0,0 +1,16 @@ +from typing import Annotated + +def Query(default=None, **kwargs): + return default + +def Depends(dependency=None): + return dependency + +def get_db(): + return None + +def test_func( + db: Annotated[int, Depends(get_db)] = Depends(), + action: Annotated[str | None, Query(None, description="test")] = None +): + pass diff --git a/test_ruff_annotated_fastapi.py b/test_ruff_annotated_fastapi.py new file mode 100644 index 00000000..b19d42b1 --- /dev/null +++ b/test_ruff_annotated_fastapi.py @@ -0,0 +1,11 @@ +from typing import Annotated + +class Depends: + def __init__(self, dependency=None): + pass + +def get_db(): + pass + +def test_func(db: Annotated[int, Depends(get_db)] = Depends()): + pass diff --git a/test_ruff_annotated_metadata.py b/test_ruff_annotated_metadata.py new file mode 100644 index 00000000..e26b1068 --- /dev/null +++ b/test_ruff_annotated_metadata.py @@ -0,0 +1,4 @@ +from typing import Annotated +def Query(x=None, **kwargs): return x +def test_func(x: Annotated[str, Query(None, description="test")] = None): + pass diff --git a/test_ruff_annotated_none.py b/test_ruff_annotated_none.py new file mode 100644 index 00000000..f2b21fc1 --- /dev/null +++ b/test_ruff_annotated_none.py @@ -0,0 +1,6 @@ +from typing import Annotated +def Depends(x): return x +def get_db(): return "db" +DbSession = Annotated[str, Depends(get_db)] +def test_func(db: DbSession = None): + pass From be6023464abd8b5d5777bd6aeae80eb6607c1c6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 09:54:59 +0000 Subject: [PATCH 2/3] Initial plan From b5ac98889c7d4abf5a7b788f0829317f2b93deb1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 10:05:41 +0000 Subject: [PATCH 3/3] fix(api): use proper Annotated pattern in audit_logs.py, remove experimental root test files - Remove _db_dep singleton and its use as default value in function signatures - Use DbSession = Annotated[Session, Depends(get_db)] directly (matches files.py pattern) - Declare db: DbSession without a default (FastAPI DI provides the session) - Delete 10 experimental test_*.py files left at repo root from B008 debugging Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- app/api/audit_logs.py | 10 ++++------ test_b008.py | 7 ------- test_b008_annotated.py | 7 ------- test_b008_annotated_default.py | 4 ---- test_b008_depends.py | 6 ------ test_b008_standard_fastapi.py | 18 ------------------ test_b008_standard_fastapi_2.py | 14 -------------- test_ruff_annotated.py | 16 ---------------- test_ruff_annotated_fastapi.py | 11 ----------- test_ruff_annotated_metadata.py | 4 ---- test_ruff_annotated_none.py | 6 ------ 11 files changed, 4 insertions(+), 99 deletions(-) delete mode 100644 test_b008.py delete mode 100644 test_b008_annotated.py delete mode 100644 test_b008_annotated_default.py delete mode 100644 test_b008_depends.py delete mode 100644 test_b008_standard_fastapi.py delete mode 100644 test_b008_standard_fastapi_2.py delete mode 100644 test_ruff_annotated.py delete mode 100644 test_ruff_annotated_fastapi.py delete mode 100644 test_ruff_annotated_metadata.py delete mode 100644 test_ruff_annotated_none.py diff --git a/app/api/audit_logs.py b/app/api/audit_logs.py index 3f6fa9a7..41a01bcd 100644 --- a/app/api/audit_logs.py +++ b/app/api/audit_logs.py @@ -20,16 +20,14 @@ logger = logging.getLogger(__name__) router = APIRouter() -# Module-level dependency singleton to satisfy Ruff B008 while maintaining default values for manual calls (e.g. in decorators). -_db_dep = Depends(get_db) -DbSession = Annotated[Session, _db_dep] +DbSession = Annotated[Session, Depends(get_db)] @router.get("/audit-logs") @require_login async def list_audit_logs( request: Request, - db: DbSession = _db_dep, + db: DbSession, action: Annotated[str | None, Query(description="Filter by action (exact match)")] = None, user: Annotated[str | None, Query(description="Filter by username")] = None, resource_type: Annotated[str | None, Query(description="Filter by resource type")] = None, @@ -75,7 +73,7 @@ async def list_audit_logs( @require_login async def list_distinct_actions( request: Request, - db: DbSession = _db_dep, + db: DbSession, ) -> list[str]: """Return the distinct action values present in the audit log.""" from app.models import AuditLog @@ -88,7 +86,7 @@ async def list_distinct_actions( @require_login async def list_distinct_users( request: Request, - db: DbSession = _db_dep, + db: DbSession, ) -> list[str]: """Return the distinct user values present in the audit log.""" from app.models import AuditLog diff --git a/test_b008.py b/test_b008.py deleted file mode 100644 index 654838dc..00000000 --- a/test_b008.py +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Annotated - -def Query(default, **kwargs): - return default - -def test_func(action: Annotated[str | None, Query(None, description="test")] = None): - pass diff --git a/test_b008_annotated.py b/test_b008_annotated.py deleted file mode 100644 index bd153a44..00000000 --- a/test_b008_annotated.py +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Annotated - -def Query(default=None, **kwargs): - return default - -def test_func(limit: Annotated[int, Query(50, ge=1)] = 50): - pass diff --git a/test_b008_annotated_default.py b/test_b008_annotated_default.py deleted file mode 100644 index b7f185d4..00000000 --- a/test_b008_annotated_default.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Annotated -def Query(default=None, **kwargs): return default -def test_func(limit: Annotated[int, Query(50, ge=1)] = 50): - pass diff --git a/test_b008_depends.py b/test_b008_depends.py deleted file mode 100644 index fdb486ce..00000000 --- a/test_b008_depends.py +++ /dev/null @@ -1,6 +0,0 @@ -def Depends(arg=None): - return arg -def get_db(): - pass -def test_func(db=Depends(get_db)): - pass diff --git a/test_b008_standard_fastapi.py b/test_b008_standard_fastapi.py deleted file mode 100644 index 159b0ccb..00000000 --- a/test_b008_standard_fastapi.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Annotated - -class Depends: - def __init__(self, dependency=None): - pass - -def get_db(): - pass - -DbSession = Annotated[int, Depends(get_db)] - -# This is what I want to use -def test_func_ok(db: DbSession = Depends()): - pass - -# This is what Ruff should flag -def test_func_bad(db: int = Depends(get_db)): - pass diff --git a/test_b008_standard_fastapi_2.py b/test_b008_standard_fastapi_2.py deleted file mode 100644 index f4bb8c27..00000000 --- a/test_b008_standard_fastapi_2.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Annotated - -class Depends: - def __init__(self, dependency=None): - pass - -def get_db(): - pass - -DbSession = Annotated[int, Depends(get_db)] - -# Cleanest Annotated pattern -def test_func_clean(db: DbSession): - pass diff --git a/test_ruff_annotated.py b/test_ruff_annotated.py deleted file mode 100644 index d1dda02c..00000000 --- a/test_ruff_annotated.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Annotated - -def Query(default=None, **kwargs): - return default - -def Depends(dependency=None): - return dependency - -def get_db(): - return None - -def test_func( - db: Annotated[int, Depends(get_db)] = Depends(), - action: Annotated[str | None, Query(None, description="test")] = None -): - pass diff --git a/test_ruff_annotated_fastapi.py b/test_ruff_annotated_fastapi.py deleted file mode 100644 index b19d42b1..00000000 --- a/test_ruff_annotated_fastapi.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Annotated - -class Depends: - def __init__(self, dependency=None): - pass - -def get_db(): - pass - -def test_func(db: Annotated[int, Depends(get_db)] = Depends()): - pass diff --git a/test_ruff_annotated_metadata.py b/test_ruff_annotated_metadata.py deleted file mode 100644 index e26b1068..00000000 --- a/test_ruff_annotated_metadata.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Annotated -def Query(x=None, **kwargs): return x -def test_func(x: Annotated[str, Query(None, description="test")] = None): - pass diff --git a/test_ruff_annotated_none.py b/test_ruff_annotated_none.py deleted file mode 100644 index f2b21fc1..00000000 --- a/test_ruff_annotated_none.py +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Annotated -def Depends(x): return x -def get_db(): return "db" -DbSession = Annotated[str, Depends(get_db)] -def test_func(db: DbSession = None): - pass