Pydantic: Type of type

Created on 8 Aug 2019  路  7Comments  路  Source: samuelcolvin/pydantic

Question

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:

  • OS: macos
  • Python version import sys; print(sys.version): 3.7.2
  • Pydantic version import pydantic; print(pydantic.VERSION): 0.29
question

Most helpful comment

from 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].

All 7 comments

from 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!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ashpreetbedi picture ashpreetbedi  路  3Comments

krzysieqq picture krzysieqq  路  3Comments

AlbertMukhammadiev picture AlbertMukhammadiev  路  3Comments

timonbimon picture timonbimon  路  3Comments

dconathan picture dconathan  路  3Comments