I've the following source code structure
/testapp/
/testapp/__init__.py
/testapp/testmsg.py
/testapp/sub/
/testapp/sub/__init__.py
/testapp/sub/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?
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/README
TestApp/LICENSE
TestApp/setup.py
TestApp/run_test.py
TestApp/testapp/__init__.py
TestApp/testapp/testmsg.py
TestApp/testapp/sub/
TestApp/testapp/sub/__init__.py
TestApp/testapp/sub/testprinter.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;
Use relative import like below
from .. import testmsg
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)