3

For Python 3.

I just started learning Python. I have PHP and Ruby background.

Currently very confused with modules, __init__ and python -m.

At the moment I have the following:

modules/practice.py
tests/test_practice.py

In practice.py

class First:
  def attempt(self):
    return 'attempted'

In test_practice.py

from modules.practice import First

class TestMain:
  def test_attempt(self):
    first = First()
    attempted = first.attempt()
    assert attempted is 'attempted'

When I run pytest I get an error ModuleNotFoundError: No module named 'modules

When I run python -m pytest test is green.

However, if I add __init__.py files in modules and tests, both are green.

After trying to find out answers on my own I confess I am not sure I am getting it.

Why pytest does not work without __init__?

When working on a project, when people assume python -m will be used and when people add the __init__.py files instead?

Hector Ordonez
  • 1,044
  • 1
  • 12
  • 20

1 Answers1

1

Do not add an __init__.py file into the tests directory.

You should add an __init__.py file into the modules directory.

Ideally it should be possible to run the test suite with either pytest or python -m pytest. For this to work, the parent directory of modules needs to be present on sys.path. Usually you would do this by writing a setup.py file for the package and installing your code in "editable" mode. The tests run against the installed code linked in site-packages.

If you don't want to write a setup.py file at this stage, you can either export an environment variable:

export PYTHONPATH=/path/to/parent_of_modules

Or you can inject to sys.path directly from conftest.py file, which gets imported first:

.
├── modules
│   ├── __init__.py
│   └── practice.py
└── tests
    ├── conftest.py
    └── test_practice.py

Example:

# conftest.py
import os
import sys

here = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(here))
wim
  • 338,267
  • 99
  • 616
  • 750
  • Thank you very much for taking the time to answer. I am interested in best practices and this is useful. I read somewhere to avoid using PYTHONPATH as in order to not alter how things would work on different environments. Maybe I misunderstood? – Hector Ordonez Jun 16 '21 at 18:40
  • 1
    I agree that PYTHONPATH should not be used in production, but for local development it's fine. It's a convenience. Best practices: write the installer and install your code, with the tests running against the installed package. See [here](https://stackoverflow.com/a/43476575/674039) for more info. – wim Jun 16 '21 at 18:49
  • Hello! I added the conftest, it seemed the most elegant solution. But what does it do? Why does it work with it, or why does it not work without? – Hector Ordonez Jun 22 '21 at 07:17
  • For `from modules.practice import First` to work, the parent directory of "modules" needs to be present on `sys.path` somehow, and it needs to be there _before_ the file containing that import statement is loaded. Since pytest loads `conftest.py` first, this is an opportunity to modify `sys.path` before loading any test modules. – wim Jun 22 '21 at 14:16