Here is my directory structure:
/home/dmugtasimov/tmp/name-res
root
tests
__init__.py
test_1.py
__init__.py
I simplified the example from the question to demostrate that only four solutions are possible:
from . import some_module
or with more commas from ..
from __future__ import absolute_import
(or use Python 3)What solution is the best? It depends on personal preference of Python 2 or 3. Only the last one is nice and universal for all Pythons. It was really a useful question.
xyz/tests/__init__.py: import xyz.tests.t
xyz/tests/t.py:
import sys
print('sys.path = %s' % sys.path) # see that the parent of "xyz" is on sys.path
print("importing xyz.tests")
import xyz.a
xyz/a.py:
# solution A: absolute_import by __future__ (or use Python 3)
#from __future__ import absolute_import
print("importing xyz.a")
# solution B: explicit relative import
#from . import b # and remove "import xyz.b"
# solution C: relative import (not recommended)
#import b # and remove "import xyz.b"
import xyz.b
xyz/b.py: print("imported xyz.b")
xyz/xyz.py: print("Imported xyz.xyz !!!")
xyz/__init__.py: empty file
Everything possible fails, e.g.
parent_of_xyz=... # The parent directory of "xyz" - absolute path
cd $parent_of_xyz
python -m xyz.tests.t
PYTHONPATH=$parent_of_xyz/xyz python -m unittest tests
PYTHONPATH=$parent_of_xyz python xyz/tests/t.py
with messages like
Imported xyz.xyz !!!
...
ImportError...
If any solution is applied (uncommented), all three examples work.
It can be more simplified without using any subdirectory.
EDIT: I tried yesterday many tests but I wrote it inconsitently from different versions. Excuse me that it was unreproducible from the answer. Now it is fixed.