PythonMastery
reference 3 min read · lesson 25 of 45 in Errors

ImportError: cannot import name 'X' from 'Y'

1 · The lesson

read

What this error means

Python found and successfully imported module Y, but when it tried to bind the name X from inside Y, that name was not there. Either X does not exist in Y (typo, renamed, removed in this version), or Y is in the middle of importing and X has not yet been defined — that is the circular import case.

When you see it

text
Traceback (most recent call last):
  File "app.py", line 1, in <module>
    from collections import OrderedDic
ImportError: cannot import name 'OrderedDic' from 'collections'

Newer Python versions also tell you where they looked:

text
ImportError: cannot import name 'soft_unicode' from 'markupsafe'
(/usr/lib/python3/site-packages/markupsafe/__init__.py)

Why it happens

Cause 1 — typo or wrong case. OrderedDic instead of OrderedDict, Path from os instead of pathlib.

Cause 2 — version mismatch. The symbol existed in an older or newer version of the package than the one you have installed. markupsafe.soft_unicode was removed in 2.1; Jinja2 < 3.1 still expects it.

Cause 3 — circular import. Module A imports from B at the top, B imports from A at the top. Whichever Python loaded first is only half-initialised when the other tries to read from it.

python
# a.py
from b import helper
def thing(): return helper() + 1

# b.py
from a import thing            # boom: a is mid-import, has no `thing` yet
def helper(): return 0

How to fix it

For typos. Check the docs or use dir(Y):

python
import collections
print([n for n in dir(collections) if 'dict' in n.lower()])

For version mismatches. Check what's installed and pin compatible versions:

bash
python -m pip show markupsafe jinja2
python -m pip install "markupsafe<2.1"   # or upgrade jinja2 instead

For circular imports. Three reliable fixes, cleanest first.

1. Extract the shared piece into a third module. Both A and B import from common.py. No cycle.

2. Move the import inside the function that needs it. The import is deferred until call time, by which point both modules are fully loaded.

python # a.py def thing(): from b import helper return helper() + 1

3. Import the module, not the name. import b then b.helper(). Python is more forgiving about half-loaded modules accessed via attribute lookup than about names bound at import time.

When you'd actually see this in real code

  • Upgrading a dependency (Django, Flask, SQLAlchemy) and a third-party plugin pinned to an older API breaks.
  • Two modules in your own project that both reference each other's models or schemas.
  • Copying an import from a code sample written against a newer version of the library.
  • ModuleNotFoundError: No module named 'Y' — Y itself can't be found. See error-modulenotfounderror.
  • AttributeError: module 'Y' has no attribute 'X' — same root cause as ImportError, but triggered by Y.X instead of from Y import X.

See Also