Skip to content

Lazy imports break dataclass InitVars in extremely rare scenarios #160665

Description

@lor1113

Bug report

3 files are required to get this bug to happen:

testing.py

from testing_2 import A
from testing_3 import B

a = A()

b = B(a)

testing_2.py

from dataclasses import dataclass

from testing_3 import B


@dataclass
class A:
    pass

testing_3.py

from dataclasses import InitVar, dataclass

lazy from testing_2 import A


@dataclass
class B:
    a: InitVar[A]

    def __post_init__(self, a: A) -> None:
        print(a)

If you run testing.py with python 3.15 you will get TypeError: B.__post_init__() missing 1 required positional argument: 'a'
The key thing that causes the error seems to be the presence of the import cycle combined with the lazy import. It's worth noting that if you use a TYPE_CHECKING guard instead as described below, it does also work on 3.15.

I found this issue while migrating a bunch of my TYPE_CHECKING guards to lazy imports - infact as PEP 810 says "Lazy imports eliminate the common need for TYPE_CHECKING guards". The version of python that breaks is cpython-3.15.0a7-linux-x86_64-gnu. The code instead works on cpython-3.14.3-linux-x86_64-gnu, if of course you replace the lazy import in testing_3.py with a if TYPE_CHECKING: block

CPython versions tested on:

3.15

Operating systems tested on:

Linux

Linked PRs

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

    stdlibStandard Library Python modules in the Lib/ directorytopic-lazy-importstype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions