1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
from datetime import datetime
from inspect import getdoc
from typing import Type
import pytest
from bson import ObjectId as BSONObjectId
from odmantic import Model, ObjectId, Reference
from odmantic.bson import BaseBSONModel, Binary, Decimal128, Int64, Regex
from odmantic.model import EmbeddedModel
def test_object_id_fastapi_get_query(fastapi_app, test_client):
value_injected = None
@fastapi_app.get("/{id}")
def get(id: ObjectId):
nonlocal value_injected
value_injected = id
return "ok"
id_get_str = "5f79d7e8b305f24ca43593e2"
test_client.get(f"/{id_get_str}")
assert value_injected == BSONObjectId(id_get_str)
def test_object_id_fastapi_get_query_invalid_id(fastapi_app, test_client):
@fastapi_app.get("/{id}")
def get(id: ObjectId):
return "ok" # pragma: no cover
invalid_oid_str = "a"
response = test_client.get(f"/{invalid_oid_str}")
assert response.status_code == 422
assert response.json()["detail"][0]["loc"] == [
"path",
"id",
"is-instance[ObjectId]",
]
@pytest.mark.skip("Need to specify custom json_encoder or to use a root_type")
def test_object_id_fastapi_response(fastapi_app, test_client):
id_get_str = "5f79d7e8b305f24ca43593e2"
@fastapi_app.get("/")
def get():
return {"id": ObjectId(id_get_str)}
response = test_client.get("/")
assert response.json() == {"id": id_get_str}
def test_object_id_fastapi_pydantic_response_model(fastapi_app, test_client):
id_get_str = "5f79d7e8b305f24ca43593e2"
class PydanticModel(BaseBSONModel):
id: ObjectId
# Defining a config object WITHOUT json_encoders arguments
model_config = {}
@fastapi_app.get("/", response_model=PydanticModel)
def get():
return {"id": ObjectId(id_get_str)}
response = test_client.get("/")
assert response.json() == {"id": id_get_str}
def test_object_id_fastapi_odmantic_response_pydantic_model(fastapi_app, test_client):
class ODMModel(Model): ...
object = ODMModel()
@fastapi_app.get("/", response_model=ODMModel.__pydantic_model__)
def get():
return object
response = test_client.get("/")
assert response.json() == {"id": str(object.id)}
def test_object_id_fastapi_odmantic_response_model(fastapi_app, test_client):
class ODMModel(Model): ...
object = ODMModel()
@fastapi_app.get("/", response_model=ODMModel)
def get():
return object
response = test_client.get("/")
assert response.json() == {"id": str(object.id)}
def test_openapi_json_with_bson_fields(fastapi_app, test_client):
class ODMModel(Model):
oid: ObjectId
int64: Int64
decimal: Decimal128
binary: Binary
regex: Regex
datetime_: datetime
@fastapi_app.get("/", response_model=ODMModel)
def get():
return None # pragma: no cover
response = test_client.get("/openapi.json")
assert response.status_code == 200
@pytest.mark.parametrize("base", (Model, EmbeddedModel))
def test_docstring_not_nullified(base: Type):
class M(base):
"""My docstring"""
doc = getdoc(M)
assert doc is None or doc == "My docstring"
description = M.model_json_schema()["description"]
assert description == "My docstring"
@pytest.mark.parametrize("base", (Model, EmbeddedModel))
def test_docstring_nullified(base: Type):
class M(base): ...
doc = getdoc(M)
assert doc == ""
assert "description" not in M.model_json_schema()
@pytest.mark.parametrize("base", (Model, EmbeddedModel, BaseBSONModel))
def test_base_classes_docstring_not_nullified(base: Type):
doc = getdoc(base)
assert doc is not None and doc != ""
@pytest.mark.parametrize("base", (Model, EmbeddedModel))
def test_pydantic_model_title(base: Type):
class M(base): ...
assert M.__pydantic_model__.model_json_schema()["title"] == "M"
@pytest.mark.parametrize("base", (Model, EmbeddedModel))
def test_pydantic_model_custom_title(base: Type):
class M(base):
model_config = {"title": "CustomTitle"}
assert M.__pydantic_model__.model_json_schema()["title"] == "CustomTitle"
def test_pydantic_model_references():
class Referenced(Model): ...
class Base(Model):
field: Referenced = Reference()
assert not hasattr(
Base.__pydantic_model__, "field"
), "class attribute should be empty"
assert not issubclass(
Base.__pydantic_model__, Model
), "the pydantic_model should inherit from Model"
b_pure = Base.__pydantic_model__(field=Referenced().__pydantic_model__())
assert not issubclass(
type(b_pure.field), # type: ignore
Model,
), "the pure field should not inherit from Model"
def test_openapi_json_references(fastapi_app, test_client):
class Referenced(Model): ...
class Base(Model):
field: Referenced = Reference()
@fastapi_app.get("/", response_model=Base)
def get():
return None # pragma: no cover
response = test_client.get("/openapi.json")
assert response.status_code == 200
|