PEP 810: Explicit lazy imports

Thanks for bringing this point here. I’m one of Pydantic’s maintainer, and PEP 810 could probably solve some annoying issues arising from circular imports. I had an initial proposal for “typing imports” with runtime support, but lazy imports provide a generalized solution that fits better so a big thanks to the authors of this PEP!

Technically, with the introduction of deferred annotations in PEP 649, we could lazily build the Pydantic models only when actions are performed on them (instantiation/validation, using model_json_schema(), etc.). In practice, we still have to eagerly evaluate annotations because we can’t assume every user is using Python 3.14, and that they don’t make use of string annotations [1]. But yes, with some work, we should be able to fully leverage PEP 649.

Regarding lazy imports, I believe they will be beneficial to work around circular imports. Right now users usually have to declare one of the import statements under an if TYPE_CHECKING: block, and somehow make Pydantic aware of the actual import somewhere else [2].

With some changes (we make assumptions about sys.modules[...].__dict__ being safely accessible in several places), we would be able to leverage PEP 810 to greatly simplify circular imports. I haven’t taken a deep look at the PEP specification, but I can’t think of any changes that would be needed for such use cases.


  1. We have some additional logic to resolve annotations from inner functions locals explaining why this is done eagerly. ↩︎

  2. This is usually done using the model_rebuild() method, where a types namespace can be provided. ↩︎

3 Likes