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

fixes __pydantic_config__ ignored for TypeDict #8734

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
24 changes: 17 additions & 7 deletions pydantic/json_schema.py
Expand Up @@ -1214,18 +1214,24 @@ def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaVa
]
if self.mode == 'serialization':
named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', [])))

config = _get_typed_dict_config(schema)
cls = _get_typed_dict_cls(schema)
config = _get_typed_dict_config(cls)
with self._config_wrapper_stack.push(config):
json_schema = self._named_required_fields_schema(named_required_fields)

json_schema_extra = config.get('json_schema_extra')
extra = schema.get('extra_behavior')
if extra is None:
extra = config.get('extra', 'ignore')
if extra == 'forbid':
json_schema['additionalProperties'] = False
elif extra == 'allow':
json_schema['additionalProperties'] = True

if cls is not None:
title = config.get('title') or cls.__name__
json_schema = self._update_class_schema(json_schema, title, extra, cls, json_schema_extra)
else:
if extra == 'forbid':
json_schema['additionalProperties'] = False
elif extra == 'allow':
json_schema['additionalProperties'] = True

return json_schema

Expand Down Expand Up @@ -2414,9 +2420,13 @@ def __hash__(self) -> int:
return hash(type(self))


def _get_typed_dict_config(schema: core_schema.TypedDictSchema) -> ConfigDict:
def _get_typed_dict_cls(schema: core_schema.TypedDictSchema) -> type[Any] | None:
metadata = _core_metadata.CoreMetadataHandler(schema).metadata
cls = metadata.get('pydantic_typed_dict_cls')
return cls


def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict:
if cls is not None:
try:
return _decorators.get_attribute_from_bases(cls, '__pydantic_config__')
Expand Down
40 changes: 40 additions & 0 deletions tests/test_json_schema.py
Expand Up @@ -2545,6 +2545,46 @@ def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHa
}


def test_typeddict_with_title():
class Model(TypedDict):
__pydantic_config__ = ConfigDict(title='Test') # type: ignore
a: str

assert TypeAdapter(Model).json_schema() == {
'title': 'Test',
'type': 'object',
'properties': {'a': {'title': 'A', 'type': 'string'}},
'required': ['a'],
}


def test_typeddict_with_json_schema_extra():
class Model(TypedDict):
__pydantic_config__ = ConfigDict(title='Test', json_schema_extra={'foobar': 'hello'}) # type: ignore
a: str

assert TypeAdapter(Model).json_schema() == {
'title': 'Test',
'type': 'object',
'properties': {'a': {'title': 'A', 'type': 'string'}},
'required': ['a'],
'foobar': 'hello',
}


def test_typeddict_with__callable_json_schema_extra():
def json_schema_extra(schema, model_class):
schema.pop('properties')
schema['type'] = 'override'
assert model_class is Model

class Model(TypedDict):
__pydantic_config__ = ConfigDict(title='Test', json_schema_extra=json_schema_extra) # type: ignore
a: str

assert TypeAdapter(Model).json_schema() == {'title': 'Test', 'type': 'override', 'required': ['a']}


@pytest.mark.parametrize(
'annotation,kwargs,field_schema',
[
Expand Down