8000 Do not override `'definitions-ref'` schemas containing serialization … · pydantic/pydantic@d404c5f · GitHub
[go: up one dir, main page]

8000 Skip to content

Commit d404c5f

Browse files
committed
Do not override 'definitions-ref' schemas containing serialization schemas or metadata
1 parent 58e61fa commit d404c5f

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

pydantic/_internal/_generate_schema.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2813,7 +2813,7 @@ def _resolve_definition(self, ref: str, definitions: dict[str, CoreSchema]) -> C
28132813
# Some `'definition-ref'` schemas might act as "intermediate" references (e.g. when using
28142814
# a PEP 695 type alias (which is referenceable) that references another PEP 695 type alias):
28152815
visited: set[str] = set()
2816-
while definition['type'] == 'definition-ref':
2816+
while definition['type'] == 'definition-ref' and _inlining_behavior(definition) == 'inline':
28172817
schema_ref = definition['schema_ref']
28182818
if schema_ref in visited:
28192819
raise PydanticUserError(

tests/test_type_alias_type.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from annotated_types import MaxLen
88
from typing_extensions import TypeAliasType
99

10-
from pydantic import BaseModel, PydanticUserError, TypeAdapter, ValidationError
10+
from pydantic import BaseModel, PlainSerializer, PydanticUserError, TypeAdapter, ValidationError, WithJsonSchema
1111

1212
T = TypeVar('T')
1313

@@ -430,3 +430,46 @@ class MyModel(BaseModel):
430430

431431
assert exc_info.value.code == 'circular-reference-schema'
432432
assert exc_info.value.message.startswith('tests.test_type_alias_type.C')
433+
434+
435+
def test_type_alias_type_with_serialization() -> None:
436+
"""Regression test for https://github.com/pydantic/pydantic/issues/11642.
437+
438+
The issue lied in the definition resolving logic, which wasn't taking
439+
possible metadata or serialization attached to a `'definition-ref'` schema.
440+
441+
In this example, the core schema for `B` — before schema cleaning — will look like:
442+
443+
```python
444+
{
445+
'type': 'definition-ref',
446+
'schema_ref': '__main__.A',
447+
'serialization': {...},
448+
'ref': '__main__.B',
449+
}
450+
```
451+
452+
and the "main"/"top-level" core schema is a `'definition-ref'` schema pointing to
453+
`'__main__.B`.
454+
455+
In schema cleaning, when resolving this top-level core schema, we would recursively
456+
unpack `'definition-ref'` schemas (and would end up with the actual schema for `__main__.A`),
457+
without taking into account the fact that the schema of `B` had a `serialization` key!
458+
"""
459+
460+
A = TypeAliasType('A', int)
461+
B = TypeAliasType('B', Annotated[A, PlainSerializer(lambda v: 3)])
462+
463+
ta = TypeAdapter(B)
464+
465+
assert ta.dump_python(1) == 3
466+
467+
468+
def test_type_alias_type_with_metadata() -> None:
469+
"""Same as `test_type_alias_type_with_serialization()` but with JSON Metadata."""
470+
471+
A = TypeAliasType('A', int)
472+
B = TypeAliasType('B', Annotated[A, WithJsonSchema({'type': 'int', 'extra': 1})])
473+
474+
ta = TypeAdapter(B)
475+
assert ta.json_schema() == {'type': 'int', 'extra': 1}

0 commit comments

Comments
 (0)
0