J Carroll
J Carroll

Reputation: 1391

Python import from parent directory

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").

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.

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

Answers (6)

MarcoP
MarcoP

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!

Structure

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

PalFS
PalFS

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

Shubham Chaudhary
Shubham Chaudhary

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

Eevee
Eevee

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

Laurent LAPORTE
Laurent LAPORTE

Reputation: 22992

It's better to insert your relative path at the begening of sys.pathlike this:

import sys
sys.path.insert(0, '../')

Upvotes: 5

codeape
codeape

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

Related Questions