/ 2 min read / 231 words

Circular Imports and TYPE_CHECKING

Abstract

Circular imports often happen when two modules need each other only for type annotations. The typing.TYPE_CHECKING constant is true under static analysis and false at runtime, so imports declared behind it never execute: the cycle disappears and the type checker still sees everything. This note records the pattern and how it applies to ORM relationship declarations.

Contents

TYPE_CHECKING is a constant from the typing module. It is True during type checks and False at runtime. This means you can import classes for type hints without causing circular imports at runtime.

When you use an import inside an if TYPE_CHECKING: block, Python skips it at runtime. Yet type checkers like mypy or pyright will see it for verifying your annotations.

Basic Example§

# a.py
from typing import TYPE_CHECKING

if TYPE_CHECKING:
  from b import B  # This import won't run at runtime

class A:
  def link_to_b(self, b: 'B') -> None:
    print('Linking A with B')
# b.py
class B:
  pass

Here, A refers to B for type hints without importing it during runtime. That helps avoid circular imports.

Usage in an ORM§

# models.py
from typing import TYPE_CHECKING
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship
from database_setup import Base

if TYPE_CHECKING:
  from other_models import RelatedModel

class MyModel(Base):
  __tablename__ = 'my_model'
  id = Column(Integer, primary_key=True)
  related_id = Column(Integer, ForeignKey('related_model.id'))

  # For type hints only:
  related_model: 'RelatedModel' = relationship('RelatedModel')

This prevents runtime loops, because the if TYPE_CHECKING: block loads only for type analysis.

Why Use It§

  • Prevents circular imports by avoiding runtime loops between modules.
  • Improves readability by separating type hints from the normal import flow.
  • Helps type checkers by allowing tools to verify your types.

References§

  1. typing.TYPE_CHECKING, Python documentation.
  2. PEP 484 — Type Hints: Runtime or type checking?, python.org.