Python package import from parent directory
Asked Answered
D

5

43

I've the following source code structure

testapp/
├─ __init__.py
├─ testmsg.py
├─ sub/
│  ├─ __init__.py
│  ├─ testprinter.py

where testmsg defines the following constant:

MSG = "Test message"

and sub/testprinter.py:

import testmsg

print("The message is: {0}".format(testmsg.MSG))

But I'm getting ImportError: No module named testmsg

Shouldn't it be working since the package structure? I don't really want to extend sys.path in each submodule and I don't even want to use relative import.

What am I doing wrong here?

Drugge answered 9/7, 2012 at 10:44 Comment(1)
@SimeonVisser running python sub/testprinter.py, but also python testprinter.py within sub directory doesn't work.Drugge
C
29

It all depends on which script you run. That script's path will be added to python's search path automatically.

Make it the following structure:

TestApp/
├─ testapp/
│  ├─ __init__.py
│  ├─ testmsg.py
│  ├─ sub/
│  │  ├─ __init__.py
│  │  ├─ testprinter.py
├─ README
├─ LICENSE
├─ setup.py
├─ run_test.py

Then run TestApp/run_test.py first:

from testapp.sub.testprinter import functest ; functest()

Then TestApp/testapp/sub/testprinter.py could do:

from testapp.testmsg import MSG
print("The message is: {0}".format(testmsg.MSG))

More good hints here;

Conflict answered 9/7, 2012 at 10:51 Comment(2)
may it depend on the fact that I didn't generate a setup.py file? What I mean is that I followed the python package structure but I didn't generate installation method, assuming it could also work without having to setup.py install it.Drugge
@CodeShining, no it doesn't matter. I only included the setup.py in the example for clarity. What really matters, as I said in the first paragraph of the answer, is which file you're running in first place. If you start (run) a file inside the package, it won't see the package. So it's a good practice to have your main script (the one you run) outside the package.Conflict
B
16

Use relative import like below

from .. import testmsg
Burmeister answered 9/7, 2012 at 10:47 Comment(4)
but being a package shouldn't it be working as expected? I wouldn't use relative if it's expected to workDrugge
CodeShining, look at Dido's decision for python 3.5 PEP-328 for standard. linkBurmeister
ValueError: attempted relative import beyond top-level packageRevoice
@CameronHudson the neighboring folder also needs to be a package (i.e. have its own __init__.py)Interlining
T
16

For people who still have this same problem. This is how I solve mine:

import unittest 
import sys
import os

sys.path.append(os.getcwd() + '/..')

from my_module.calc import *
Teryn answered 25/10, 2019 at 6:16 Comment(3)
This save my day, I have been searching my whole but no result, thanks :)Griskin
cwd is not always the actual parent of the script running and the running script is what is your current top level. if you want to meddle with sys.path, then you should use parent of the __file__ instead of parent of cwdDustidustie
as @SoulReaver points out, better do sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir)) (or use the pathlib module in Python3).Absenteeism
P
10

This question has the answer - dynamic importing:

How to import a python file in a parent directory

import sys
sys.path.append(path_to_parent)
import parent.file1

Here's something I made to import anything. Of course, you have to still copy this script around to local directories, import it, and use the path you want.

import sys
import os

# a function that can be used to import a python module from anywhere - even parent directories
def use(path):
    scriptDirectory = os.path.dirname(sys.argv[0])  # this is necessary to allow drag and drop (over the script) to work
    importPath = os.path.dirname(path)
    importModule = os.path.basename(path)
    sys.path.append(scriptDirectory+"\\"+importPath)        # Effing mess you have to go through to get python to import from a parent directory

    module = __import__(importModule)
    for attr in dir(module):
        if not attr.startswith('_'):
            __builtins__[attr] = getattr(module, attr)
Playpen answered 13/10, 2012 at 3:15 Comment(0)
F
2

Try this:


import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

from my_module import *

Frenetic answered 11/6, 2021 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.