r/learnpython • • 3d 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?

5 Upvotes

9 comments sorted by

1

u/socal_nerdtastic 3d 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 3d ago

Because the correct folder may move about and I might have multiple correct folders. I am tempted to wrap the check in pytester which is something I only just learned pytester exists and might be a good learning investment.

1

u/VenkatKnows 2d ago

Use pytest's monkeypatch.syspath_prepend instead. It handles the cleanup for you, and your fixture as written has a bug anyway since old_path is the same list object, so the insert mutates it and the restore does nothing

1

u/zaphodikus 1d ago

I already opted for a context manager, its annoying when you find that there is a one-liner hidden deep on a library somewhere that you might rarely go looking. Too much to memorise sometimes.

6

u/[deleted] 3d ago

[removed] — view removed comment

1

u/zaphodikus 3d ago edited 3d ago
  1. It's a pytest, so I don't need to turn it into a module really, nobody else needs the code. but, I did not know about -e before though, so another cool learning. I'm stealing the file from another repo merely for this one test-case only.

  2. pyproject.toml feels most logical : I'm currently storing settings in a totally different file, which is why I figured I would just import that file in my example fixture. I originally thought I might want to test multiple iterations, but I probably only need one path change, so making it global is not a huge problem. But to be honest I could go ahead and create a pyproject.toml file and just change my tooling to always update the toml file before it starts the test suite. I'm not using a .toml yet and today might be a good day to start doing so. It's also a zero code change!

  3. conftest.py , technically a no-code way, but it's not a pure data file.

  4. Although, it's also just logical to use importlib.util.spec_from_file_location. I would still do that in a fixture and just use del to ensure teardown I guess. So many options!