Python

How to Resolve "ImportError: Cannot Import Name X From Partially Initialized Module"

4 min read by DebuggedIt

Quick answer

An import that should work fine fails with a message specifically mentioning a "partially initialized module," which is Python's precise way of describing a...

An import that should work fine fails with a message specifically mentioning a "partially initialized module," which is Python's precise way of describing a circular import β€” two or more modules trying to import from each other, where one of them hasn't finished loading yet when the other reaches into it.

The Problem

Running your application fails at import time, before any actual application logic executes:

Traceback (most recent call last):
  File "app.py", line 1, in <module>
    from models import User
  File "models.py", line 2, in <module>
    from services import UserService
  File "services.py", line 1, in <module>
    from models import User
ImportError: cannot import name 'User' from partially initialized module 'models'
(most likely due to a circular import) (models.py)

Python's error message here is unusually direct about the cause, explicitly naming "circular import" as the likely culprit β€” worth trusting, since it's almost always correct.

Two modules importing each other models.py services.py models imports services, services imports models whichever loads first hits an unfinished version of the other

Why It Happens

Python modules execute top to bottom the first time they're imported, and Python tracks in-progress imports to avoid infinite loops β€” but this means if module A imports module B while B is still in the middle of importing A, B only has access to whatever parts of A have executed so far, not the complete module. If the specific name being imported hasn't been defined yet at that point, the import fails with exactly this error. This happens when:

  • Two modules each import something from the other at the top of their file, creating a direct circular dependency.
  • A longer chain of imports loops back on itself indirectly β€” module A imports B, B imports C, and C imports something from A, forming an indirect cycle that's harder to spot than a direct two-module cycle.
  • A package's __init__.py imports from a submodule, and that submodule in turn imports something from the package's top level, creating a cycle through the package initialization itself.

The Fix

The most durable fix is restructuring the code so the circular dependency doesn't exist in the first place β€” often by extracting the shared piece both modules need into a third, independent module that neither of the original two needs to import from each other for:

# Before: models.py and services.py import each other directly

# After: introduce a shared types.py that both depend on, but that depends on neither
# types.py
class UserData:
    ...

# models.py
from types_module import UserData

class User(UserData):
    ...

# services.py
from types_module import UserData

class UserService:
    def process(self, data: UserData):
        ...

If a full restructure isn't practical right now, moving the import inside the function that actually needs it (rather than at the top of the file) defers the import until the function is actually called, by which point both modules have finished their initial loading:

# services.py
def get_user_service():
    from models import User  # deferred import, avoids the circular load-time issue
    ...

This works because by the time the function actually runs (rather than at module load time), both modules have fully finished executing their top-level code, so the name being imported is guaranteed to exist. It's a pragmatic fix, though many teams consider it a code smell worth eventually refactoring away rather than a long-term solution.

For circular imports specifically involving type hints (where you need a class purely for annotation purposes, not at runtime), use TYPE_CHECKING to avoid the circular import entirely for cases where the import is only needed by static type checkers:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from models import User  # only imported by type checkers, never at runtime

class UserService:
    def process(self, user: "User"):  # string annotation avoids the runtime import
        ...

Still Not Working?

If the cycle involves more than two modules and isn't obvious from reading the tracebacks alone, map out the actual import graph explicitly rather than guessing β€” a small script using Python's own import machinery can reveal exactly which modules import which:

python -X importtime app.py 2>&1 | grep -A 2 -B 2 "models\|services"

For a clearer visual picture on larger codebases, a dedicated tool like pydeps can generate an actual dependency graph image, which makes indirect, multi-hop circular chains (A imports B imports C imports A) far easier to spot than tracing through error messages and source files by hand:

pip install pydeps
pydeps yourpackage --show-cycles