-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Bug
Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":
pydantic version: 1.9.1
pydantic compiled: True
install path: /home/paystone/.local/lib/python3.10/site-packages/pydantic
python version: 3.10.2 (main, Jan 29 2022, 02:55:36) [GCC 10.2.1 20210110]
platform: Linux-5.18.2-arch1-1-x86_64-with-glibc2.31
optional deps. installed: ['typing-extensions']
Python 3.10 incorporated PEP 604, which added syntax for writing Unions as X | Y, instead of typing.Union[X, Y]. It seems that when this syntax is used in combination with TypeVars as part of a GenericModel, the binding of TypeVars to their types fails.
Below is first a working example using typing.Union, followed by a non-working example using | syntax, with the stack trace. The example seeks to construct a Relationship GenericModel, and a BidirectionalMultiRelationship model which contains a list of either Relationship[A, B] or Relationship[B, A] models:
from typing import Union, Generic, TypeVar
from pydantic.generics import GenericModel
SourceT = TypeVar("SourceT")
TargetT = TypeVar("TargetT")
class Relationship(GenericModel, Generic[SourceT, TargetT]):
source: SourceT
target: TargetT
class BidirectionalMultiRelationship(GenericModel, Generic[SourceT, TargetT]):
relationships: list[Union[Relationship[SourceT, TargetT], Relationship[TargetT, SourceT]]]
BidirectionalMultiRelationship[str, int]from typing import Generic, TypeVar
from pydantic.generics import GenericModel
SourceT = TypeVar("SourceT")
TargetT = TypeVar("TargetT")
class Relationship(GenericModel, Generic[SourceT, TargetT]):
source: SourceT
target: TargetT
class BidirectionalMultiRelationship(GenericModel, Generic[SourceT, TargetT]):
relationships: list[Relationship[SourceT, TargetT] | Relationship[TargetT, SourceT]]
BidirectionalMultiRelationship[str, int]---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [2], in <cell line: 14>()
11 class BidirectionalMultiRelationship(GenericModel, Generic[SourceT, TargetT]):
12 relationships: Relationship[SourceT, TargetT] | Relationship[TargetT, SourceT]
---> 14 BidirectionalMultiRelationship[str, int]
File ~/.local/lib/python3.10/site-packages/pydantic/generics.py:137, in GenericModel.__class_getitem__(cls, params)
133 _generic_types_cache[(cls, params[0])] = created_model
135 # Recursively walk class type hints and replace generic typevars
136 # with concrete types that were passed.
--> 137 _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map)
139 return created_model
File ~/.local/lib/python3.10/site-packages/pydantic/generics.py:356, in _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map)
353 assert field.type_.__class__ is DeferredType, field.type_.__class__
355 field_type_hint = instance_type_hints[key]
--> 356 concrete_type = replace_types(field_type_hint, typevars_map)
357 field.type_ = concrete_type
358 field.outer_type_ = concrete_type
File ~/.local/lib/python3.10/site-packages/pydantic/generics.py:263, in replace_types(type_, type_map)
261 origin_type = getattr(typing, type_._name)
262 assert origin_type is not None
--> 263 return origin_type[resolved_type_args]
265 # We handle pydantic generic models separately as they don't have the same
266 # semantics as "typing" classes or generic aliases
267 if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__:
TypeError: 'type' object is not subscriptable
On inspection I found that at the point that the exception is thrown, origin_type is types.UnionType, where it should be Relationship.
Apologies if I missed an existing issue for this. I couldn't find anything in my search.