Reputation: 1391
I have the following:
ModuleFolder
|
|-->. ModuleFile.py .
|
'-->. TestsFolder .
|
'---> UnitTest1.py
I'm trying to import from the parent directory. In this case I am trying to run "UnitTest1.py" from the test folder, and import from the directory immediately above it (the file "ModuleFile.py").
from .. import *
but I am specifically trying to do an import MyModuleName
so I can be more explicit in the unittest and avoid mangling/collisions of names.What I am doing (and it is working for me) is the following:
sys.path.append("../")
And then importing what I need from the parent directory.
sys.path
? Because it's relative. If I am running from /home/workspace/MyModule/unittests/ and my module is under /home/workspace/MyModule/ I assumed adding /home/workspace/MyModule/ to the path won't necessarily be true if a coworker runs this on his machine under his own directory of /home/documents/MyModule.My Question:
Is this Python-proper? If not, what's wrong with this. Is there a better way? Or is this truly an RTFM moment where the answer is in one of the 7+ SO questions I've already looked at? (I saw those all recommending the explicit path rather than the relative path approach I took).
Other useful information:
Upvotes: 22
Views: 36166
Reputation: 1776
This is always very cofusing. Relative imports are relative to the module structure. To test relative imports, you need to import your module in your main file (from outside the module). Let me try to show a case that works:
$ python use_module.py
Hello World!
Or you can make it an executable module and run it with python -m
(always from outside the module)
$ python -m module.child_a
Hello World!
test_module.py
module
├── __init__.py [can be empty]
├── child_a
├── __init__.py
├── __main__.py
│── child_b
├── foo.py
test_module.py
from module.child_a import message
print(message)
foo.py
phrase = "Hello World"
mark = '!'
child_a/__init__.py
from .__main__ import message
child_a/__main__.py
from .. child_b.foo import phrase, mark
message = phrase + mark
if __name__ == "__main__":
#this block is run when executing `python -m module.etl`
print(message)
NOTE: if you add another file in child_a
say child_a/myscript.py
you can still execute it with python -m module.sub_a.myscript
(always from outside the module)
Upvotes: 0
Reputation: 831
You can also make symlink of the module path which you want to import and then use that symlink to import. Create a symlink in the python dist-packages.
To create a symlink:
ln -s "/path/to/ModuleFolder" "/path/to/python/dist/packages/module_symlink_name"
To import module in the script:
from module_symlink_name import ModuleFile
No need to export python path or modifying sys path.
Upvotes: 2
Reputation: 51113
Make your test folder a module (by adding __init__.py).
Then you can use run python -m tests.test_name
or use the following Makefile in your project home:
TEST_FILES = $(wildcard tests/test_*.py)
TESTS = $(subst .py,,$(subst /,.,$(TEST_FILES)))
all.PHONY: test
test:
@- $(foreach TEST,$(TESTS), \
echo === Running test: $(TEST); \
python -m $(TEST); \
)
Upvotes: 2
Reputation: 48564
Don't run the test from the tests folder. Run it from the root of your project, which is the module folder. You should very rarely need to muck with either sys.path
or PYTHONPATH
, and when you do, you're either causing bugs for other libraries down the road or making life harder on your users.
python -m TestsFolder.UnitTest1
If you use a test runner like py.test, you can just run py.test
from the root of your checkout and it'll find the tests for you. (Assuming you name your tests something more like test_unit1.py
. Your current naming scheme is a little unorthodox. ;))
Upvotes: 29
Reputation: 22992
It's better to insert your relative path at the begening of sys.path
like this:
import sys
sys.path.insert(0, '../')
Upvotes: 5
Reputation: 100886
My suggestion is:
Don't try to be clever, do what you're supposed to do. I.e. make sure that your modules and packages are somewhere in your Python path.
The simplest way is to set the environment variable PYTHONPATH in the shell that you use to execute your scripts:
$ export PYTHONPATH=/the/directory/where/your/modules/and/packages/are
$ cd /the/directory/where/your/unit/tests/are
$ python test1.py
Upvotes: 2