Suppose a repository has a directory called ./example with an __init__.py file to signal that it is a package.
The tests are in ./tests, which does not have an __init__.py file:
.
|-- README.md
|-- example
| |-- __init__.py
| `-- func.py
|-- setup.py
`-- tests
`-- test_hello.py
./example/func.py is pretty simple:
def hello():
return "hello!"
If I run an interactive interpreter in the root directory I can import example:
$ python
>>> import example
>>> example.hello()
'hello!'
I can also put a script in the root directory that imports example:
$ cat > temp.py
import example
print(example.hello())
^D
$ python temp.py
hello!
Here's where things get odd. If I run pytest in the root directory with no arguments it fails to import example:
$ pytest
ImportError while importing test module '/Users/gregwilson/example/tests/test_hello.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
../conda/envs/stjs/lib/python3.9/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_hello.py:1: in <module>
import example
E ModuleNotFoundError: No module named 'example'
However, if I run python -m pytest in the root directory it works:
$ python -m pytest
collected 1 item
tests/test_hello.py .
If I now add an empty file tests/__init__.py, the tests work both ways:
$ touch tests/_init__.py
$ python -m pytest
collected 1 item
tests/test_hello.py .
$ pytest
collected 1 item
tests/test_hello.py .
My questions are:
- Why does
pytestfail butpython -m pytestwork before I add./tests/__init__.py? - Why does adding an
__init__.pyfile totestsmakepyteston its own work?
But wait, it gets weirder.
I can make a directory ./temp and add a file ./temp/temp.py that imports example and tries to use it:
$ mkdir temp
$ cat > temp/temp.py
import example
print(example.hello())
^D
Running that directly doesn't work:
$ python temp/temp.py
ModuleNotFoundError: No module named 'example'
Running it with python -m does:
$ python -m temp.temp
hello!
But unlike the tests case, adding an __init__.py file to ./temp doesn't make it work:
$ touch temp/__init__.py
$ python temp/temp.py
ModuleNotFoundError: No module named 'example'
I'd be grateful if someone could explain what's going on here.