pytest-dev/pytest · error · ImportError

import error in

Error message

import error in {used}: {ex}

What it means

An ImportError raised by _pytest.monkeypatch when resolving a dotted import path and an intermediate module fails to import, but the failure is for a different module than the one being imported (a transitive import error). The original exception is chained; the message wraps the inner error with the failing segment name so the user knows which part of the dotted path broke.

Solutions

  1. Read the chained ImportError: the inner message names the truly missing module.
  2. Install the missing dependency or fix the intermediate package's __init__.
  3. Verify the dotted path resolves in a plain Python session: `python -c 'import a.b.c'`.
  4. Patch a more specific path (closer to the leaf) to avoid importing a heavy/buggy intermediate.

Example fix

# before
monkeypatch.setattr('mypkg.sub.target', new_val)
# ImportError: import error in mypkg.sub: No module named 'missing_dep'
# after
# (install missing_dep, or patch where target already lives)
import mypkg.sub.target as t
monkeypatch.setattr(t, 'attr', new_val)
Defensive patterns

Strategy: try-catch

Validate before calling

import importlib
def path_resolves(dotted: str) -> bool:
    parts = dotted.split('.')
    mod = parts[0]
    try:
        obj = importlib.import_module(mod)
    except ImportError:
        return False
    for p in parts[1:]:
        if not hasattr(obj, p):
            return False
        obj = getattr(obj, p)
    return True

Try / catch

try:
    monkeypatch.setattr('a.b.c', value)
except ImportError as e:
    # inspect chained exception for the truly missing module
    print(f'transitive import failed: {e.__cause__}')

Prevention

When it happens

Trigger: Calling `monkeypatch.setattr('a.b.c', value)` or `monkeypatch.delattr('a.b.c')` where importing `a` or `a.b` raises an ImportError whose offending module is not the segment being imported. For example, `a` imports fine but triggers an ImportError from a sibling module.

Common situations: Patching a path in a package whose __init__ has conditional imports; missing optional dependencies of an intermediate package; circular imports; wrong environment where a transitive dependency is absent.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/5d856b5b5869b0d4. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/monkeypatch.py:88

    found: object = importlib.import_module(used)
    for part in parts:
        used += "." + part
        try:
            found = getattr(found, part)
        except AttributeError:
            pass
        else:
            continue
        # We use explicit un-nesting of the handling block in order
        # to avoid nested exceptions.
        try:
            importlib.import_module(used)
        except ImportError as ex:
            expected = str(ex).split()[-1]
            if expected == used:
                raise
            else:
                raise ImportError(f"import error in {used}: {ex}") from ex
        found = annotated_getattr(found, part, used)
    return found


def annotated_getattr(obj: object, name: str, ann: str) -> object:
    try:
        obj = getattr(obj, name)
    except AttributeError as e:
        raise AttributeError(
            f"{type(obj).__name__!r} object at {ann} has no attribute {name!r}"
        ) from e
    return obj


def derive_importpath(import_path: str, raising: bool) -> tuple[str, object]:
    if not isinstance(import_path, str) or "." not in import_path:
        raise TypeError(f"must be absolute import path string, not {import_path!r}")
    module, attr = import_path.rsplit(".", 1)

View on GitHub (pinned to 0d6fbdeffa)