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

Serialize unsubstituted type vars as Any #7606

Merged
merged 5 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion docs/concepts/models.md
Expand Up @@ -815,7 +815,7 @@ class SerializeAsAnyModel(BaseModel, Generic[BoundT]):
data_model = DataModel()

print(GenericModel(data=data_model).model_dump())
#> {'data': {'a': 42}}
#> {'data': {'a': 42, 'b': 2, 'c': 3}}


print(SerializeAsAnyModel(data=data_model).model_dump())
Expand Down
8 changes: 6 additions & 2 deletions pydantic/_internal/_generate_schema.py
Expand Up @@ -1450,11 +1450,15 @@ def _unsubstituted_typevar_schema(self, typevar: typing.TypeVar) -> core_schema.
assert isinstance(typevar, typing.TypeVar)

if typevar.__bound__:
return self.generate_schema(typevar.__bound__)
schema = self.generate_schema(typevar.__bound__)
elif typevar.__constraints__:
return self._union_schema(typing.Union[typevar.__constraints__]) # type: ignore
schema = self._union_schema(typing.Union[typevar.__constraints__]) # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constraints feel closer to default than to a bound to me, I would personally make them function the old way. I’ll leave it up to you though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay changed

else:
return core_schema.any_schema()
schema['serialization'] = core_schema.wrap_serializer_function_ser_schema(
lambda x, h: h(x), schema=core_schema.any_schema()
)
return schema

def _computed_field_schema(
self,
Expand Down
9 changes: 5 additions & 4 deletions pydantic/types.py
Expand Up @@ -989,6 +989,7 @@ class Foo(BaseModel):
=== ":white_check_mark: Do this"
```py
from decimal import Decimal

from typing_extensions import Annotated

from pydantic import BaseModel, Field
Expand Down Expand Up @@ -1080,7 +1081,7 @@ def __hash__(self) -> int:
```py
import uuid

from pydantic import BaseModel, UUID1
from pydantic import UUID1, BaseModel

class Model(BaseModel):
uuid1: UUID1
Expand All @@ -1094,7 +1095,7 @@ class Model(BaseModel):
```py
import uuid

from pydantic import BaseModel, UUID3
from pydantic import UUID3, BaseModel
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reverted this change but looks like something in our docstring formatting stuff is sorting in reverse


class Model(BaseModel):
uuid3: UUID3
Expand All @@ -1108,7 +1109,7 @@ class Model(BaseModel):
```py
import uuid

from pydantic import BaseModel, UUID4
from pydantic import UUID4, BaseModel

class Model(BaseModel):
uuid4: UUID4
Expand All @@ -1122,7 +1123,7 @@ class Model(BaseModel):
```py
import uuid

from pydantic import BaseModel, UUID5
from pydantic import UUID5, BaseModel

class Model(BaseModel):
uuid5: UUID5
Expand Down
23 changes: 23 additions & 0 deletions tests/test_generics.py
Expand Up @@ -2622,3 +2622,26 @@ class Model(Generic[T], BaseModel):
m1 = Model[int](x=1)
m2 = Model[int](x=1)
assert len({m1, m2}) == 1


def test_serialize_unsubstituted_typevars_as_any() -> None:
ErrorDataT = TypeVar('ErrorDataT', bound=BaseModel)

class ErrorDetails(BaseModel):
foo: str

class Error(BaseModel, Generic[ErrorDataT]):
message: str
details: Optional[ErrorDataT]

sample_error = Error(
message='We just had an error',
details=ErrorDetails(foo='var'),
)

assert sample_error.model_dump() == {
'message': 'We just had an error',
'details': {
'foo': 'var',
},
}