[fastapi] Update FAST002 to check keyword-only arguments (#15119)

## Summary

Close #15117. Update `FAST002` to check keyword-only arguments.

## Test Plan

New test case
This commit is contained in:
Harutaka Kawamura 2024-12-23 19:02:42 +09:00 committed by GitHub
parent 1c3d11e8a8
commit 8440f3ea9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 81 additions and 16 deletions

View file

@ -57,6 +57,9 @@ def get_users(
pass
@app.get("/items/{item_id}")
async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
pass
# Non fixable errors

View file

@ -99,9 +99,15 @@ pub(crate) fn fastapi_non_annotated_dependency(
let mut updatable_count = 0;
let mut has_non_updatable_default = false;
let total_params = function_def.parameters.args.len();
let total_params =
function_def.parameters.args.len() + function_def.parameters.kwonlyargs.len();
for parameter in &function_def.parameters.args {
for parameter in function_def
.parameters
.args
.iter()
.chain(&function_def.parameters.kwonlyargs)
{
let needs_update = matches!(
(&parameter.parameter.annotation, &parameter.default),
(Some(_annotation), Some(default)) if is_fastapi_dependency(checker, default)

View file

@ -1,5 +1,6 @@
---
source: crates/ruff_linter/src/rules/fastapi/mod.rs
snapshot_kind: text
---
FAST002.py:24:5: FAST002 [*] FastAPI dependency without `Annotated`
|
@ -320,13 +321,40 @@ FAST002.py:53:5: FAST002 [*] FastAPI dependency without `Annotated`
55 56 | limit: int = 10,
56 57 | ):
FAST002.py:67:5: FAST002 FastAPI dependency without `Annotated`
FAST002.py:61:25: FAST002 [*] FastAPI dependency without `Annotated`
|
65 | skip: int = 0,
66 | limit: int = 10,
67 | current_user: User = Depends(get_current_user),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
68 | ):
69 | pass
60 | @app.get("/items/{item_id}")
61 | async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
62 | pass
|
= help: Replace with `typing.Annotated`
Unsafe fix
12 12 | Security,
13 13 | )
14 14 | from pydantic import BaseModel
15 |+from typing import Annotated
15 16 |
16 17 | app = FastAPI()
17 18 | router = APIRouter()
--------------------------------------------------------------------------------
58 59 |
59 60 |
60 61 | @app.get("/items/{item_id}")
61 |-async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
62 |+async def read_items(*, item_id: Annotated[int, Path(title="The ID of the item to get")], q: str):
62 63 | pass
63 64 |
64 65 | # Non fixable errors
FAST002.py:70:5: FAST002 FastAPI dependency without `Annotated`
|
68 | skip: int = 0,
69 | limit: int = 10,
70 | current_user: User = Depends(get_current_user),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
71 | ):
72 | pass
|
= help: Replace with `typing.Annotated`

View file

@ -1,5 +1,6 @@
---
source: crates/ruff_linter/src/rules/fastapi/mod.rs
snapshot_kind: text
---
FAST002.py:24:5: FAST002 [*] FastAPI dependency without `Annotated`
|
@ -320,13 +321,40 @@ FAST002.py:53:5: FAST002 [*] FastAPI dependency without `Annotated`
55 56 | limit: int = 10,
56 57 | ):
FAST002.py:67:5: FAST002 FastAPI dependency without `Annotated`
FAST002.py:61:25: FAST002 [*] FastAPI dependency without `Annotated`
|
65 | skip: int = 0,
66 | limit: int = 10,
67 | current_user: User = Depends(get_current_user),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
68 | ):
69 | pass
60 | @app.get("/items/{item_id}")
61 | async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
62 | pass
|
= help: Replace with `typing_extensions.Annotated`
Unsafe fix
12 12 | Security,
13 13 | )
14 14 | from pydantic import BaseModel
15 |+from typing_extensions import Annotated
15 16 |
16 17 | app = FastAPI()
17 18 | router = APIRouter()
--------------------------------------------------------------------------------
58 59 |
59 60 |
60 61 | @app.get("/items/{item_id}")
61 |-async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str):
62 |+async def read_items(*, item_id: Annotated[int, Path(title="The ID of the item to get")], q: str):
62 63 | pass
63 64 |
64 65 | # Non fixable errors
FAST002.py:70:5: FAST002 FastAPI dependency without `Annotated`
|
68 | skip: int = 0,
69 | limit: int = 10,
70 | current_user: User = Depends(get_current_user),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FAST002
71 | ):
72 | pass
|
= help: Replace with `typing_extensions.Annotated`