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

Generic types (as Dict) without type parameters result in an error #550

Closed
zbarry opened this issue May 25, 2019 · 4 comments

Comments

Projects
None yet
4 participants
@zbarry
Copy link

commented May 25, 2019

Bug

For bugs/questions:

  • OS: CentOS 7
  • Python version: 3.7.2
  • Pydantic version: 0.26

Moving to separate issue here from #545

This error happens when you create a subclass of BaseModel which specifies a field of type Dict which does not specify mapping types, i.e.:

from pydantic import BaseModel
from typing import Dict, Any

class SubclassThatWorks(BaseModel):
    asdf: int
    fdsa: Dict[Any, Any]

class SubclassThatFails(BaseModel):
    asdf: int
    fdsa: Dict

with the error message being:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
    385         try:
--> 386             if issubclass(type_, val_type):
    387                 return validators

TypeError: issubclass() arg 1 must be a class

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
<ipython-input-5-c7b931439a60> in <module>
----> 1 class Subclass(BaseModel):
      2     asdf: int
      3     fdsa: Dict

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/main.py in __new__(mcs, name, bases, namespace)
    180                     annotation=ann_type,
    181                     class_validators=vg.get_validators(ann_name),
--> 182                     config=config,
    183                 )
    184 

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in infer(cls, name, value, annotation, class_validators, config)
    136             required=required,
    137             model_config=config,
--> 138             schema=schema,
    139         )
    140 

/scratch/miniconda3/envs/jupyter/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

/scratch/miniconda3/envs/jupyter/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 

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _populate_sub_fields(self)
    221             assert issubclass(origin, Mapping)
    222             self.key_field = self._create_sub_type(
--> 223                 self.type_.__args__[0], 'key_' + self.name, for_keys=True  # type: ignore
    224             )
    225             self.type_ = self.type_.__args__[1]  # type: ignore

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _create_sub_type(self, type_, name, for_keys)
    235             name=name,
    236             class_validators=None if for_keys else {k: v for k, v in self.class_validators.items() if not v.whole},
--> 237             model_config=self.model_config,
    238         )
    239 

/scratch/miniconda3/envs/jupyter/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

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in prepare(self)
    171 
    172         self._populate_sub_fields()
--> 173         self._populate_validators()
    174 
    175     def _populate_sub_fields(self) -> None:  # noqa: C901 (ignore complexity)

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/fields.py in _populate_validators(self)
    253                     get_validators()
    254                     if get_validators
--> 255                     else find_validators(self.type_, self.model_config.arbitrary_types_allowed)
    256                 ),
    257                 self.schema is not None and self.schema.const and constant_validator,

/scratch/miniconda3/envs/jupyter/lib/python3.7/site-packages/pydantic/validators.py in find_validators(type_, arbitrary_types_allowed)
    387                 return validators
    388         except TypeError as e:
--> 389             raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') from e
    390 
    391     if arbitrary_types_allowed:

RuntimeError: error checking inheritance of ~KT (type: KT)

dmontagu added a commit to dmontagu/pydantic that referenced this issue May 26, 2019

Fix issue with unspecified generic type
Seems to solve samuelcolvin#550

With this change, models with bare `List` or `Dict` as a typehint still validate for type agreement, but don't validate the type of the parameters.

I'm not sure this is the "right" fix (I don't know the implications of ignoring TypeVars like this), but considering how simple it was I figured I'd at least share.

@dmontagu dmontagu referenced this issue May 26, 2019

Merged

Fix issue with unspecified generic type #554

4 of 4 tasks complete
@dmontagu

This comment has been minimized.

Copy link
Contributor

commented May 26, 2019

Looks like an issue where a TypeVar is being passed to issubclass, I would expect this to be a relatively simple fix (but maybe I'm overlooking something more complex).

@tiangolo

This comment has been minimized.

Copy link
Collaborator

commented May 27, 2019

@zbarry if you have a dict that receives any value as key/value, use Dict[Any, Any]. Or simply dict.

Dict alone is actually a syntax error.

Edit: Dict alone should be assumed as Dict[Any, Any], I just checked the spec: https://www.python.org/dev/peps/pep-0484/#the-any-type

If a generic type is used without specifying type parameters, they assumed to be Any

So, this is a valid issue. But let me update the title.

@tiangolo tiangolo changed the title Dict validation checking: TypeError: issubclass() arg 1 must be a class Generic types (as Dict) without type parameters result in an error May 27, 2019

@zbarry

This comment has been minimized.

Copy link
Author

commented May 27, 2019

Yeah, was going to say, mypy thefile.py on:

from typing import Dict

def dictthing(a: Dict):
    return a

def dictexplicitthing(a: Dict[int, str]):
    return a

dictthing(dict(a=3))
dictexplicitthing({'a': 4})
dictexplicitthing({3: 'fdsa'})

only complains on the first call to dictexplicitthing and is fine with the dictthing call.

I actually tried this in a second python kernel in JupyterLab and surprisingly found it worked. Dug just a little bit into it, and a major difference between the two kernels (confirmed the error again on the first kernel), was that the erroring kernel is 3.7.2 and the non-erroring was 3.6.6. I don't know if there are any significant differences between how these versions handle annotations, though.

@dmontagu

This comment has been minimized.

Copy link
Contributor

commented May 29, 2019

@zbarry It wouldn't surprise me if this is due to differences in typing in python 3.6 and 3.7. In particular, I know inherting from typing.Generic used to change the metaclass, which made it hard/impossible to create custom generic classes with more interesting metaclasses. So maybe the mechanics of the generics/TypeVars changed and that's why this is happening now.

dmontagu added a commit to dmontagu/pydantic that referenced this issue May 29, 2019

Fix issue with unspecified generic type
Seems to solve samuelcolvin#550

With this change, models with bare `List` or `Dict` as a typehint still validate for type agreement, but don't validate the type of the parameters.

I'm not sure this is the "right" fix (I don't know the implications of ignoring TypeVars like this), but considering how simple it was I figured I'd at least share.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.