Hi there. Is there a way to claim a variable as "type of type"? How should I write definition for class_map under this situation?
import pydantic
class A(pydantic.BaseModel):
pass
class B(pydantic.BaseModel):
pass
class_map: Dict[???, str] = {A: "I'm class a", B: "I'm class b"}
Please complete:
import sys; print(sys.version): 3.7.2import pydantic; print(pydantic.VERSION): 0.29from typing import Any, Dict, Type
classmap: Dict[Type[Any], str]
Type is a generic, so you can specify a more specific version by putting something besides Any in the brackets. (The Any is not required, just a way to be explicit that you are not constraining anything about the type).
If you are always using model types as keys, you can use Dict[Type[BaseModel], str].
or Dict[Type[Union[A, B]], str]
The type accept only A or B as keys
@dmontagu @koxudaxi Both works. Thanks : )
Hi. There'll be an assertionError if I class_map is a variable of class inherited BaseModel
import pydantic
class A(pydantic.BaseModel):
pass
class B(pydantic.BaseModel):
pass
class C(pydantic.BaseModel):
class_map: Dict[Type[Any], str]
Here's the the top of stack:
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pydantic/fields.py in __init__(self, name, type_, class_validators, model_config, default, required, alias, schema)
105 self.parse_json: bool = False
106 self.shape: Shape = Shape.SINGLETON
--> 107 self.prepare()
108
109 @classmethod
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)
170 self.allow_none = True
171
--> 172 self._populate_sub_fields()
173 self._populate_validators()
174
/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pydantic/fields.py in _populate_sub_fields(self)
229 self.shape = Shape.SEQUENCE
230 else:
--> 231 assert issubclass(origin, Mapping)
232 self.key_field = self._create_sub_type(
233 self.type_.__args__[0], 'key_' + self.name, for_keys=True # type: ignore
Any insights?
@i4never that is a bug due to an older version of pydantic; I believe it has been fixed in more recent versions. It's still an issue, I just checked. Let me see if I can figure out why / if there is a workaround.
It looks like this is currently not supported. It wouldn't be a hard fix to add support, but it looks like it would be a feature request rather than a bug fix. I think right now the focus is on getting v1.0 out, but if you feel this is important you can make a feature request.
As a workaround, you can use:
class C(pydantic.BaseModel):
class_map: Dict[Any, str]
@pydantic.validator("class_map", whole=True)
def validate_keys_are_types(cls, v):
for key in v:
# If you want to validate the keys are models, use:
# if not issubclass(key, pydantic.BaseModel):
# If you just want to make sure it is a type (i.e., Type[Any]), use:
if not isinstance(key, type):
raise TypeError
return v
print(C(class_map={int: "a"}))
# C class_map={<class 'int'>: 'a'}
C(class_map={1: "a"})
"""
pydantic.error_wrappers.ValidationError: 1 validation error
class_map
(type=type_error)
"""
(But I think at the very least we should probably support the use of Type as an annotation without raising an exception, whether it is validated or not; ideally it would be.)
That's a rare use case. I believe the workaround is great and a feature request is too much.
Thanks!
Most helpful comment
Typeis a generic, so you can specify a more specific version by putting something besidesAnyin the brackets. (TheAnyis not required, just a way to be explicit that you are not constraining anything about the type).If you are always using model types as keys, you can use
Dict[Type[BaseModel], str].