I have a python module arranged in a directory. Call it foo
.
Here is the file layout:
caller.py
foo/__init__.py
foo/bar.py
foo/test/bar_test.py
That is, the module is called foo
and the code in foo/__init__.py
gets imported when the import foo
statement in caller.py
gets run.
Within foo/__init__.py
, I wish to access the contents of bar.py
. This is done with import foo.bar
.
My problem arises when writing the code that runs in foo/test/bar_test.py
. If this file was simply foo/bar_test.py
, then it could also use import foo.bar
to import the contents of foo.bar.py
. Unfortunately, we have a coding standard that says that unit tests go in a subdirectory called tests
.
Given that coding standard, how do we import bar.py?
This doesn't work:
# foo/test/bar_test.py
import foo.bar
def test_return5():
assert bar.return5() == 5
It gives me:
$ py.test
================================================== test session starts ==================================================
platform linux -- Python 3.6.3, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /home/hadoop/xxx/foo, inifile:
collected 0 items / 1 errors
======================================================== ERRORS =========================================================
___________________________________________ ERROR collecting test/bar_test.py ___________________________________________
ImportError while importing test module '/home/hadoop/xxx/foo/test/bar_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test/bar_test.py:3: in <module>
import foo.bar
E ModuleNotFoundError: No module named 'foo'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================ 1 error in 0.10 seconds ================================================
This works, but it's gross:
# foo/test/bar_test.py
import os
import sys
sys.path.append( os.path.join(os.path.dirname(__file__), "../.."))
import foo.bar
def test_return5():
assert foo.bar.return5() == 5
This does not work:
# foo/test/bar_test.py
import os
import sys
sys.path.append( os.path.join(os.path.dirname(__file__), ".."))
import bar
def test_return5():
assert bar.return5() == 5
Because:
$ py.test
================================================== test session starts ==================================================
platform linux -- Python 3.6.3, pytest-3.2.1, py-1.4.34, pluggy-0.4.0
rootdir: /home/hadoop/xxx/foo, inifile:
collected 0 items / 1 errors
======================================================== ERRORS =========================================================
___________________________________________ ERROR collecting test/bar_test.py ___________________________________________
ImportError while importing test module '/home/hadoop/xxx/foo/test/bar_test.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test/bar_test.py:8: in <module>
import bar
bar.py:3: in <module>
import foo
E ModuleNotFoundError: No module named 'foo'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
================================================ 1 error in 0.10 seconds ================================================
Because bar.py has:
# foo/bar.py
import foo
def return5():
return 5