Reputation: 55655
Consider the following project structure:
a.py
test/
test_a.py
with test_a.py
importing module a
:
import a
As expected, running nosetests
in the test
directory results in import error:
ERROR: Failure: ImportError (No module named a)
However, I noticed that adding an empty __init__.py
file to the test
directory makes import work with nosetests
(but not when you run test_a.py
with Python). Could you explain why?
I understand that adding __init__.py
makes test
a package. But does it mean that import includes the directory containing the package in the lookup?
Upvotes: 6
Views: 1481
Reputation: 680
I looked into the souce code of nose module and here's why.
def importFromPath(self, path, fqname):
"""Import a dotted-name package whose tail is at path. In other words,
given foo.bar and path/to/foo/bar.py, import foo from path/to/foo then
bar from path/to/foo/bar, returning bar.
"""
# find the base dir of the package
path_parts = os.path.normpath(os.path.abspath(path)).split(os.sep)
name_parts = fqname.split('.')
if path_parts[-1] == '__init__.py':
path_parts.pop()
path_parts = path_parts[:-(len(name_parts))]
dir_path = os.sep.join(path_parts)
# then import fqname starting from that dir
return self.importFromDir(dir_path, fqname)
def importFromDir(self, dir, fqname):
"""Import a module *only* from path, ignoring sys.path and
reloading if the version in sys.modules is not the one we want.
"""
dir = os.path.normpath(os.path.abspath(dir))
In your case when importFromDir is called from importFromPath, 'dir' is the directory a level above from the __init__.py
directory. So that's why adding __init__.py
to your test makes 'import a' work
Upvotes: 2
Reputation: 363294
The presence of an __init__.py
file in the directory transforms test
from just a plain old directory into a python package. This has an effect on sys.path
.
Modify your test_a.py
module like this:
import sys
def test_thing():
for i, p in enumerate(sys.path):
print i, p
try:
import a
except ImportError:
print('caught import error')
Then try running nosetests -s
from the test directory, with and without an __init__.py
in there.
Note: it is the test runner that munges sys.path
. And that is documented in the second "Note" of this section here (thanks @davidism). You won't see any change there just by running python test_a.py
with and without the package structure.
Upvotes: 5