Skip to content

Commit

Permalink
Add pattern support to param (#1336)
Browse files Browse the repository at this point in the history
* Add pattern support to param

* Refactor regex to pattern in param functions
  • Loading branch information
sunfkny authored Nov 13, 2024
1 parent 8786c68 commit ee0f27b
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 19 deletions.
6 changes: 3 additions & 3 deletions ninja/params/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Pattern, TypeVar, Union

from typing_extensions import Annotated

Expand Down Expand Up @@ -86,7 +86,7 @@ def P(
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -104,7 +104,7 @@ def P(
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand Down
30 changes: 15 additions & 15 deletions ninja/params/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# what it basically does makes function XXX that create instance of models.XXX
# and annotates function with result = Any
# idea from https://github.com/tiangolo/fastapi/blob/master/fastapi/param_functions.py
from typing import Any, Dict, Optional
from typing import Any, Dict, Optional, Pattern, Union

from ninja.params import models

Expand All @@ -20,7 +20,7 @@ def Path( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -38,7 +38,7 @@ def Path( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -59,7 +59,7 @@ def Query( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -77,7 +77,7 @@ def Query( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -98,7 +98,7 @@ def Header( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -116,7 +116,7 @@ def Header( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -137,7 +137,7 @@ def Cookie( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -155,7 +155,7 @@ def Cookie( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -176,7 +176,7 @@ def Body( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -194,7 +194,7 @@ def Body( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -215,7 +215,7 @@ def Form( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -233,7 +233,7 @@ def Form( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand All @@ -254,7 +254,7 @@ def File( # noqa: N802
le: Optional[float] = None,
min_length: Optional[int] = None,
max_length: Optional[int] = None,
regex: Optional[str] = None,
pattern: Union[str, Pattern[str], None] = None,
example: Any = None,
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
Expand All @@ -272,7 +272,7 @@ def File( # noqa: N802
le=le,
min_length=min_length,
max_length=max_length,
regex=regex,
pattern=pattern,
example=example,
examples=examples,
deprecated=deprecated,
Expand Down
15 changes: 14 additions & 1 deletion ninja/params/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
from abc import ABC, abstractmethod
from collections import defaultdict
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, TypeVar
from typing import (
TYPE_CHECKING,
Any,
Dict,
List,
Optional,
Pattern,
Tuple,
Type,
TypeVar,
Union,
)

from django.conf import settings
from django.http import HttpRequest
Expand Down Expand Up @@ -204,6 +215,7 @@ def __init__(
examples: Optional[Dict[str, Any]] = None,
deprecated: Optional[bool] = None,
include_in_schema: Optional[bool] = True,
pattern: Union[str, Pattern[str], None] = None,
# param_name: str = None,
# param_type: Any = None,
**extra: Any,
Expand Down Expand Up @@ -237,6 +249,7 @@ def __init__(
le=le,
min_length=min_length,
max_length=max_length,
pattern=pattern,
json_schema_extra=json_schema_extra,
**extra,
)
Expand Down
5 changes: 5 additions & 0 deletions tests/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ def get_path_param_le_ge_int(request, item_id: int = Path(..., le=3, ge=1)):
return item_id


@router.get("/path/param-pattern/{item_id}")
def get_path_param_pattern(request, item_id: str = Path(..., pattern="^foo")):
return item_id


@router.get("/path/param-django-str/{str:item_id}")
def get_path_param_django_str(request, item_id):
return item_id
Expand Down
16 changes: 16 additions & 0 deletions tests/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,20 @@ def test_text_get():
}


response_not_valid_pattern = {
"detail": [
{
"ctx": {
"pattern": "^foo",
},
"loc": ["path", "item_id"],
"msg": "String should match pattern '^foo'",
"type": "string_pattern_mismatch",
}
]
}


@pytest.mark.parametrize(
"path,expected_status,expected_response",
[
Expand Down Expand Up @@ -249,6 +263,8 @@ def test_text_get():
("/path/param-le-ge-int/3", 200, 3),
("/path/param-le-ge-int/4", 422, response_less_than_equal_3),
("/path/param-le-ge-int/2.7", 422, response_not_valid_int_float),
("/path/param-pattern/foo", 200, "foo"),
("/path/param-pattern/fo", 422, response_not_valid_pattern),
],
)
def test_get_path(path, expected_status, expected_response):
Expand Down

0 comments on commit ee0f27b

Please sign in to comment.