|
|
|
@ -3,7 +3,6 @@ from typing import List |
|
|
|
import pytest |
|
|
|
from dirty_equals import AnyThing, IsDict, IsOneOf, IsPartialDict |
|
|
|
from fastapi import FastAPI, Header |
|
|
|
from fastapi._compat import PYDANTIC_V2 |
|
|
|
from fastapi.testclient import TestClient |
|
|
|
from pydantic import BaseModel, Field |
|
|
|
from typing_extensions import Annotated |
|
|
|
@ -109,7 +108,7 @@ class HeaderModelRequiredListAlias(BaseModel): |
|
|
|
async def read_model_required_list_alias( |
|
|
|
p: Annotated[HeaderModelRequiredListAlias, Header()], |
|
|
|
): |
|
|
|
return {"p": p.p} # pragma: no cover |
|
|
|
return {"p": p.p} |
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize( |
|
|
|
@ -168,15 +167,7 @@ def test_required_list_alias_missing(path: str): |
|
|
|
"path", |
|
|
|
[ |
|
|
|
"/required-list-alias", |
|
|
|
pytest.param( |
|
|
|
"/model-required-list-alias", |
|
|
|
marks=pytest.mark.xfail( |
|
|
|
raises=AssertionError, |
|
|
|
condition=PYDANTIC_V2, |
|
|
|
reason="Fails only with PDv2 models", |
|
|
|
strict=False, |
|
|
|
), |
|
|
|
), |
|
|
|
"/model-required-list-alias", |
|
|
|
], |
|
|
|
) |
|
|
|
def test_required_list_alias_by_name(path: str): |
|
|
|
@ -190,9 +181,7 @@ def test_required_list_alias_by_name(path: str): |
|
|
|
"type": "missing", |
|
|
|
"loc": ["header", "p_alias"], |
|
|
|
"msg": "Field required", |
|
|
|
"input": IsOneOf( # /model-required-list-alias with PDv2 fails here |
|
|
|
None, IsPartialDict({"p": ["hello", "world"]}) |
|
|
|
), |
|
|
|
"input": IsOneOf(None, IsPartialDict({"p": ["hello", "world"]})), |
|
|
|
} |
|
|
|
] |
|
|
|
} |
|
|
|
@ -214,18 +203,13 @@ def test_required_list_alias_by_name(path: str): |
|
|
|
"path", |
|
|
|
[ |
|
|
|
"/required-list-alias", |
|
|
|
pytest.param( |
|
|
|
"/model-required-list-alias", |
|
|
|
marks=pytest.mark.xfail(raises=AssertionError, strict=False), |
|
|
|
), |
|
|
|
"/model-required-list-alias", |
|
|
|
], |
|
|
|
) |
|
|
|
def test_required_list_alias_by_alias(path: str): |
|
|
|
client = TestClient(app) |
|
|
|
response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) |
|
|
|
assert response.status_code == 200, ( # /model-required-list-alias fails here |
|
|
|
response.text |
|
|
|
) |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
assert response.json() == {"p": ["hello", "world"]} |
|
|
|
|
|
|
|
|
|
|
|
@ -248,11 +232,10 @@ class HeaderModelRequiredListValidationAlias(BaseModel): |
|
|
|
async def read_model_required_list_validation_alias( |
|
|
|
p: Annotated[HeaderModelRequiredListValidationAlias, Header()], |
|
|
|
): |
|
|
|
return {"p": p.p} # pragma: no cover |
|
|
|
return {"p": p.p} |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
["/required-list-validation-alias", "/model-required-list-validation-alias"], |
|
|
|
@ -276,10 +259,7 @@ def test_required_list_validation_alias_schema(path: str): |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
pytest.param( |
|
|
|
"/required-list-validation-alias", |
|
|
|
marks=pytest.mark.xfail(raises=AssertionError, strict=False), |
|
|
|
), |
|
|
|
"/required-list-validation-alias", |
|
|
|
"/model-required-list-validation-alias", |
|
|
|
], |
|
|
|
) |
|
|
|
@ -293,7 +273,7 @@ def test_required_list_validation_alias_missing(path: str): |
|
|
|
"type": "missing", |
|
|
|
"loc": [ |
|
|
|
"header", |
|
|
|
"p_val_alias", # /required-list-validation-alias fails here |
|
|
|
"p_val_alias", |
|
|
|
], |
|
|
|
"msg": "Field required", |
|
|
|
"input": AnyThing, |
|
|
|
@ -306,17 +286,14 @@ def test_required_list_validation_alias_missing(path: str): |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
pytest.param( |
|
|
|
"/required-list-validation-alias", |
|
|
|
marks=pytest.mark.xfail(raises=AssertionError, strict=False), |
|
|
|
), |
|
|
|
"/required-list-validation-alias", |
|
|
|
"/model-required-list-validation-alias", |
|
|
|
], |
|
|
|
) |
|
|
|
def test_required_list_validation_alias_by_name(path: str): |
|
|
|
client = TestClient(app) |
|
|
|
response = client.get(path, headers=[("p", "hello"), ("p", "world")]) |
|
|
|
assert response.status_code == 422 # /required-list-validation-alias fails here |
|
|
|
assert response.status_code == 422 |
|
|
|
|
|
|
|
assert response.json() == { |
|
|
|
"detail": [ |
|
|
|
@ -331,7 +308,6 @@ def test_required_list_validation_alias_by_name(path: str): |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
["/required-list-validation-alias", "/model-required-list-validation-alias"], |
|
|
|
@ -341,9 +317,9 @@ def test_required_list_validation_alias_by_validation_alias(path: str): |
|
|
|
response = client.get( |
|
|
|
path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")] |
|
|
|
) |
|
|
|
assert response.status_code == 200, response.text # both fail here |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
|
|
|
|
assert response.json() == {"p": ["hello", "world"]} # pragma: no cover |
|
|
|
assert response.json() == {"p": ["hello", "world"]} |
|
|
|
|
|
|
|
|
|
|
|
# ===================================================================================== |
|
|
|
@ -365,11 +341,10 @@ class HeaderModelRequiredListAliasAndValidationAlias(BaseModel): |
|
|
|
def read_model_required_list_alias_and_validation_alias( |
|
|
|
p: Annotated[HeaderModelRequiredListAliasAndValidationAlias, Header()], |
|
|
|
): |
|
|
|
return {"p": p.p} # pragma: no cover |
|
|
|
return {"p": p.p} |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
@ -396,10 +371,7 @@ def test_required_list_alias_and_validation_alias_schema(path: str): |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
pytest.param( |
|
|
|
"/required-list-alias-and-validation-alias", |
|
|
|
marks=pytest.mark.xfail(raises=AssertionError, strict=False), |
|
|
|
), |
|
|
|
"/required-list-alias-and-validation-alias", |
|
|
|
"/model-required-list-alias-and-validation-alias", |
|
|
|
], |
|
|
|
) |
|
|
|
@ -413,7 +385,6 @@ def test_required_list_alias_and_validation_alias_missing(path: str): |
|
|
|
"type": "missing", |
|
|
|
"loc": [ |
|
|
|
"header", |
|
|
|
# /required-list-alias-and-validation-alias fails here |
|
|
|
"p_val_alias", |
|
|
|
], |
|
|
|
"msg": "Field required", |
|
|
|
@ -424,7 +395,6 @@ def test_required_list_alias_and_validation_alias_missing(path: str): |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
@ -442,13 +412,11 @@ def test_required_list_alias_and_validation_alias_by_name(path: str): |
|
|
|
"type": "missing", |
|
|
|
"loc": [ |
|
|
|
"header", |
|
|
|
# /required-list-alias-and-validation-alias fails here |
|
|
|
"p_val_alias", |
|
|
|
], |
|
|
|
"msg": "Field required", |
|
|
|
"input": IsOneOf( |
|
|
|
None, |
|
|
|
# /model-required-list-alias-and-validation-alias fails here |
|
|
|
IsPartialDict({"p": ["hello", "world"]}), |
|
|
|
), |
|
|
|
} |
|
|
|
@ -457,7 +425,6 @@ def test_required_list_alias_and_validation_alias_by_name(path: str): |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
@ -468,9 +435,7 @@ def test_required_list_alias_and_validation_alias_by_name(path: str): |
|
|
|
def test_required_list_alias_and_validation_alias_by_alias(path: str): |
|
|
|
client = TestClient(app) |
|
|
|
response = client.get(path, headers=[("p_alias", "hello"), ("p_alias", "world")]) |
|
|
|
assert ( # /required-list-alias-and-validation-alias fails here |
|
|
|
response.status_code == 422 |
|
|
|
) |
|
|
|
assert response.status_code == 422 |
|
|
|
assert response.json() == { |
|
|
|
"detail": [ |
|
|
|
{ |
|
|
|
@ -479,7 +444,6 @@ def test_required_list_alias_and_validation_alias_by_alias(path: str): |
|
|
|
"msg": "Field required", |
|
|
|
"input": IsOneOf( |
|
|
|
None, |
|
|
|
# /model-required-list-alias-and-validation-alias fails here |
|
|
|
IsPartialDict({"p_alias": ["hello", "world"]}), |
|
|
|
), |
|
|
|
} |
|
|
|
@ -488,7 +452,6 @@ def test_required_list_alias_and_validation_alias_by_alias(path: str): |
|
|
|
|
|
|
|
|
|
|
|
@needs_pydanticv2 |
|
|
|
@pytest.mark.xfail(raises=AssertionError, strict=False) |
|
|
|
@pytest.mark.parametrize( |
|
|
|
"path", |
|
|
|
[ |
|
|
|
@ -501,5 +464,5 @@ def test_required_list_alias_and_validation_alias_by_validation_alias(path: str) |
|
|
|
response = client.get( |
|
|
|
path, headers=[("p_val_alias", "hello"), ("p_val_alias", "world")] |
|
|
|
) |
|
|
|
assert response.status_code == 200, response.text # both fail here |
|
|
|
assert response.json() == {"p": ["hello", "world"]} # pragma: no cover |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
assert response.json() == {"p": ["hello", "world"]} |
|
|
|
|