* Implemented response_model_exclude_defaults and response_model_exclude_none to be compatible pydantic options.
* :truck: Rename and invert include_none to exclude_none to keep in sync with Pydantic
Co-authored-by: Lukas Voegtle <lukas.voegtle@sick.de>
Co-authored-by: Sebastián RamÃrez <tiangolo@gmail.com>
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
by_alias: bool = True,
skip_defaults: bool = None,
exclude_unset: bool = False,
- include_none: bool = True,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
custom_encoder: dict = {},
sqlalchemy_safe: bool = True,
) -> Any:
exclude=exclude,
by_alias=by_alias,
exclude_unset=bool(exclude_unset or skip_defaults),
+ exclude_none=exclude_none,
+ exclude_defaults=exclude_defaults,
)
else: # pragma: nocover
+ if exclude_defaults:
+ raise ValueError("Cannot use exclude_defaults")
obj_dict = obj.dict(
include=include,
exclude=exclude,
)
return jsonable_encoder(
obj_dict,
- include_none=include_none,
+ exclude_none=exclude_none,
+ exclude_defaults=exclude_defaults,
custom_encoder=encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
or (not isinstance(key, str))
or (not key.startswith("_sa"))
)
- and (value is not None or include_none)
+ and (value is not None or not exclude_none)
and ((include and key in include) or key not in exclude)
):
encoded_key = jsonable_encoder(
key,
by_alias=by_alias,
exclude_unset=exclude_unset,
- include_none=include_none,
+ exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
value,
by_alias=by_alias,
exclude_unset=exclude_unset,
- include_none=include_none,
+ exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
- include_none=include_none,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
data,
by_alias=by_alias,
exclude_unset=exclude_unset,
- include_none=include_none,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
custom_encoder=custom_encoder,
sqlalchemy_safe=sqlalchemy_safe,
)
security_definition = jsonable_encoder(
security_requirement.security_scheme.model,
by_alias=True,
- include_none=False,
+ exclude_none=True,
)
security_name = security_requirement.security_scheme.scheme_name
security_definitions[security_name] = security_definition
if components:
output["components"] = components
output["paths"] = paths
- return jsonable_encoder(OpenAPI(**output), by_alias=True, include_none=False)
+ return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True)
def _prepare_response_content(
- res: Any, *, by_alias: bool = True, exclude_unset: bool
+ res: Any,
+ *,
+ by_alias: bool = True,
+ exclude_unset: bool,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
) -> Any:
if isinstance(res, BaseModel):
if PYDANTIC_1:
- return res.dict(by_alias=by_alias, exclude_unset=exclude_unset)
+ return res.dict(
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
else:
return res.dict(
- by_alias=by_alias, skip_defaults=exclude_unset
+ by_alias=by_alias, skip_defaults=exclude_unset,
) # pragma: nocover
elif isinstance(res, list):
return [
- _prepare_response_content(item, exclude_unset=exclude_unset) for item in res
+ _prepare_response_content(
+ item,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
+ for item in res
]
elif isinstance(res, dict):
return {
- k: _prepare_response_content(v, exclude_unset=exclude_unset)
+ k: _prepare_response_content(
+ v,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
+ )
for k, v in res.items()
}
return res
exclude: Union[SetIntStr, DictIntStrAny] = set(),
by_alias: bool = True,
exclude_unset: bool = False,
+ exclude_defaults: bool = False,
+ exclude_none: bool = False,
is_coroutine: bool = True,
) -> Any:
if field:
errors = []
response_content = _prepare_response_content(
- response_content, by_alias=by_alias, exclude_unset=exclude_unset
+ response_content,
+ by_alias=by_alias,
+ exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
)
if is_coroutine:
value, errors_ = field.validate(response_content, {}, loc=("response",))
exclude=exclude,
by_alias=by_alias,
exclude_unset=exclude_unset,
+ exclude_defaults=exclude_defaults,
+ exclude_none=exclude_none,
)
else:
return jsonable_encoder(response_content)
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(),
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
dependency_overrides_provider: Any = None,
) -> Callable:
assert dependant.call is not None, "dependant.call must be a function"
exclude=response_model_exclude,
by_alias=response_model_by_alias,
exclude_unset=response_model_exclude_unset,
+ exclude_defaults=response_model_exclude_defaults,
+ exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
response = response_class(
response_model_exclude: Union[SetIntStr, DictIntStrAny] = set(),
response_model_by_alias: bool = True,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Optional[Type[Response]] = None,
dependency_overrides_provider: Any = None,
self.response_model_exclude = response_model_exclude
self.response_model_by_alias = response_model_by_alias
self.response_model_exclude_unset = response_model_exclude_unset
+ self.response_model_exclude_defaults = response_model_exclude_defaults
+ self.response_model_exclude_none = response_model_exclude_none
self.include_in_schema = include_in_schema
self.response_class = response_class
response_model_exclude=self.response_model_exclude,
response_model_by_alias=self.response_model_by_alias,
response_model_exclude_unset=self.response_model_exclude_unset,
+ response_model_exclude_defaults=self.response_model_exclude_defaults,
+ response_model_exclude_none=self.response_model_exclude_none,
dependency_overrides_provider=self.dependency_overrides_provider,
)
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_exclude=route.response_model_exclude,
response_model_by_alias=route.response_model_by_alias,
response_model_exclude_unset=route.response_model_exclude_unset,
+ response_model_exclude_defaults=route.response_model_exclude_defaults,
+ response_model_exclude_none=route.response_model_exclude_none,
include_in_schema=route.include_in_schema,
response_class=route.response_class or default_response_class,
name=route.name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
response_model_by_alias: bool = True,
response_model_skip_defaults: bool = None,
response_model_exclude_unset: bool = False,
+ response_model_exclude_defaults: bool = False,
+ response_model_exclude_none: bool = False,
include_in_schema: bool = True,
response_class: Type[Response] = None,
name: str = None,
response_model_exclude_unset=bool(
response_model_exclude_unset or response_model_skip_defaults
),
+ response_model_exclude_defaults=response_model_exclude_defaults,
+ response_model_exclude_none=response_model_exclude_none,
include_in_schema=include_in_schema,
response_class=response_class or self.default_response_class,
name=name,
foo: str = Field(..., alias="Foo")
+class ModelWithDefault(BaseModel):
+ foo: str = ...
+ bar: str = "bar"
+ bla: str = "bla"
+
+
@pytest.fixture(
name="model_with_path", params=[PurePath, PurePosixPath, PureWindowsPath]
)
assert jsonable_encoder(model) == {"Foo": "Bar"}
+def test_encode_model_with_default():
+ model = ModelWithDefault(foo="foo", bar="bar")
+ assert jsonable_encoder(model) == {"foo": "foo", "bar": "bar", "bla": "bla"}
+ assert jsonable_encoder(model, exclude_unset=True) == {"foo": "foo", "bar": "bar"}
+ assert jsonable_encoder(model, exclude_defaults=True) == {"foo": "foo"}
+ assert jsonable_encoder(model, exclude_unset=True, exclude_defaults=True) == {
+ "foo": "foo"
+ }
+
+
def test_custom_encoders():
class safe_datetime(datetime):
pass
class ModelSubclass(Model):
y: int
+ z: int = 0
+ w: int = None
+
+
+class ModelDefaults(BaseModel):
+ w: Optional[str] = None
+ x: Optional[str] = None
+ y: str = "y"
+ z: str = "z"
@app.get("/", response_model=Model, response_model_exclude_unset=True)
def get() -> ModelSubclass:
- return ModelSubclass(sub={}, y=1)
+ return ModelSubclass(sub={}, y=1, z=0)
+
+
+@app.get(
+ "/exclude_unset", response_model=ModelDefaults, response_model_exclude_unset=True
+)
+def get() -> ModelDefaults:
+ return ModelDefaults(x=None, y="y")
+
+
+@app.get(
+ "/exclude_defaults",
+ response_model=ModelDefaults,
+ response_model_exclude_defaults=True,
+)
+def get() -> ModelDefaults:
+ return ModelDefaults(x=None, y="y")
+
+
+@app.get(
+ "/exclude_none", response_model=ModelDefaults, response_model_exclude_none=True
+)
+def get() -> ModelDefaults:
+ return ModelDefaults(x=None, y="y")
+
+
+@app.get(
+ "/exclude_unset_none",
+ response_model=ModelDefaults,
+ response_model_exclude_unset=True,
+ response_model_exclude_none=True,
+)
+def get() -> ModelDefaults:
+ return ModelDefaults(x=None, y="y")
client = TestClient(app)
def test_return_defaults():
response = client.get("/")
assert response.json() == {"sub": {}}
+
+
+def test_return_exclude_unset():
+ response = client.get("/exclude_unset")
+ assert response.json() == {"x": None, "y": "y"}
+
+
+def test_return_exclude_defaults():
+ response = client.get("/exclude_defaults")
+ assert response.json() == {}
+
+
+def test_return_exclude_none():
+ response = client.get("/exclude_none")
+ assert response.json() == {"y": "y", "z": "z"}
+
+
+def test_return_exclude_unset_none():
+ response = client.get("/exclude_unset_none")
+ assert response.json() == {"y": "y"}