Reputation: 720
There were already questions regarding this topic. Sometimes programmers put some __init__.py
at some places, often it is said one should use absolute paths. However, I don't get it to work here:
How do I import a class from a package so that tests in pytest run and the code can be used?
At the moment I get pytest or the code passing respective running.
My example project structure is
.
├── testingonly
│ ├── cli.py
│ ├── __init__.py
│ └── testingonly.py
└── tests
├── __init__.py
└── test_testingonly.py
__init__.py
is in both cases an empty file.
$ cat testingonly/cli.py
"""Console script for testingonly."""
from testingonly import Tester
def main(args=None):
"""Console script for testingonly."""
te = Tester()
return 0
main()
$ cat testingonly/testingonly.py
"""Main module."""
class Tester():
def __init__(self):
print("Hello")
This gives - as expected:
$ python3 testingonly/cli.py
Hello
Trying to test this, however, fails:
$ pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.7.3, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/stefan/Development/testingonly
collected 0 items / 1 error
=============================================================== ERRORS ================================================================
_____________________________________________ ERROR collecting tests/test_testingonly.py ______________________________________________
ImportError while importing test module '/home/stefan/Development/testingonly/tests/test_testingonly.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib/python3.7/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_testingonly.py:10: in <module>
from testingonly import cli
testingonly/cli.py:2: in <module>
from testingonly import Tester
E ImportError: cannot import name 'Tester' from 'testingonly' (/home/stefan/Development/testingonly/testingonly/__init__.py)
Renaming testingonly/testingonly.py
to testingonly/mytest.py
and changing the imports in test_testingonly.py (from testingonly import mytest) and cli.py (from mytest import Tester) gives
$ pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.7.3, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/stefan/Development/testingonly
collected 0 items / 1 error
=============================================================== ERRORS ================================================================
_____________________________________________ ERROR collecting tests/test_testingonly.py ______________________________________________
ImportError while importing test module '/home/stefan/Development/testingonly/tests/test_testingonly.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/lib/python3.7/importlib/__init__.py:127: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
tests/test_testingonly.py:10: in <module>
from testingonly import cli
testingonly/cli.py:2: in <module>
from mytest import Tester
E ModuleNotFoundError: No module named 'mytest'
======================================================= short test summary info =======================================================
ERROR tests/test_testingonly.py
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
========================================================== 1 error in 0.37s ===========================================================
$ python3 testingonly/cli.py
Hello
The other proposed solution with renaming to mytest.py lets the tests pass, but in cli.py using from testingonly.mytest import Tester
gives a NameNotFound error.
$ python3 testingonly/cli.py
Traceback (most recent call last):
File "testingonly/cli.py", line 2, in <module>
from testingonly.mytest import Tester
ModuleNotFoundError: No module named 'testingonly'
$ pytest
========================================================= test session starts =========================================================
platform linux -- Python 3.7.3, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /home/stefan/Development/testingonly
collected 1 item
tests/test_testingonly.py . [100%]
========================================================== 1 passed in 0.12s ==========================================================
Upvotes: 9
Views: 33554
Reputation: 1
Good day, guys
I faced the same problem and, after read a lot of options to solve it, I decided to download the Python installer with my current versions installed (3.10.9 and 3.12.1), run it, and choose Repair.
The problem is solved.
Upvotes: 0
Reputation: 24275
This is only a python path issue. Your pytest is unable to find the path to source modules.
One way to fix this: export PYTHONPATH=$PYTHONPATH:.
before running pytest. Here you are saying that your current folder represented by a dot is a python module path. This is what happens when you also run via python -m pytest
, where the module path gets set automatically.
But this requires you to set the PYTHONPATH
every time before you run pytest, or use a long command for pytest which is very inconvenient.
One earlier method to overcome this issue: install pytest-pythonpath plugin to automatically add PYTHONPATH
to environment. This module is obsolete now (as seen in its home page) because pytest.ini allows you to specify python path directly from v7 onwards
So now all you have to do is this: ensure that your pytest is version 7 or above, and your pytest.ini file should contain these lines:
[pytest]
testpaths = tests
python_files = tests.py test_*.py
pythonpath = .
Now your pytest will have no trouble finding your source modules. You may also add your source folders to pythonpath
in pytest.ini if required
pytest documentation for pythonpath: https://docs.pytest.org/en/7.0.x/reference/reference.html#confval-pythonpath
Upvotes: 5
Reputation: 3047
The self-named module testingonly
and file name of testingonly.py
may be causing some issues with the way the modules are imported.
Remove the __init__.py
from the tests
directory. Ref this answer .
Try renaming testingonly.py
to mytest.py
and then importing it into your project again.
In the cli.py
, it should be:
from testingonly.mytest import Tester
And then for your test file test_testingonly.py
:
from testingonly.mytest import Tester
You're test_testingonly.py
file should look like this:
import pytest
from testingonly.mytest import Tester # Import the Tester Class
def test_tester(capsys):
# Create the Tester Class
te = Tester()
# Get the captured output
captured = capsys.readouterr()
# Assert that the capture output is tested
assert captured.out == "Hello\n"
Finally, Run your tests with:
python -m pytest tests/
Here is a fully working example based off of your code: https://github.com/cdesch/testingonly
Upvotes: 2