pytest-dev/pytest · error · ImportError
Can't find module {modname} at location {self!s}
Error message
Can't find module {modname} at location {self!s} What it means
Raised by LocalPath.pyimport() in importlib mode when importlib.util.spec_from_file_location returns a spec without a loader (or None). This means Python's import machinery could not determine how to load a module from the given file path — typically because the file extension is not a recognized importable format (.py, .so, etc.). The error is an ImportError, distinct from the ENOENT raised earlier when the file does not exist.
Source
Thrown at src/_pytest/_py/path.py:1099
if ensuresyspath is False no modification of syspath happens.
Special value of ensuresyspath=="importlib" is intended
purely for using in pytest, it is capable only of importing
separate .py files outside packages, e.g. for test suite
without any __init__.py file. It effectively allows having
same-named test modules in different places and offers
mild opt-in via this option. Note that it works only in
recent versions of python.
"""
if not self.check():
raise error.ENOENT(self)
if ensuresyspath == "importlib":
if modname is None:
modname = self.purebasename
spec = importlib.util.spec_from_file_location(modname, str(self))
if spec is None or spec.loader is None:
raise ImportError(f"Can't find module {modname} at location {self!s}")
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
pkgpath = None
if modname is None:
pkgpath = self.pypkgpath()
if pkgpath is not None:
pkgroot = pkgpath.dirpath()
names = self.new(ext="").relto(pkgroot).split(self.sep)
if names[-1] == "__init__":
names.pop()
modname = ".".join(names)
else:
pkgroot = self.dirpath()
modname = self.purebasename
self._ensuresyspath(ensuresyspath, pkgroot)View on GitHub (pinned to 0d6fbdeffa)
Solutions
- Ensure the target file has a Python-recognized extension (.py, .pyc, .so).
- Register a custom loader/path hook if importing a non-standard extension.
- Verify the path exists and is readable before calling pyimport.
- If importing source, use importlib.util directly with explicit source handling.
Example fix
// before mod = path.pyimport() # path points to 'data.txt' // after mod = path_with_py_extension.pyimport()
Defensive patterns
Strategy: validation
Validate before calling
import importlib.util
IMPORTABLE_EXTS = {'.py', '.pyc', '.pyo', '.so'}
def can_import(path) -> bool:
if not path.check(file=True):
return False
if path.ext not in IMPORTABLE_EXTS:
return False
spec = importlib.util.spec_from_file_location(path.purebasename, str(path))
return spec is not None and spec.loader is not None Type guard
def has_importable_ext(path) -> bool:
return path.ext in {'.py', '.pyc', '.so'} Try / catch
try:
mod = path.pyimport()
except ImportError as e:
if "Can't find module" in str(e):
# fallback: load source manually or skip
... Prevention
- Validate the file extension before pyimport.
- Use importlib.util directly for finer control over non-standard extensions.
When it happens
Trigger: Calling path.pyimport(ensuresyspath='importlib') on a .txt, .json, or extension-less file; on a path whose suffix is not registered with any import loader; with an explicit modname that importlib still cannot resolve to a loader.
Common situations: Dynamically importing test data or generated modules with unexpected extensions; cross-platform issues with .pyc vs .py; plugin systems that point at non-Python files.
Related errors
- no {name!r} checker available for {self.path!r}
- XXX win32
- can only pass None, Path instances or non-empty strings to L
- {relpath!r}: not a string or path object
- Don't know how to compute {hashtype!r} hash
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/f88739777f73315f.
Report an issue: GitHub.