Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.10.x] Properly encode model and dataclass default for schema #4781

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/4781-Bobronium.md
@@ -0,0 +1 @@
Fix `schema` and `schema_json` on models where a model instance is a one of default values.
12 changes: 9 additions & 3 deletions pydantic/schema.py
@@ -1,6 +1,7 @@
import re
import warnings
from collections import defaultdict
from dataclasses import is_dataclass
from datetime import date, datetime, time, timedelta
from decimal import Decimal
from enum import Enum
Expand Down Expand Up @@ -971,16 +972,21 @@ def multitypes_literal_field_for_schema(values: Tuple[Any, ...], field: ModelFie


def encode_default(dft: Any) -> Any:
if isinstance(dft, Enum):
from .main import BaseModel

if isinstance(dft, BaseModel) or is_dataclass(dft):
dft = cast('dict[str, Any]', pydantic_encoder(dft))

if isinstance(dft, dict):
return {encode_default(k): encode_default(v) for k, v in dft.items()}
elif isinstance(dft, Enum):
return dft.value
elif isinstance(dft, (int, float, str)):
return dft
elif isinstance(dft, (list, tuple)):
t = dft.__class__
seq_args = (encode_default(v) for v in dft)
return t(*seq_args) if is_namedtuple(t) else t(seq_args)
elif isinstance(dft, dict):
return {encode_default(k): encode_default(v) for k, v in dft.items()}
elif dft is None:
return None
else:
Expand Down
32 changes: 32 additions & 0 deletions tests/test_schema.py
Expand Up @@ -1523,6 +1523,38 @@ class UserModel(BaseModel):
}


def test_model_default():
"""Make sure inner model types are encoded properly"""

class Inner(BaseModel):
a: Dict[Path, str] = {Path(): ''}

class Outer(BaseModel):
inner: Inner = Inner()

assert Outer.schema() == {
'definitions': {
'Inner': {
'properties': {
'a': {
'additionalProperties': {'type': 'string'},
'default': {'.': ''},
'title': 'A',
'type': 'object',
}
},
'title': 'Inner',
'type': 'object',
}
},
'properties': {
'inner': {'allOf': [{'$ref': '#/definitions/Inner'}], 'default': {'a': {'.': ''}}, 'title': 'Inner'}
},
'title': 'Outer',
'type': 'object',
}


@pytest.mark.parametrize(
'kwargs,type_,expected_extra',
[
Expand Down