Skip to content

Self-referenced ClassVar causes TypeError: issubclass() arg 1 must be a class (in 1.9.0, worked in 1.8.2) #3679

Closed

Description

@mcgfeller

Checks

Bug

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

pydantic version: 1.9.0
pydantic compiled: True
install path: C:\Program Files\Python39\Lib\site-packages\pydantic
python version: 3.9.0 (tags/v3.9.0:9cf6752, Oct  5 2020, 15:34:40) [MSC v.1927 64 bit (AMD64)]
platform: Windows-10-10.0.19041-SP0
optional deps. installed: ['email-validator', 'typing-extensions']

Also occurs on Linux with Python 3.9.9.

from __future__ import annotations
import pydantic
import typing

class WithClassVar(pydantic.BaseModel):
    Instances : typing.ClassVar[dict[str,WithClassVar]] = {} # fails with issubclass() arg 1 must be a class; arg  1 is typing.ClassVar object 
    # Instances : typing.ClassVar[dict[str,'WithClassVar']] = {} # works
    # instance : dict[str,WithClassVar] = {} # no classvar - works

...

I believe this case is specific to a ClassVar referencing itself. The argument passed to issubclass is not a class, but an instance of typing.ClassVar.

Call stack:

__subclasscheck__ (c:\Program Files\Python39\Lib\typing.py:789)
pydantic.fields.ModelField._type_analysis (c:\Program Files\Python39\Lib\site-packages\pydantic\fields.py:638)
pydantic.fields.ModelField.prepare (c:\Program Files\Python39\Lib\site-packages\pydantic\fields.py:534)
pydantic.typing.update_field_forward_refs (c:\Program Files\Python39\Lib\site-packages\pydantic\typing.py:451)
pydantic.typing.update_model_forward_refs (c:\Program Files\Python39\Lib\site-packages\pydantic\typing.py:480)
pydantic.main.BaseModel.__try_update_forward_refs__ (c:\Program Files\Python39\Lib\site-packages\pydantic\main.py:773)
pydantic.main.ModelMetaclass.__new__ (c:\Program Files\Python39\Lib\site-packages\pydantic\main.py:292)
<module> (.... \pydantic_bug.py:5)

Activity

  1. ajkaijanaho commented on Jan 18, 2022

    @ajkaijanaho

    I get the same error with the following variant:

    from __future__ import annotations
    import pydantic
    import typing
    
    class WithClassVar(pydantic.BaseModel):
        Instance : typing.ClassVar['WithClassVar']

    However, if I remove the first line (importing annotations), the example seems to work.

    The following class definition passes initial muster

    from __future__ import annotations
    import pydantic
    import typing
    
    class WithClassVar(pydantic.BaseModel):
        Instance : typing.ClassVar[WithClassVarAlias]
    
    WithClassVarAlias = WithClassVar

    ... but if I try to construct an instance, I get a problem:

    print(WithClassVar())

    leads to

    pydantic.error_wrappers.ValidationError: 1 validation error for WithClassVar
    Instance
      field required (type=value_error.missing)
    
  2. added this to the v1.9.1 milestone on Apr 1, 2022
  3. added a commit that references this issue on May 11, 2022
    fb31c4a
  4. added a commit that references this issue on May 13, 2022
    a45276d
  5. added a commit that references this issue on May 13, 2022
    c49868a
  6. added 3 commits that reference this issue on May 14, 2022
    9c2c10e
    98dab9e
    122dd2f
  7. added 2 commits that reference this issue on Jun 24, 2022
    c82e161
    ec3ba9e
  8. mcgfeller commented on Dec 5, 2022

    @mcgfeller
    Author

    Unfortunately, this stopped working again on 1.10.2 with Python 3.11:

                 pydantic version: 1.10.2
                pydantic compiled: True
                     install path: C:\Projects\DDH\.venv\Lib\site-packages\pydantic
                   python version: 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)]
                         platform: Windows-10-10.0.19044-SP0
         optional deps. installed: ['email-validator', 'typing-extensions']
    

    Now, it doesn't work even when quoted, this "workaround" was ok before:

    from __future__ import annotations
    import pydantic
    import typing
    
    class WithClassVar(pydantic.BaseModel):
        Instances : typing.ClassVar[dict[str,WithClassVar]] = {} # fails with issubclass() arg 1 must be a class; arg  1 is typing.ClassVar object 
        # Instances : typing.ClassVar[dict[str,'WithClassVar']] = {} # worked in 1.9, stopped working in 1.10.2
        # instance : dict[str,WithClassVar] = {} # no classvar - works
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug V1Bug related to Pydantic V1.X

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions