runtime
110 / 250
lesson 110 Modules & Packages · intermediate

When an import fails

ModuleNotFoundError names the module Python couldn't find. Usually it's a typo, a module in another folder, or a package that isn't installed; sometimes it's a dependency of the module you asked for.

You'll be able to
  • Read err.name to see exactly which module is missing, and know where Python looks (sys.path)
  • Check whether a module can be imported with importlib.util.find_spec
  • Treat a missing optional module as "not available" while re-raising when one of its own dependencies is missing
The idea

ModuleNotFoundError: No module named 'pricng' is Python saying it looked everywhere it knows and found no module with that name. Where it looks is the list sys.path: first the folder of the program you ran, then the standard library, then the installed packages. The error object's name attribute is the exact module that was missing.

The usual causes, in order: a typo; the module is in another folder (inside a package, so it needs a dotted name); the package isn't installed in the environment you're running (in a real project you'd run python -m pip install <package> in the project's virtual environment; this browser runner can only load the packages it ships with); or a file of yours shadows a standard module (a json.py in your folder is found before the real json).

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Which modules can be found?
import importlib.util
from pathlib import Path

Path("pricing.py").write_text("TAX_RATE = 0.07\n", encoding="utf-8")
importlib.invalidate_caches()

for name in ["json", "pricing", "pricng", "requests"]:
    print(name, importlib.util.find_spec(name) is not None)
example-2.py · A typo in an import
import jsom

A module can be missing because it doesn't exist, or because something it imports doesn't. Code that treats a module as optional ("use the fast exporter if it's available") must tell those apart: catch the error, compare err.name with the module you asked for, and re-raise anything else, or a broken install is silently reported as "not available".

example-3.py · Optional, but not hiding a broken dependency
import importlib
from pathlib import Path

Path("fast_export.py").write_text("import polars\n\nFORMAT = 'parquet'\n", encoding="utf-8")
importlib.invalidate_caches()

def optional(name):
    try:
        return importlib.import_module(name)
    except ModuleNotFoundError as err:
        if err.name != name:
            raise
        return None

print(optional("pdf_export"))
try:
    optional("fast_export")
except ModuleNotFoundError as err:
    print("fast_export is installed but needs", err.name)

When to use it: reading any import error, writing plug-in or optional-feature code, and checking an environment before a long job. Mistakes to avoid: catching ModuleNotFoundError (or ImportError) around everything and carrying on, "fixing" a path problem by copying files around instead of importing from the package, and naming your files after standard modules.

Review
  • ModuleNotFoundError's err.name is the module Python couldn't find; sys.path is where it looked.
  • Typos, the wrong folder, a missing install and shadowing are the usual causes.
  • importlib.util.find_spec checks without importing; for optional modules, compare err.name and re-raise anything else.
  • Next module: automating real tasks with command-line arguments and files.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

When an import fails — Modules & Packages · Runtime