r/learnpython • u/zaphodikus • 11h ago
dynamic import module path hack in pytest
In order to validate (using pytest) a python module which is not in my path or relative folders, I want to hack the import path.
I'm wondering what alternatives there are to doing a PYTHONPATH hack.
I could use https://docs.pytest.org/en/7.1.x/reference/reference.html#confval-pythonpath, but that applies to the entire session as I understand it. And I only want to change one suite, so I am writing a quick fixture that will roughly look like (hard-coded for simplicity)
@pytest.fixture(scope="function")
def modules_path():
old_path = sys.path
extra_path= os.path.abspath("c:/otherpath/other") # replace constant with a func
sys.path.insert(0, extra_path)
yield extra_path
sys.path = old_path
I've always felt there was a better way to do import path hacks that nobody had ever told me about. Or is this @fixture approach not as evil as I assumed it was, and was merely biased by painful memories whenever I did use it. Alternatives?
1
u/socal_nerdtastic 10h ago
Why can't you start the pytest program in the correct folder?
cd c:/otherpath/other
py c:/path/to/pytest/program/testymctestface.py
1
u/zaphodikus 10h ago
Because the
correctfolder may move about and I might have multiplecorrectfolders. I am tempted to wrap the check inpytesterwhich is something I only just learnedpytesterexists and might be a good learning investment.
6
u/stickycontentss 10h ago
A few alternatives that are cleaner than exporting PYTHONPATH, roughly in order of preference:
Make the module installable.
pip install -e .(oruv pip install -e .) with a minimalpyproject.toml- after that pytest imports it like any installed package and the problem disappears permanently, for you and anyone else who clones the repo.pytest's built-in
pythonpathini option (pytest 7+). Inpyproject.toml:toml [tool.pytest.ini_options] pythonpath = ["src"]This is the same effect as the PYTHONPATH hack, but declarative, scoped to tests only, and applied before collection - unlike
sys.path.insert()inside a test module, which runs too late and depends on import order.Root
conftest.pythat does the path insert once - it works because conftest is loaded before test imports, but the pytest docs now recommend option 2 instead.If the file genuinely isn't importable (not on the path at all), load it explicitly in a fixture with
importlib.util.spec_from_file_location.Also worth knowing:
addopts = "--import-mode=importlib"avoids the duplicate-module-name clashes you can hit when the same filename exists in several folders.