Browse Source

Use inline snapshots in assertions

pull/14829/head
Yurii Motov 4 months ago
parent
commit
1a251c63c2
  1. 299
      tests/test_request_params/test_body/test_nullable_and_defaults.py
  2. 157
      tests/test_request_params/test_cookie/test_nullable_and_defaults.py
  3. 157
      tests/test_request_params/test_file/test_nullable_and_defaults.py
  4. 271
      tests/test_request_params/test_form/test_nullable_and_defaults.py
  5. 243
      tests/test_request_params/test_header/test_nullable_and_defaults.py
  6. 243
      tests/test_request_params/test_query/test_nullable_and_defaults.py

299
tests/test_request_params/test_body/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import IsList, IsOneOf, IsPartialDict from dirty_equals import IsList, IsOneOf, IsPartialDict
from fastapi import Body, FastAPI from fastapi import Body, FastAPI
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import Is, snapshot
from pydantic import BaseModel, BeforeValidator, field_validator from pydantic import BaseModel, BeforeValidator, field_validator
from .utils import get_body_model_name from .utils import get_body_model_name
@ -92,28 +93,30 @@ def test_nullable_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
}, "anyOf": [{"type": "integer"}, {"type": "null"}],
"str_val": { },
"title": "Str Val", "str_val": {
"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Str Val",
}, "anyOf": [{"type": "string"}, {"type": "null"}],
"list_val": { },
"title": "List Val", "list_val": {
"anyOf": [ "title": "List Val",
{"type": "array", "items": {"type": "integer"}}, "anyOf": [
{"type": "null"}, {"type": "array", "items": {"type": "integer"}},
], {"type": "null"},
],
},
}, },
}, "required": ["int_val", "str_val", "list_val"],
"required": ["int_val", "str_val", "list_val"], "title": Is(body_model_name),
"title": body_model_name, "type": "object",
"type": "object", }
} )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -165,28 +168,30 @@ def test_nullable_required_missing(path: str):
client = TestClient(app) client = TestClient(app)
response = client.post(path, json={}) response = client.post(path, json={})
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body", "int_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "int_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["body", "str_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "str_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["body", "list_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "list_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -205,16 +210,18 @@ def test_nullable_required_no_body(path: str):
client = TestClient(app) client = TestClient(app)
response = client.post(path) response = client.post(path)
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body"], "type": "missing",
"msg": "Field required", "loc": ["body"],
"input": None, "msg": "Field required",
}, "input": None,
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -229,16 +236,18 @@ def test_nullable_required_no_embed_missing(path: str):
client = TestClient(app) client = TestClient(app)
response = client.post(path) response = client.post(path)
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"input": None, {
"loc": ["body"], "input": None,
"msg": "Field required", "loc": ["body"],
"type": "missing", "msg": "Field required",
} "type": "missing",
] }
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -267,16 +276,18 @@ def test_nullable_required_no_embed_pass_empty_dict(
client = TestClient(app) client = TestClient(app)
response = client.post(path, json={}) response = client.post(path, json={})
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"input": {}, {
"loc": ["body"], "input": {},
"msg": msg, "loc": ["body"],
"type": error_type, "msg": Is(msg),
} "type": Is(error_type),
] }
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -487,30 +498,32 @@ def test_nullable_non_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "integer"}, {"type": "null"}],
}, # "default": None, # `None` values are omitted in OpenAPI schema
"str_val": { },
"title": "Str Val", "str_val": {
"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Str Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "string"}, {"type": "null"}],
}, # "default": None, # `None` values are omitted in OpenAPI schema
"list_val": { },
"title": "List Val", "list_val": {
"anyOf": [ "title": "List Val",
{"type": "array", "items": {"type": "integer"}}, "anyOf": [
{"type": "null"}, {"type": "array", "items": {"type": "integer"}},
], {"type": "null"},
# "default": None, # `None` values are omitted in OpenAPI schema ],
# "default": None, # `None` values are omitted in OpenAPI schema
},
}, },
}, "title": Is(body_model_name),
"title": body_model_name, "type": "object",
"type": "object", }
} )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -595,16 +608,18 @@ def test_nullable_non_required_no_body(path: str):
client = TestClient(app) client = TestClient(app)
response = client.post(path) response = client.post(path)
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body"], "type": "missing",
"msg": "Field required", "loc": ["body"],
"input": None, "msg": "Field required",
}, "input": None,
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -836,31 +851,33 @@ def test_nullable_with_non_null_default_schema(path: str):
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
body_model = app.openapi()["components"]["schemas"][body_model_name] body_model = app.openapi()["components"]["schemas"][body_model_name]
assert body_model == { assert body_model == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"default": -1, "anyOf": [{"type": "integer"}, {"type": "null"}],
}, "default": -1,
"str_val": {
"title": "Str Val",
"anyOf": [{"type": "string"}, {"type": "null"}],
"default": "default",
},
"list_val": IsPartialDict(
{
"title": "List Val",
"anyOf": [
{"type": "array", "items": {"type": "integer"}},
{"type": "null"},
],
}, },
), "str_val": {
}, "title": "Str Val",
"title": body_model_name, "anyOf": [{"type": "string"}, {"type": "null"}],
"type": "object", "default": "default",
} },
"list_val": IsPartialDict(
{
"title": "List Val",
"anyOf": [
{"type": "array", "items": {"type": "integer"}},
{"type": "null"},
],
},
),
},
"title": Is(body_model_name),
"type": "object",
}
)
if path == "/model-nullable-with-non-null-default": if path == "/model-nullable-with-non-null-default":
# Check default value for list_val param for model-based parameters only. # Check default value for list_val param for model-based parameters only.
@ -949,16 +966,18 @@ def test_nullable_with_non_null_default_no_body(path: str):
client = TestClient(app) client = TestClient(app)
response = client.post(path) response = client.post(path)
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body"], "type": "missing",
"msg": "Field required", "loc": ["body"],
"input": None, "msg": "Field required",
}, "input": None,
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(

157
tests/test_request_params/test_cookie/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import IsList, IsOneOf from dirty_equals import IsList, IsOneOf
from fastapi import Cookie, FastAPI from fastapi import Cookie, FastAPI
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from pydantic import BaseModel, BeforeValidator, field_validator from pydantic import BaseModel, BeforeValidator, field_validator
app = FastAPI() app = FastAPI()
@ -67,26 +68,28 @@ async def read_model_nullable_required(
], ],
) )
def test_nullable_required_schema(path: str): def test_nullable_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": True, {
"schema": { "required": True,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"anyOf": [{"type": "integer"}, {"type": "null"}],
},
"name": "int_val",
"in": "cookie",
}, },
"name": "int_val", {
"in": "cookie", "required": True,
}, "schema": {
{ "title": "Str Val",
"required": True, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { },
"title": "Str Val", "name": "str_val",
"anyOf": [{"type": "string"}, {"type": "null"}], "in": "cookie",
}, },
"name": "str_val", ]
"in": "cookie", )
},
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -105,22 +108,24 @@ def test_nullable_required_missing(path: str):
"Validator should not be called if the value is missing" "Validator should not be called if the value is missing"
) )
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["cookie", "int_val"], "type": "missing",
"msg": "Field required", "loc": ["cookie", "int_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["cookie", "str_val"], "type": "missing",
"msg": "Field required", "loc": ["cookie", "str_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -206,28 +211,30 @@ async def read_model_nullable_non_required(
], ],
) )
def test_nullable_non_required_schema(path: str): def test_nullable_non_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "integer"}, {"type": "null"}],
# "default": None, # `None` values are omitted in OpenAPI schema
},
"name": "int_val",
"in": "cookie",
}, },
"name": "int_val", {
"in": "cookie", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { # "default": None, # `None` values are omitted in OpenAPI schema
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str_val",
# "default": None, # `None` values are omitted in OpenAPI schema "in": "cookie",
}, },
"name": "str_val", ]
"in": "cookie", )
},
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -339,28 +346,30 @@ async def read_model_nullable_with_non_null_default(
], ],
) )
def test_nullable_with_non_null_default_schema(path: str): def test_nullable_with_non_null_default_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"default": -1, "anyOf": [{"type": "integer"}, {"type": "null"}],
"default": -1,
},
"name": "int_val",
"in": "cookie",
}, },
"name": "int_val", {
"in": "cookie", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { "default": "default",
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str_val",
"default": "default", "in": "cookie",
}, },
"name": "str_val", ]
"in": "cookie", )
},
]
@pytest.mark.parametrize( @pytest.mark.parametrize(

157
tests/test_request_params/test_file/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import IsOneOf from dirty_equals import IsOneOf
from fastapi import FastAPI, File, UploadFile from fastapi import FastAPI, File, UploadFile
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import Is, snapshot
from pydantic import BeforeValidator from pydantic import BeforeValidator
from starlette.datastructures import UploadFile as StarletteUploadFile from starlette.datastructures import UploadFile as StarletteUploadFile
@ -70,24 +71,29 @@ def test_nullable_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"file": { "properties": {
"title": "File", "file": {
"anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], "title": "File",
"anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}],
},
"files": {
"title": "Files",
"anyOf": [
{
"type": "array",
"items": {"type": "string", "format": "binary"},
},
{"type": "null"},
],
},
}, },
"files": { "required": ["file", "files"],
"title": "Files", "title": Is(body_model_name),
"anyOf": [ "type": "object",
{"type": "array", "items": {"type": "string", "format": "binary"}}, }
{"type": "null"}, )
],
},
},
"required": ["file", "files"],
"title": body_model_name,
"type": "object",
}
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -107,22 +113,24 @@ def test_nullable_required_missing(path: str):
"Validator should not be called if the value is missing" "Validator should not be called if the value is missing"
) )
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body", "file"], "type": "missing",
"msg": "Field required", "loc": ["body", "file"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["body", "files"], "type": "missing",
"msg": "Field required", "loc": ["body", "files"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -242,25 +250,30 @@ def test_nullable_non_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"file": { "properties": {
"title": "File", "file": {
"anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], "title": "File",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}],
}, # "default": None, # `None` values are omitted in OpenAPI schema
"files": { },
"title": "Files", "files": {
"anyOf": [ "title": "Files",
{"type": "array", "items": {"type": "string", "format": "binary"}}, "anyOf": [
{"type": "null"}, {
], "type": "array",
# "default": None, # `None` values are omitted in OpenAPI schema "items": {"type": "string", "format": "binary"},
},
{"type": "null"},
],
# "default": None, # `None` values are omitted in OpenAPI schema
},
}, },
}, "title": Is(body_model_name),
"title": body_model_name, "type": "object",
"type": "object", }
} )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -380,24 +393,32 @@ def test_nullable_with_non_null_default_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"file": { "properties": {
"title": "File", "file": {
"anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], "title": "File",
"default": "default", # <= Default value for file looks strange to me "anyOf": [
{"type": "string", "format": "binary"},
{"type": "null"},
],
"default": "default", # <= Default value here looks strange to me
},
"files": {
"title": "Files",
"anyOf": [
{
"type": "array",
"items": {"type": "string", "format": "binary"},
},
{"type": "null"},
],
},
}, },
"files": { "title": Is(body_model_name),
"title": "Files", "type": "object",
"anyOf": [ }
{"type": "array", "items": {"type": "string", "format": "binary"}}, )
{"type": "null"},
],
},
},
"title": body_model_name,
"type": "object",
}
@pytest.mark.parametrize( @pytest.mark.parametrize(

271
tests/test_request_params/test_form/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import IsList, IsOneOf, IsPartialDict from dirty_equals import IsList, IsOneOf, IsPartialDict
from fastapi import FastAPI, Form from fastapi import FastAPI, Form
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import Is, snapshot
from pydantic import BaseModel, BeforeValidator, field_validator from pydantic import BaseModel, BeforeValidator, field_validator
from .utils import get_body_model_name from .utils import get_body_model_name
@ -79,28 +80,30 @@ def test_nullable_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
}, "anyOf": [{"type": "integer"}, {"type": "null"}],
"str_val": { },
"title": "Str Val", "str_val": {
"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Str Val",
}, "anyOf": [{"type": "string"}, {"type": "null"}],
"list_val": { },
"title": "List Val", "list_val": {
"anyOf": [ "title": "List Val",
{"type": "array", "items": {"type": "integer"}}, "anyOf": [
{"type": "null"}, {"type": "array", "items": {"type": "integer"}},
], {"type": "null"},
],
},
}, },
}, "required": ["int_val", "str_val", "list_val"],
"required": ["int_val", "str_val", "list_val"], "title": Is(body_model_name),
"title": body_model_name, "type": "object",
"type": "object", }
} )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -120,28 +123,30 @@ def test_nullable_required_missing(path: str):
"Validator should not be called if the value is missing" "Validator should not be called if the value is missing"
) )
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["body", "int_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "int_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["body", "str_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "str_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["body", "list_val"], "type": "missing",
"msg": "Field required", "loc": ["body", "list_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -218,22 +223,24 @@ def test_nullable_required_pass_empty_str_to_int_val_and_list_val(path: str):
call([""]), # list_val call([""]), # list_val
] ]
assert response.status_code == 422, response.text assert response.status_code == 422, response.text
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"input": "", {
"loc": ["body", "int_val"], "input": "",
"msg": "Input should be a valid integer, unable to parse string as an integer", "loc": ["body", "int_val"],
"type": "int_parsing", "msg": "Input should be a valid integer, unable to parse string as an integer",
}, "type": "int_parsing",
{ },
"input": "", {
"loc": ["body", "list_val", 0], "input": "",
"msg": "Input should be a valid integer, unable to parse string as an integer", "loc": ["body", "list_val", 0],
"type": "int_parsing", "msg": "Input should be a valid integer, unable to parse string as an integer",
}, "type": "int_parsing",
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -326,30 +333,32 @@ def test_nullable_non_required_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
assert app.openapi()["components"]["schemas"][body_model_name] == { assert openapi["components"]["schemas"][body_model_name] == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "integer"}, {"type": "null"}],
}, # "default": None, # `None` values are omitted in OpenAPI schema
"str_val": { },
"title": "Str Val", "str_val": {
"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Str Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "string"}, {"type": "null"}],
}, # "default": None, # `None` values are omitted in OpenAPI schema
"list_val": { },
"title": "List Val", "list_val": {
"anyOf": [ "title": "List Val",
{"type": "array", "items": {"type": "integer"}}, "anyOf": [
{"type": "null"}, {"type": "array", "items": {"type": "integer"}},
], {"type": "null"},
# "default": None, # `None` values are omitted in OpenAPI schema ],
# "default": None, # `None` values are omitted in OpenAPI schema
},
}, },
}, "title": Is(body_model_name),
"title": body_model_name, "type": "object",
"type": "object", }
} )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -445,16 +454,18 @@ def test_nullable_non_required_pass_empty_str_to_all(path: str):
call([""]), # list_val call([""]), # list_val
] ]
assert response.status_code == 422, response.text assert response.status_code == 422, response.text
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"input": "", {
"loc": ["body", "list_val", 0], "input": "",
"msg": "Input should be a valid integer, unable to parse string as an integer", "loc": ["body", "list_val", 0],
"type": "int_parsing", "msg": "Input should be a valid integer, unable to parse string as an integer",
}, "type": "int_parsing",
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -547,33 +558,35 @@ async def read_model_nullable_with_non_null_default(
def test_nullable_with_non_null_default_schema(path: str): def test_nullable_with_non_null_default_schema(path: str):
openapi = app.openapi() openapi = app.openapi()
body_model_name = get_body_model_name(openapi, path) body_model_name = get_body_model_name(openapi, path)
body_model = app.openapi()["components"]["schemas"][body_model_name] body_model = openapi["components"]["schemas"][body_model_name]
assert body_model == { assert body_model == snapshot(
"properties": { {
"int_val": { "properties": {
"title": "Int Val", "int_val": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"default": -1, "anyOf": [{"type": "integer"}, {"type": "null"}],
}, "default": -1,
"str_val": { },
"title": "Str Val", "str_val": {
"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Str Val",
"default": "default", "anyOf": [{"type": "string"}, {"type": "null"}],
"default": "default",
},
"list_val": IsPartialDict(
{
"title": "List Val",
"anyOf": [
{"type": "array", "items": {"type": "integer"}},
{"type": "null"},
],
}
),
}, },
"list_val": IsPartialDict( "title": Is(body_model_name),
{ "type": "object",
"title": "List Val", }
"anyOf": [ )
{"type": "array", "items": {"type": "integer"}},
{"type": "null"},
],
}
),
},
"title": body_model_name,
"type": "object",
}
if path == "/model-nullable-with-non-null-default": if path == "/model-nullable-with-non-null-default":
# Check default value for list_val param for model-based parameters only. # Check default value for list_val param for model-based parameters only.
@ -691,16 +704,18 @@ def test_nullable_with_non_null_default_pass_empty_str_to_all(path: str):
call([""]), # list_val call([""]), # list_val
] ]
assert response.status_code == 422, response.text # pragma: no cover assert response.status_code == 422, response.text # pragma: no cover
assert response.json() == { # pragma: no cover assert response.json() == snapshot( # pragma: no cover
"detail": [ {
{ "detail": [
"input": "", {
"loc": ["body", "list_val", 0], "input": "",
"msg": "Input should be a valid integer, unable to parse string as an integer", "loc": ["body", "list_val", 0],
"type": "int_parsing", "msg": "Input should be a valid integer, unable to parse string as an integer",
}, "type": "int_parsing",
] },
} ]
}
)
# TODO: Remove 'no cover' when the issue is fixed # TODO: Remove 'no cover' when the issue is fixed

243
tests/test_request_params/test_header/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import AnyThing, IsList, IsOneOf, IsPartialDict from dirty_equals import AnyThing, IsList, IsOneOf, IsPartialDict
from fastapi import FastAPI, Header from fastapi import FastAPI, Header
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from pydantic import BaseModel, BeforeValidator, field_validator from pydantic import BaseModel, BeforeValidator, field_validator
app = FastAPI() app = FastAPI()
@ -80,38 +81,40 @@ async def read_model_nullable_required(
], ],
) )
def test_nullable_required_schema(path: str): def test_nullable_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": True, {
"schema": { "required": True,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"anyOf": [{"type": "integer"}, {"type": "null"}],
},
"name": "int-val",
"in": "header",
}, },
"name": "int-val", {
"in": "header", "required": True,
}, "schema": {
{ "title": "Str Val",
"required": True, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { },
"title": "Str Val", "name": "str-val",
"anyOf": [{"type": "string"}, {"type": "null"}], "in": "header",
}, },
"name": "str-val", {
"in": "header", "required": True,
}, "schema": {
{ "title": "List Val",
"required": True, "anyOf": [
"schema": { {"type": "array", "items": {"type": "integer"}},
"title": "List Val", {"type": "null"},
"anyOf": [ ],
{"type": "array", "items": {"type": "integer"}}, },
{"type": "null"}, "name": "list-val",
], "in": "header",
}, },
"name": "list-val", ]
"in": "header", )
},
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -138,28 +141,30 @@ def test_nullable_required_missing(path: str):
"Validator should not be called if the value is missing" "Validator should not be called if the value is missing"
) )
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["header", "int-val"], "type": "missing",
"msg": "Field required", "loc": ["header", "int-val"],
"input": AnyThing(), "msg": "Field required",
}, "input": AnyThing(),
{ },
"type": "missing", {
"loc": ["header", "str-val"], "type": "missing",
"msg": "Field required", "loc": ["header", "str-val"],
"input": AnyThing(), "msg": "Field required",
}, "input": AnyThing(),
{ },
"type": "missing", {
"loc": ["header", "list-val"], "type": "missing",
"msg": "Field required", "loc": ["header", "list-val"],
"input": AnyThing(), "msg": "Field required",
}, "input": AnyThing(),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -293,41 +298,43 @@ async def read_model_nullable_non_required(
], ],
) )
def test_nullable_non_required_schema(path: str): def test_nullable_non_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "integer"}, {"type": "null"}],
# "default": None, # `None` values are omitted in OpenAPI schema
},
"name": "int-val",
"in": "header",
}, },
"name": "int-val", {
"in": "header", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { # "default": None, # `None` values are omitted in OpenAPI schema
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str-val",
# "default": None, # `None` values are omitted in OpenAPI schema "in": "header",
}, },
"name": "str-val", {
"in": "header", "required": False,
}, "schema": {
{ "title": "List Val",
"required": False, "anyOf": [
"schema": { {"type": "array", "items": {"type": "integer"}},
"title": "List Val", {"type": "null"},
"anyOf": [ ],
{"type": "array", "items": {"type": "integer"}}, # "default": None, # `None` values are omitted in OpenAPI schema
{"type": "null"}, },
], "name": "list-val",
# "default": None, # `None` values are omitted in OpenAPI schema "in": "header",
}, },
"name": "list-val", ]
"in": "header", )
},
]
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -488,42 +495,44 @@ async def read_model_nullable_with_non_null_default(
) )
def test_nullable_with_non_null_default_schema(path: str): def test_nullable_with_non_null_default_schema(path: str):
parameters = app.openapi()["paths"][path]["get"]["parameters"] parameters = app.openapi()["paths"][path]["get"]["parameters"]
assert parameters == [ assert parameters == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"default": -1, "anyOf": [{"type": "integer"}, {"type": "null"}],
"default": -1,
},
"name": "int-val",
"in": "header",
}, },
"name": "int-val", {
"in": "header", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { "default": "default",
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str-val",
"default": "default", "in": "header",
}, },
"name": "str-val", {
"in": "header", "required": False,
}, "schema": IsPartialDict(
{ {
"required": False, "title": "List Val",
"schema": IsPartialDict( "anyOf": [
{ {"type": "array", "items": {"type": "integer"}},
"title": "List Val", {"type": "null"},
"anyOf": [ ],
{"type": "array", "items": {"type": "integer"}}, }
{"type": "null"}, ),
], "name": "list-val",
} "in": "header",
), },
"name": "list-val", ]
"in": "header", )
},
]
if path == "/model-nullable-with-non-null-default": if path == "/model-nullable-with-non-null-default":
# Check default value for list_val param for model-based parameters only. # Check default value for list_val param for model-based parameters only.

243
tests/test_request_params/test_query/test_nullable_and_defaults.py

@ -5,6 +5,7 @@ import pytest
from dirty_equals import IsList, IsOneOf, IsPartialDict from dirty_equals import IsList, IsOneOf, IsPartialDict
from fastapi import FastAPI, Query from fastapi import FastAPI, Query
from fastapi.testclient import TestClient from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from pydantic import BaseModel, BeforeValidator, field_validator from pydantic import BaseModel, BeforeValidator, field_validator
app = FastAPI() app = FastAPI()
@ -73,38 +74,40 @@ async def read_model_nullable_required(
], ],
) )
def test_nullable_required_schema(path: str): def test_nullable_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": True, {
"schema": { "required": True,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"anyOf": [{"type": "integer"}, {"type": "null"}],
},
"name": "int_val",
"in": "query",
}, },
"name": "int_val", {
"in": "query", "required": True,
}, "schema": {
{ "title": "Str Val",
"required": True, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { },
"title": "Str Val", "name": "str_val",
"anyOf": [{"type": "string"}, {"type": "null"}], "in": "query",
}, },
"name": "str_val", {
"in": "query", "in": "query",
}, "name": "list_val",
{ "required": True,
"in": "query", "schema": {
"name": "list_val", "anyOf": [
"required": True, {"items": {"type": "integer"}, "type": "array"},
"schema": { {"type": "null"},
"anyOf": [ ],
{"items": {"type": "integer"}, "type": "array"}, "title": "List Val",
{"type": "null"}, },
],
"title": "List Val",
}, },
}, ]
] )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -124,28 +127,30 @@ def test_nullable_required_missing(path: str):
"Validator should not be called if the value is missing" "Validator should not be called if the value is missing"
) )
assert response.status_code == 422 assert response.status_code == 422
assert response.json() == { assert response.json() == snapshot(
"detail": [ {
{ "detail": [
"type": "missing", {
"loc": ["query", "int_val"], "type": "missing",
"msg": "Field required", "loc": ["query", "int_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["query", "str_val"], "type": "missing",
"msg": "Field required", "loc": ["query", "str_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
{ },
"type": "missing", {
"loc": ["query", "list_val"], "type": "missing",
"msg": "Field required", "loc": ["query", "list_val"],
"input": IsOneOf(None, {}), "msg": "Field required",
}, "input": IsOneOf(None, {}),
] },
} ]
}
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -239,41 +244,43 @@ async def read_model_nullable_non_required(
], ],
) )
def test_nullable_non_required_schema(path: str): def test_nullable_non_required_schema(path: str):
assert app.openapi()["paths"][path]["get"]["parameters"] == [ assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
# "default": None, # `None` values are omitted in OpenAPI schema "anyOf": [{"type": "integer"}, {"type": "null"}],
# "default": None, # `None` values are omitted in OpenAPI schema
},
"name": "int_val",
"in": "query",
}, },
"name": "int_val", {
"in": "query", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { # "default": None, # `None` values are omitted in OpenAPI schema
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str_val",
# "default": None, # `None` values are omitted in OpenAPI schema "in": "query",
}, },
"name": "str_val", {
"in": "query", "in": "query",
}, "name": "list_val",
{ "required": False,
"in": "query", "schema": {
"name": "list_val", "anyOf": [
"required": False, {"items": {"type": "integer"}, "type": "array"},
"schema": { {"type": "null"},
"anyOf": [ ],
{"items": {"type": "integer"}, "type": "array"}, "title": "List Val",
{"type": "null"}, # "default": None, # `None` values are omitted in OpenAPI schema
], },
"title": "List Val",
# "default": None, # `None` values are omitted in OpenAPI schema
}, },
}, ]
] )
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -394,42 +401,44 @@ async def read_model_nullable_with_non_null_default(
) )
def test_nullable_with_non_null_default_schema(path: str): def test_nullable_with_non_null_default_schema(path: str):
parameters = app.openapi()["paths"][path]["get"]["parameters"] parameters = app.openapi()["paths"][path]["get"]["parameters"]
assert parameters == [ assert parameters == snapshot(
{ [
"required": False, {
"schema": { "required": False,
"title": "Int Val", "schema": {
"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Int Val",
"default": -1, "anyOf": [{"type": "integer"}, {"type": "null"}],
"default": -1,
},
"name": "int_val",
"in": "query",
}, },
"name": "int_val", {
"in": "query", "required": False,
}, "schema": {
{ "title": "Str Val",
"required": False, "anyOf": [{"type": "string"}, {"type": "null"}],
"schema": { "default": "default",
"title": "Str Val", },
"anyOf": [{"type": "string"}, {"type": "null"}], "name": "str_val",
"default": "default", "in": "query",
}, },
"name": "str_val", {
"in": "query", "in": "query",
}, "name": "list_val",
{ "required": False,
"in": "query", "schema": IsPartialDict(
"name": "list_val", {
"required": False, "anyOf": [
"schema": IsPartialDict( {"items": {"type": "integer"}, "type": "array"},
{ {"type": "null"},
"anyOf": [ ],
{"items": {"type": "integer"}, "type": "array"}, "title": "List Val",
{"type": "null"}, }
], ),
"title": "List Val", },
} ]
), )
},
]
if path == "/model-nullable-with-non-null-default": if path == "/model-nullable-with-non-null-default":
# Check default value for list_val param for model-based parameters only. # Check default value for list_val param for model-based parameters only.

Loading…
Cancel
Save