-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Initial Checks
- I have searched GitHub for a duplicate issue and I'm sure this is something new
- I have searched Google & StackOverflow for a solution and couldn't find anything
- I have read and followed the docs and still think this is a bug
- I am confident that the issue is with pydantic (not my code, or another library in the ecosystem like FastAPI or mypy)
Description
When pydantic generic models are instantiated with Unions, the order of a particular set of types are fixed by the first instantiation, e.g.:
from typing import Generic, TypeVar, Union
from pydantic.generics import GenericModel
NumberT = TypeVar('NumberT')
class NumberModel(GenericModel, Generic[NumberT]):
data: NumberT
FloatOrIntModel = NumberModel[Union[float, int]]
print(FloatOrIntModel(data='1').data)
IntOrFloatModel = NumberModel[Union[int, float]]
print(IntOrFloatModel(data='1').data)prints
1.0
1.0
While changing the order of the instantiations changes type coercion of both models:
1
1
In pydantic, type coercion of Union models depends on the order of the types. However, as explained in the documentation on Unions:
typing.Union also ignores order when defined, so Union[int, float] == Union[float, int] which can lead to unexpected behaviour when combined with matching based on the Union type order inside other type definitions
I think this should be considered a bug in pydantic, even though the user is warned against 'unexpected behaviour' combined with other code that depend on Union type equality. The unexpected behaviour in this case is caused by pydantic itself, there is no "matching based on the Union type order inside other type definitions" in the example code, nor are any third-party code imported. It is not difficult to envision situations where this dependency could cause very hard-to-find bugs.
It seems the cause of the error is the _generic_types_cache in generics.py, which caches the first Union model and uses this as the blueprint of later matching models (i.e. with the same set of types).
Setting smart_union to True has no impact.
Related to #2835.
Example Code
No response
Python, Pydantic & OS Version
pydantic version: 1.10.1
pydantic compiled: True
install path: /Users/sveinugu/Library/Caches/pypoetry/virtualenvs/unifair-myuXak-6-py3.10/lib/python3.10/site-packages/pydantic
python version: 3.10.4 | packaged by conda-forge | (main, Mar 24 2022, 17:42:03) [Clang 12.0.1 ]
platform: macOS-11.2.3-arm64-arm-64bit
optional deps. installed: ['typing-extensions']
Affected Components
- Compatibility between releases
- Data validation/parsing
- Data serialization -
.dict()and.json() - JSON Schema
- Dataclasses
- Model Config
- Field Types - adding or changing a particular data type
- Function validation decorator
- Generic Models
- Other Model behaviour -
construct(), pickling, private attributes, ORM mode - Settings Management
- Plugins and integration with other tools - mypy, FastAPI, python-devtools, Hypothesis, VS Code, PyCharm, etc.