This is the first time I've really sat down and tried python 3, and seem to be failing miserably. I have the following two files:
test.py
config.py
config.py has a few functions defined in it as well as a few variables. I've stripped it down to the following:
config.py
debug = True
test.py
import config
print (config.debug)
I also have an __init__.py
However, I'm getting the following error:
ModuleNotFoundError: No module named 'config'
I'm aware that the py3 convention is to use absolute imports:
from . import config
However, this leads to the following error:
ImportError: cannot import name 'config'
So I'm at a loss as to what to do here... Any help is greatly appreciated. :)
TL;DR: You can't do relative imports from the file you execute since __main__ module is not a part of a package.
Absolute imports - import something available on sys.path
Relative imports - import something relative to the current module, must be a part of a package
If you're running both variants in exactly the same way, one of them should work. Here is an example that should help you understand what's going on. Let's add another main.py file with the overall directory structure like this:
.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py
And let's update test.py to see what's going on:
# config.py
debug = True
# test.py
print(__name__)
try:
# Trying to find module in the parent package
from . import config
print(config.debug)
del config
except ImportError:
print('Relative import failed')
try:
# Trying to find module on sys.path
import config
print(config.debug)
except ModuleNotFoundError:
print('Absolute import failed')
# main.py
import ryan.test
Let's run test.py first:
$ python ryan/test.py
__main__
Relative import failed
True
Here "test" is the __main__ module and doesn't know anything about belonging to a package. However import config should work, since the ryan folder will be added to sys.path.
Let's run main.py instead:
$ python main.py
ryan.test
True
Absolute import failed
And here test is inside of the "ryan" package and can perform relative imports. import config fails since implicit relative imports are not allowed in Python 3.
Hope this helped.
P.S.: If you're sticking with Python 3 there is no more need for __init__.py files.
You have to append your project's path to PYTHONPATH and make sure to use absolute imports.
For UNIX (Linux, OSX, ...)
export PYTHONPATH="${PYTHONPATH}:/path/to/your/project/"
For Windows
set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\project\
Absolute imports
Assuming that we have the following project structure,
└── myproject
├── mypackage
│ ├── __init__.py
│ ├── a.py
└── anotherpackage
├── __init__.py
├── b.py
├── c.py
└── mysubpackage
├── __init__.py
└── d.py
just make sure to reference each import starting from the project's root directory. For instance,
# in module a.py
import anotherpackage.mysubpackage.d
# in module b
import anotherpackage.c
import mypackage.a
For a more comprehensive explanation, refer to the article How to fix ModuleNotFoundError and ImportError
I figured it out. Very frustrating, especially coming from python2.
You have to add a . to the module, regardless of whether or not it is relative or absolute.
I created the directory setup as follows.
/main.py
--/lib
--/__init__.py
--/mody.py
--/modx.py
modx.py
def does_something():
return "I gave you this string."
mody.py
from modx import does_something
def loaded():
string = does_something()
print(string)
main.py
from lib import mody
mody.loaded()
when I execute main, this is what happens
$ python main.py
Traceback (most recent call last):
File "main.py", line 2, in <module>
from lib import mody
File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
from modx import does_something
ImportError: No module named 'modx'
I ran 2to3, and the core output was this
RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
## -1,4 +1,4 ##
-from modx import does_something
+from .modx import does_something
def loaded():
string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py
I had to modify mody.py's import statement to fix it
try:
from modx import does_something
except ImportError:
from .modx import does_something
def loaded():
string = does_something()
print(string)
Then I ran main.py again and got the expected output
$ python main.py
I gave you this string.
Lastly, just to clean it up and make it portable between 2 and 3.
from __future__ import absolute_import
from .modx import does_something
Setting PYTHONPATH can also help with this problem.
Here is how it can be done on Windows
set PYTHONPATH=.
You can simply add following file to your tests directory, and then python will run it before the tests
__init__.py file
import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
Set PYTHONPATH environment variable in root project directory.
Considering UNIX-like:
export PYTHONPATH=.
Tried your example
from . import config
got the following SystemError:
/usr/bin/python3.4 test.py
Traceback (most recent call last):
File "test.py", line 1, in
from . import config
SystemError: Parent module '' not loaded, cannot perform relative import
This will work for me:
import config
print('debug=%s'%config.debug)
>>>debug=True
Tested with Python:3.4.2 - PyCharm 2016.3.2
Beside this PyCharm offers you to Import this name.
You hav to click on config and a help icon appears.
If you are using python 3+ then try adding below lines
import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)
Declare correct sys.path list before you call module:
import os, sys
#'/home/user/example/parent/child'
current_path = os.path.abspath('.')
#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)
sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')
I am working in a Linux machine. I had the same issue when I run python my_module/__main__.py.
The error is fixed, if you run the command export PYTHONPATH=. before your run your script.
export PYTHONPATH=.
python my_module/__main__.py
Try
from . import config
What that does is import from the same folder level. If you directly try to import it assumes it's a subordinate
This example works on Python 3.6.
I suggest going to Run -> Edit Configurations in PyCharm, deleting any entries there, and trying to run the code through PyCharm again.
If that doesn't work, check your project interpreter (Settings -> Project Interpreter) and run configuration defaults (Run -> Edit Configurations...).
As was stated in the comments to the original post, this seemed to be an issue with the python interpreter I was using for whatever reason, and not something wrong with the python scripts. I switched over from the WinPython bundle to the official python 3.6 from python.org and it worked just fine. thanks for the help everyone :)
You may use these statements to set the working directory, which worked for me with python3
import os
import sys
sys.path.insert(1, os.getcwd())
For me, simply adding the current directory worked.
Using the following structure:
└── myproject
├── a.py
└── b.py
a.py:
from b import some_object
# returns ModuleNotFound error
from myproject.b import some_object
# works
In my experience, PYTHONPATH environment variable does not work everytime.
In my case, my pytest only worked when I added the absolute path:
sys.path.insert(
0, "/Users/bob/project/repo/lambda"
)
I see many answers importing sys and os. Here's a not mentioned yet shorter one that GitHub Copilot gave me:
import sys
sys.path.append(__file__.rsplit("/", 1)[0])
Adding this to the top of my python script solved the problem as well.
To have Bash automatically recognise the project dir you're in:
sudo nano ~/.bashrc
OR
sudo nano ~/.bash_profile
At the bottom of the bash file:
function set_pythonpath {
export PYTHONPATH="$(pwd):$PYTHONPATH"
}
PROMPT_COMMAND=set_pythonpath
To save and exit:
Ctrl + X
Y
Test your changes by:
cat ~/.bashrc
Related
I want to import a function from another file in the same directory.
Usually, one of the following works:
from .mymodule import myfunction
from mymodule import myfunction
...but the other one gives me one of these errors:
ImportError: attempted relative import with no known parent package
ModuleNotFoundError: No module named 'mymodule'
SystemError: Parent module '' not loaded, cannot perform relative import
Why is this?
unfortunately, this module needs to be inside the package, and it also
needs to be runnable as a script, sometimes. Any idea how I could
achieve that?
It's quite common to have a layout like this...
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py
...with a mymodule.py like this...
#!/usr/bin/env python3
# Exported function
def as_int(a):
return int(a)
# Test function for module
def _test():
assert as_int('1') == 1
if __name__ == '__main__':
_test()
...a myothermodule.py like this...
#!/usr/bin/env python3
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __name__ == '__main__':
_test()
...and a main.py like this...
#!/usr/bin/env python3
from mypackage.myothermodule import add
def main():
print(add('1', '1'))
if __name__ == '__main__':
main()
...which works fine when you run main.py or mypackage/mymodule.py, but fails with mypackage/myothermodule.py, due to the relative import...
from .mymodule import as_int
The way you're supposed to run it is...
python3 -m mypackage.myothermodule
...but it's somewhat verbose, and doesn't mix well with a shebang line like #!/usr/bin/env python3.
The simplest fix for this case, assuming the name mymodule is globally unique, would be to avoid using relative imports, and just use...
from mymodule import as_int
...although, if it's not unique, or your package structure is more complex, you'll need to include the directory containing your package directory in PYTHONPATH, and do it like this...
from mypackage.mymodule import as_int
...or if you want it to work "out of the box", you can frob the PYTHONPATH in code first with this...
import sys
import os
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))
from mypackage.mymodule import as_int
It's kind of a pain, but there's a clue as to why in an email written by a certain Guido van Rossum...
I'm -1 on this and on any other proposed twiddlings of the __main__
machinery. The only use case seems to be running scripts that happen
to be living inside a module's directory, which I've always seen as an
antipattern. To make me change my mind you'd have to convince me that
it isn't.
Whether running scripts inside a package is an antipattern or not is subjective, but personally I find it really useful in a package I have which contains some custom wxPython widgets, so I can run the script for any of the source files to display a wx.Frame containing only that widget for testing purposes.
Explanation
From PEP 328
Relative imports use a module's __name__ attribute to determine that
module's position in the package hierarchy. If the module's name does
not contain any package information (e.g. it is set to '__main__')
then relative imports are resolved as if the module were a top level
module, regardless of where the module is actually located on the file
system.
At some point PEP 338 conflicted with PEP 328:
... relative imports rely on __name__ to determine the current
module's position in the package hierarchy. In a main module, the
value of __name__ is always '__main__', so explicit relative imports
will always fail (as they only work for a module inside a package)
and to address the issue, PEP 366 introduced the top level variable __package__:
By adding a new module level attribute, this PEP allows relative
imports to work automatically if the module is executed using the -m
switch. A small amount of boilerplate in the module itself will allow
the relative imports to work when the file is executed by name. [...] When it [the attribute] is present, relative imports will be based on this attribute
rather than the module __name__ attribute. [...] When the main module is specified by its filename, then the __package__ attribute will be set to None. [...] When the import system encounters an explicit relative import in a
module without __package__ set (or with it set to None), it will
calculate and store the correct value (__name__.rpartition('.')[0]
for normal modules and __name__ for package initialisation modules)
(emphasis mine)
If the __name__ is '__main__', __name__.rpartition('.')[0] returns empty string. This is why there's empty string literal in the error description:
SystemError: Parent module '' not loaded, cannot perform relative import
The relevant part of the CPython's PyImport_ImportModuleLevelObject function:
if (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
"Parent module %R not loaded, cannot perform relative "
"import", package);
goto error;
}
CPython raises this exception if it was unable to find package (the name of the package) in interp->modules (accessible as sys.modules). Since sys.modules is "a dictionary that maps module names to modules which have already been loaded", it's now clear that the parent module must be explicitly absolute-imported before performing relative import.
Note: The patch from the issue 18018 has added another if block, which will be executed before the code above:
if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
PyErr_SetString(PyExc_ImportError,
"attempted relative import with no known parent package");
goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
...
*/
If package (same as above) is empty string, the error message will be
ImportError: attempted relative import with no known parent package
However, you will only see this in Python 3.6 or newer.
Solution #1: Run your script using -m
Consider a directory (which is a Python package):
.
├── package
│ ├── __init__.py
│ ├── module.py
│ └── standalone.py
All of the files in package begin with the same 2 lines of code:
from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())
I'm including these two lines only to make the order of operations obvious. We can ignore them completely, since they don't affect the execution.
__init__.py and module.py contain only those two lines (i.e., they are effectively empty).
standalone.py additionally attempts to import module.py via relative import:
from . import module # explicit relative import
We're well aware that /path/to/python/interpreter package/standalone.py will fail. However, we can run the module with the -m command line option that will "search sys.path for the named module and execute its contents as the __main__ module":
vaultah#base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
-m does all the importing stuff for you and automatically sets __package__, but you can do that yourself in the
Solution #2: Set __package__ manually
Please treat it as a proof of concept rather than an actual solution. It isn't well-suited for use in real-world code.
PEP 366 has a workaround to this problem, however, it's incomplete, because setting __package__ alone is not enough. You're going to need to import at least N preceding packages in the module hierarchy, where N is the number of parent directories (relative to the directory of the script) that will be searched for the module being imported.
Thus,
Add the parent directory of the Nth predecessor of the current module to sys.path
Remove the current file's directory from sys.path
Import the parent module of the current module using its fully-qualified name
Set __package__ to the fully-qualified name from 2
Perform the relative import
I'll borrow files from the Solution #1 and add some more subpackages:
package
├── __init__.py
├── module.py
└── subpackage
├── __init__.py
└── subsubpackage
├── __init__.py
└── standalone.py
This time standalone.py will import module.py from the package package using the following relative import
from ... import module # N = 3
We'll need to precede that line with the boilerplate code, to make it work.
import sys
from pathlib import Path
if __name__ == '__main__' and __package__ is None:
file = Path(__file__).resolve()
parent, top = file.parent, file.parents[3]
sys.path.append(str(top))
try:
sys.path.remove(str(parent))
except ValueError: # Already removed
pass
import package.subpackage.subsubpackage
__package__ = 'package.subpackage.subsubpackage'
from ... import module # N = 3
It allows us to execute standalone.py by filename:
vaultah#base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py
A more general solution wrapped in a function can be found here. Example usage:
if __name__ == '__main__' and __package__ is None:
import_parents(level=3) # N = 3
from ... import module
from ...module.submodule import thing
Solution #3: Use absolute imports and setuptools
The steps are -
Replace explicit relative imports with equivalent absolute imports
Install package to make it importable
For instance, the directory structure may be as follows
.
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module.py
│ │ └── standalone.py
│ └── setup.py
where setup.py is
from setuptools import setup, find_packages
setup(
name = 'your_package_name',
packages = find_packages(),
)
The rest of the files were borrowed from the Solution #1.
Installation will allow you to import the package regardless of your working directory (assuming there'll be no naming issues).
We can modify standalone.py to use this advantage (step 1):
from package import module # absolute import
Change your working directory to project and run /path/to/python/interpreter setup.py install --user (--user installs the package in your site-packages directory) (step 2):
vaultah#base:~$ cd project
vaultah#base:~/project$ python3 setup.py install --user
Let's verify that it's now possible to run standalone.py as a script:
vaultah#base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
Note: If you decide to go down this route, you'd be better off using virtual environments to install packages in isolation.
Solution #4: Use absolute imports and some boilerplate code
Frankly, the installation is not necessary - you could add some boilerplate code to your script to make absolute imports work.
I'm going to borrow files from Solution #1 and change standalone.py:
Add the parent directory of package to sys.path before attempting to import anything from package using absolute imports:
import sys
from pathlib import Path # if you haven't already done so
file = Path(__file__).resolve()
parent, root = file.parent, file.parents[1]
sys.path.append(str(root))
# Additionally remove the current file's directory from sys.path
try:
sys.path.remove(str(parent))
except ValueError: # Already removed
pass
Replace the relative import by the absolute import:
from package import module # absolute import
standalone.py runs without problems:
vaultah#base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
I feel that I should warn you: try not to do this, especially if your project has a complex structure.
As a side note, PEP 8 recommends the use of absolute imports, but states that in some scenarios explicit relative imports are acceptable:
Absolute imports are recommended, as they are usually more readable
and tend to be better behaved (or at least give better error
messages). [...] However, explicit relative imports are an acceptable
alternative to absolute imports, especially when dealing with complex
package layouts where using absolute imports would be unnecessarily
verbose.
Put this inside your package's __init__.py file:
# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
Assuming your package is like this:
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module1.py
│ │ └── module2.py
│ └── setup.py
Now use regular imports in you package, like:
# in module2.py
from module1 import class1
This works in both python 2 and 3.
I ran into this issue. A hack workaround is importing via an if/else block like follows:
#!/usr/bin/env python3
#myothermodule
if __name__ == '__main__':
from mymodule import as_int
else:
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __name__ == '__main__':
_test()
SystemError: Parent module '' not loaded, cannot perform relative import
This means you are running a module inside the package as a script. Mixing scripts inside packages is tricky and should be avoided if at all possible. Use a wrapper script that imports the package and runs your scripty function instead.
If your top-level directory is called foo, which is on your PYTHONPATH module search path, and you have a package bar there (it is a directory you'd expect an __init__.py file in), scripts should not be placed inside bar, but should live on in foo at best.
Note that scripts differ from modules here in that they are used as a filename argument to the python command, either by using python <filename> or via a #! (shebang) line. It is loaded directly as the __main__ module (this is why if __name__ == "__main__": works in scripts), and there is no package context to build on for relative imports.
Your options
If you can, package your project with setuptools (or poetry or flit, which can help simplify packaging), and create console script entrypoints; installing your project with pip then creates scripts that know how to import your package properly. You can install your package locally with pip install -e ., so it can still be edited in-place.
Otherwise, never, ever, use python path/to/packagename/file.py, always use python path/to/script.py and script.py can use from packagename import ....
As a fallback, you could use the -m command-line switch to tell Python to import a module and use that as the __main__ file instead. This does not work with a shebang line, as there is no script file any more, however.
If you use python -m foo.bar and foo/bar.py is found in a sys.path directory, that is then imported and executed as __main__ with the right package context. If bar is also a package, inside foo/, it must have a __main__.py file (so foo/bar/__main__.py as the path from the sys.path directory).
In extreme circumstances, add the metadata Python uses to resolve relative imports by setting __package__ directly; the file foo/bar/spam.py, importable as foo.bar.spam, is given the global __package__ = "foo.bar". It is just another global, like __file__ and __name__, set by Python when imported.
On sys.path
The above all requires that your package can be imported, which means it needs to be found in one of the directories (or zipfiles) listed in sys.path. There are several options here too:
The directory where path/to/script.py was found (so path/to) is automatically added to sys.path. Executing python path/to/foo.py adds path/to to sys.path.
If you packaged your project (with setuptools, poetry, flit or another Python packaging tool), and installed it, the package has been added to the right place already.
As a last resort, add the right directory to sys.path yourself. If the package can be located relatively to the script file, use the __file__ variable in the script global namespace (e.g. using the pathlib.Path object, HERE = Path(__file__).resolve().parent is a reference to the directory the file lives in, as absolute path).
For PyCharm users:
I also was getting ImportError: attempted relative import with no known parent package because I was adding the . notation to silence a PyCharm parsing error. PyCharm innaccurately reports not being able to find:
lib.thing import function
If you change it to:
.lib.thing import function
it silences the error but then you get the aforementioned ImportError: attempted relative import with no known parent package. Just ignore PyCharm's parser. It's wrong and the code runs fine despite what it says.
To obviate this problem, I devised a solution with the repackage package, which has worked for me for some time. It adds the upper directory to the lib path:
import repackage
repackage.up()
from mypackage.mymodule import myfunction
Repackage can make relative imports that work in a wide range of cases, using an intelligent strategy (inspecting the call stack).
TL;DR: to #Aya's answer, updated with pathlib library, and working for Jupyter notebooks where __file__ is not defined:
You want to import my_function defined under ../my_Folder_where_the_package_lives/my_package.py
respect to where you are writing the code.
Then do:
import os
import sys
import pathlib
PACKAGE_PARENT = pathlib.Path(__file__).parent
#PACKAGE_PARENT = pathlib.Path.cwd().parent # if on jupyter notebook
SCRIPT_DIR = PACKAGE_PARENT / "my_Folder_where_the_package_lives"
sys.path.append(str(SCRIPT_DIR))
from my_package import my_function
Hopefully, this will be of value to someone out there - I went through half a dozen stackoverflow posts trying to figure out relative imports similar to whats posted above here. I set up everything as suggested but I was still hitting ModuleNotFoundError: No module named 'my_module_name'
Since I was just developing locally and playing around, I hadn't created/run a setup.py file. I also hadn't apparently set my PYTHONPATH.
I realized that when I ran my code as I had been when the tests were in the same directory as the module, I couldn't find my module:
$ python3 test/my_module/module_test.py 2.4.0
Traceback (most recent call last):
File "test/my_module/module_test.py", line 6, in <module>
from my_module.module import *
ModuleNotFoundError: No module named 'my_module'
However, when I explicitly specified the path things started to work:
$ PYTHONPATH=. python3 test/my_module/module_test.py 2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s
OK
So, in the event that anyone has tried a few suggestions, believes their code is structured correctly and still finds themselves in a similar situation as myself try either of the following if you don't export the current directory to your PYTHONPATH:
Run your code and explicitly include the path like so:
$ PYTHONPATH=. python3 test/my_module/module_test.py
To avoid calling PYTHONPATH=., create a setup.py file with contents like the following and run python setup.py development to add packages to the path:
# setup.py
from setuptools import setup, find_packages
setup(
name='sample',
packages=find_packages()
)
TL;DR
You can only relatively import modules inside another module in the same package.
Concept Clarify
We see a lot of example code in books/docs/articles, they show us how to relatively import a module, but when we do so, it fails.
The reason is, put it in a simple sentence, we did not run the code as the python module mechanism expects, even though the code is written totally right. It's like some kind of runtime thing.
Module loading is depended on how you run the code. That is the source of confusion.
What is a module?
A module is a python file when and only when it is being imported by another file. Given a file mod.py, is it a module? Yes and No, if you run python mod.py, it is not a module, because it is not imported.
What is a package?
A package is a folder that includes Python module(s).
BTW, __init__.py is not necessary from python 3.3, if you don't need any package initialization or auto-load submodules. You don't need to place a blank __init__.py in a directory.
That proves a package is just a folder as long as there are files being imported.
Real Answer
Now, this description becomes clearer.
You can only relatively import modules inside another module in the same package.
Given a directory:
. CWD
|-- happy_maker.py # content: print('Sends Happy')
`-- me.py # content: from . import happy_maker
Run python me.py, we got attempted relative import with no known parent package
me.py is run directly, it is not a module, and we can't use relative import in it.
Solution 1
Use import happy_maker instead of from . import happy_maker
Solution 2
Switch our working directory to the parent folder.
. CWD
|-- happy
| |-- happy_maker.py
`-- me.py
Run python -m happy.me.
When we are in the directory that includes happy, happy is a package, me.py, happy_maker.py are modules, we can use relative import now, and we still want to run me.py, so we use -m which means run the module as a script.
Python Idiom
. CWD
|-- happy
| |-- happy_maker.py # content: print('Sends Happy')
| `-- me.py # content: from . import happy_maker
`-- main.py # content: import happy.me
This structure is the python idiom. main is our script, best practice in Python. Finally, we got there.
Siblings or Grandparents
Another common need:
.
|-- happy
| |-- happy_maker.py
| `-- me.py
`-- sad
`-- sad_maker.py
We want to import sad_maker in me.py, How to do that?
First, we need to make happy and sad in the same package, so we have to go up a directory level. And then from ..sad import sad_maker in the me.py.
That is all.
My boilerplate to make a module with relative imports in a package runnable standalone.
package/module.py
## Standalone boilerplate before relative imports
if __package__ is None:
DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(DIR.parent))
__package__ = DIR.name
from . import variable_in__init__py
from . import other_module_in_package
...
Now you can use your module in any fashion:
Run module as usual: python -m package.module
Use it as a module: python -c 'from package import module'
Run it standalone: python package/module.py
or with shebang (#!/bin/env python) just: package/module.py
NB! Using sys.path.append instead of sys.path.insert will give you a hard to trace error if your module has the same name as your package. E.g. my_script/my_script.py
Of course if you have relative imports from higher levels in your package hierarchy, than this is not enough, but for most cases, it's just okay.
I needed to run python3 from the main project directory to make it work.
For example, if the project has the following structure:
project_demo/
├── main.py
├── some_package/
│ ├── __init__.py
│ └── project_configs.py
└── test/
└── test_project_configs.py
Solution
I would run python3 inside folder project_demo/ and then perform a
from some_package import project_configs
I was getting this ImportError: attempted relative import with no known parent package
In my program I was using the file from current path for importing its function.
from .filename import function
Then I modified the current path (Dot) with package name. Which resolved my issue.
from package_name.filename import function
I hope the above answer helps you.
Importing from same directory
Firstly, you can import from the same directory.
Here is the file structure...
Folder
|
├─ Scripts
| ├─ module123.py
|
├─ main.py
├─ script123.py
Here is main.py
from . import script123
from Scripts import module123
As you can see, importing from . imports from current directory.
Note: if running using anything but IDLE, make sure that your terminal is navigated to the same directory as the main.py file before running.
Also, importing from a local folder also works.
Importing from parent directory
As seen in my GitHub gist here, there is the following method.
Take the following file tree...
ParentDirectory
├─ Folder
| |
| ├─ Scripts
| | ├─ module123.py
| |
| ├─ main.py
| ├─ script123.py
|
├─ parentModule.py
Then, just add this code to the top of your main.py file.
import inspect
import os
import sys
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_dir = os.path.dirname(current_dir)
sys.path.insert(0, parent_dir)
from ParentDirectory import Stuff
I tried all of the above to no avail, only to realize I mistakenly had a - in my package name.
In short, don't have - in the directory where __init__.py is. I've never felt elated after finding out such inanity.
if both packages are in your import path (sys.path), and the module/class you want is in example/example.py, then to access the class without relative import try:
from example.example import fkt
If none of the above worked for you, you can specify the module explicitly.
Directory:
├── Project
│ ├── Dir
│ │ ├── __init__.py
│ │ ├── module.py
│ │ └── standalone.py
Solution:
#in standalone.py
from Project.Dir.module import ...
module - the module to be imported
Here is a three-liner for those who disagree with Guido:
import sys
from pathlib import Path
sys.path.append(str(Path(sys.argv[0]).absolute().parent.parent))
Hope it helps.
I think the best solution is to create a package for your module:
Here is more info on how to do it.
Once you have a package you don't need to worry about relative import, you can just do absolute imports.
I encounter this a lot when I am working with Django, since a lot of functionality is performed from the manage.py script but I also want to have some of my modules runnable directly as scripts as well (ideally you would make them manage.py directives but we're not there yet).
This is a mock up of what such a project might look like;
├── dj_app
│ ├── models.py
│ ├── ops
│ │ ├── bar.py
│ │ └── foo.py
│ ├── script.py
│ ├── tests.py
│ ├── utils.py
│ └── views.py
└── manage.py
The important parts here being manage.py, dj_app/script.py, and dj_app/tests.py. We also have submodules dj_app/ops/bar.py and dj_app/ops/foo.py which contain more items we want to use throughout the project.
The source of the issue commonly comes from wanting your dj_app/script.py script methods to have test cases in dj_app/tests.py which get invoked when you run manage.py test.
This is how I set up the project and its imports;
# dj_app/ops/foo.py
# Foo operation methods and classes
foo_val = "foo123"
.
# dj_app/ops/bar.py
# Bar operations methods and classes
bar_val = "bar123"
.
# dj_app/script.py
# script to run app methods from CLI
# if run directly from command line
if __name__ == '__main__':
from ops.bar import bar_val
from ops.foo import foo_val
# otherwise
else:
from .ops.bar import bar_val
from .ops.foo import foo_val
def script_method1():
print("this is script_method1")
print("bar_val: {}".format(bar_val))
print("foo_val: {}".format(foo_val))
if __name__ == '__main__':
print("running from the script")
script_method1()
.
# dj_app/tests.py
# test cases for the app
# do not run this directly from CLI or the imports will break
from .script import script_method1
from .ops.bar import bar_val
from .ops.foo import foo_val
def main():
print("Running the test case")
print("testing script method")
script_method1()
if __name__ == '__main__':
print("running tests from command line")
main()
.
# manage.py
# just run the test cases for this example
import dj_app.tests
dj_app.tests.main()
.
Running the test cases from manage.py;
$ python3 manage.py
Running the test case
testing script method
this is script_method1
bar_val: bar123
foo_val: foo123
Running the script on its own;
$ python3 dj_app/script.py
running from the script
this is script_method1
bar_val: bar123
foo_val: foo123
Note that you get an error if you try to run the test.py directly however, so don't do that;
$ python3 dj_app/tests.py
Traceback (most recent call last):
File "dj_app/tests.py", line 5, in <module>
from .script import script_method1
ModuleNotFoundError: No module named '__main__.script'; '__main__' is not a package
If I run into more complicated situations for imports, I usually end up implementing something like this to hack through it;
import os
import sys
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, THIS_DIR)
from script import script_method1
sys.path.pop(0)
This my project structure
├── folder
| |
│ ├── moduleA.py
| | |
| | └--function1()
| | └~~ uses function2()
| |
│ └── moduleB.py
| |
| └--function2()
|
└── main.py
└~~ uses function1()
Here my moduleA imports moduleB and main imports moduleA
I added the snippet below in moduleA to import moduleB
try:
from .moduleB import function2
except:
from moduleB import function2
Now I can execute both main.py as well as moduleA.py individually
Is this a solution ?
The below solution is tested on Python3
├── classes
| |
| ├──__init__.py
| |
│ ├── userclass.py
| | |
| | └--viewDetails()
| |
| |
│ └── groupclass.py
| |
| └--viewGroupDetails()
|
└── start.py
└~~ uses function1()
Now, in order to use viewDetails of userclass or viewGroupDetails of groupclass define that in _ init _.py of classess directory first.
Ex: In _ init _.py
from .userclasss import viewDetails
from .groupclass import viewGroupDetails
Step2: Now, in start.py we can directly import viewDetails
Ex: In start.py
from classes import viewDetails
from classes import viewGroupDetails
I ran into a similar problem when trying to write a python file that can be loaded either as a module or an executable script.
Setup
/path/to/project/
├── __init__.py
└── main.py
└── mylib/
├── list_util.py
└── args_util.py
with:
main.py:
#!/usr/bin/env python3
import sys
import mylib.args_util
if __name__ == '__main__':
print(f'{mylib.args_util.parseargs(sys.argv[1:])=}')
mylib/list_util.py:
def to_int_list(args):
return [int(x) for x in args]
mylib/args_util.py:
#!/usr/bin/env python3
import sys
from . import list_util as lu
def parseargs(args):
return sum(lu.to_int_list(args))
if __name__ == '__main__':
print(f'{parseargs(sys.argv[1:])=}')
Output
$ ./main.py 1 2 3
mylib.args_util.parseargs(sys.argv[1:])=6
$ mylib/args_util.py 1 2 3
Traceback (most recent call last):
File "/path/to/project/mylib/args_util.py", line 10, in <module>
from . import list_util as lu
ImportError: attempted relative import with no known parent package
Solution
I settled for a Bash/Python polyglot solution. The Bash version of the program just calls python3 -m mylib.args_util then exits.
The Python version ignores the Bash code because it's contained in the docstring.
The Bash version ignores the Python code because it uses exec to stop parsing/running lines.
mylib/args_util.py:
#!/bin/bash
# -*- Mode: python -*-
''''true
exec /usr/bin/env python3 -m mylib.args_util "$#"
'''
import sys
from . import list_util as lu
def parseargs(args):
return sum(lu.to_int_list(args))
if __name__ == '__main__':
print(f'{parseargs(sys.argv[1:])=}')
Output
$ ./main.py 1 2 3
mylib.args_util.parseargs(sys.argv[1:])=6
$ mylib/args_util.py 1 2 3
parseargs(sys.argv[1:])=6
Explanation
Line 1: #!/bin/bash; this is the "shebang" line; it tells the interactive shell how run this script.
Python: ignored (comment)
Bash: ignored (comment)
Line 2: # -*- Mode: python -*- optional; this is called the "mode-line"; it tells Emacs to use Python syntax highlighting instead of guessing that the language is Bash when reading the file.
Python: ignored (comment)
Bash: ignored (comment)
Line 3: ''''true
Python: views this as an unassigned docstring starting with 'true\n
Bash: views this as three strings (of which the first two are empty strings) that expand to true (i.e. '' + '' + 'true' = 'true'); it then runs true (which does nothing) and continues to the next line
Line 4: exec /usr/bin/env python3 -m mylib.args_util "$#"
Python: still views this as part of the docstring from line 3.
Bash: runs python3 -m mylib.args_util then exits (it doesn't parse anything beyond this line)
Line 5: '''
Python: views this as the end of the docstring from line 3.
Bash: doesn't parse this line
Caveats
This doesn't work on Windows:
Workaround: Use WSL or a Batch wrapper script to call python -m mylib.args_util.
This only works if the current working directory is set to /path/to/project/.
Workaround: Set PYTHONPATH when calling /usr/bin/env
#!/bin/bash
# -*- Mode: python -*-
''''true
exec /usr/bin/env python3 \
PYTHONPATH="$(cd "$(dirname "$0")/.." ; pwd)" \
-m mylib.args_util "$#"
'''
I've created a new, experimental import library for Python: ultraimport
It gives the programmer more control over imports and makes them unambiguous. Also it gives better error messages when an import fails.
It allows you to do relative, file-system based imports that always work, no matter how you run your code and no matter what is your current working directory. It does not matter if you run a script or module. You also don't have to change sys.path which might have other side effects.
You would then change
from .mymodule import myfunction
to
import ultraimport
myfunction = ultraimport('__dir__/mymodule.py', 'myfunction')
This way the import will always work, even if you run the code as script.
One issue when importing scripts like this is that subsequent relative imports might fail. ultraimport has a builtin preprocessor to automatically rewrite relative imports.
I had a similar problem: I needed a Linux service and cgi plugin which use common constants to cooperate. The 'natural' way to do this is to place them in the init.py of the package, but I cannot start the cgi plugin with the -m parameter.
My final solution was similar to Solution #2 above:
import sys
import pathlib as p
import importlib
pp = p.Path(sys.argv[0])
pack = pp.resolve().parent
pkg = importlib.import_module('__init__', package=str(pack))
The disadvantage is that you must prefix the constants (or common functions) with pkg:
print(pkg.Glob)
TLDR; Append Script path to the System Path by adding following in the entry point of your python script.
import os.path
import sys
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
Thats it now you can run your project in PyCharma as well as from Terminal!!
Moving the file from which you are importing to an outside directory helps.
This is extra useful when your main file makes any other files in its own directory.
Ex:
Before:
Project
|---dir1
|-------main.py
|-------module1.py
After:
Project
|---module1.py
|---dir1
|-------main.py
I was getting the same error and my project structure was like
->project
->vendors
->vendors.py
->main.py
I was trying to call like this
from .vendors.Amazon import Amazom_Purchase
Here it was throwing an error so I fixed it simply by removing the first . from the statement
from vendors.Amazon import Amazom_Purchase
Hope this helps.
It's good to note that sometimes the cache causes of all it - I've tried different things after re-arranging classes into new directories and relative import started to work after I removed the __pycache__
If the following import:
from . import something
doesn't work for you it is because this is python-packaging import and will not work with your regular implementation, and here is an example to show how to use it:
Folder structure:
.
└── funniest
├── funniest
│ ├── __init__.py
│ └── text.py
├── main.py
└── setup.py
inside __init__.py add:
def available_module():
return "hello world"
text.py add:
from . import available_module
inside setup.py add
from setuptools import setup
setup(name='funniest',
version='0.1',
description='The funniest joke in the world',
url='http://github.com/storborg/funniest',
author='Flying Circus',
author_email='flyingcircus#example.com',
license='MIT',
packages=['funniest'],
zip_safe=False)
Now, this is the most important part you need to install your package:
pip install .
Anywhere else in our system using the same Python, we can do this now:
>> import funnies.text as fun
>> fun.available_module()
This should output 'hello world'
you can test this in main.py (this will not require any installation of the Package)
Here is main.py as well
import funniest.text as fun
print(fun.available_module())
I want to import a function from another file in the same directory.
Usually, one of the following works:
from .mymodule import myfunction
from mymodule import myfunction
...but the other one gives me one of these errors:
ImportError: attempted relative import with no known parent package
ModuleNotFoundError: No module named 'mymodule'
SystemError: Parent module '' not loaded, cannot perform relative import
Why is this?
unfortunately, this module needs to be inside the package, and it also
needs to be runnable as a script, sometimes. Any idea how I could
achieve that?
It's quite common to have a layout like this...
main.py
mypackage/
__init__.py
mymodule.py
myothermodule.py
...with a mymodule.py like this...
#!/usr/bin/env python3
# Exported function
def as_int(a):
return int(a)
# Test function for module
def _test():
assert as_int('1') == 1
if __name__ == '__main__':
_test()
...a myothermodule.py like this...
#!/usr/bin/env python3
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __name__ == '__main__':
_test()
...and a main.py like this...
#!/usr/bin/env python3
from mypackage.myothermodule import add
def main():
print(add('1', '1'))
if __name__ == '__main__':
main()
...which works fine when you run main.py or mypackage/mymodule.py, but fails with mypackage/myothermodule.py, due to the relative import...
from .mymodule import as_int
The way you're supposed to run it is...
python3 -m mypackage.myothermodule
...but it's somewhat verbose, and doesn't mix well with a shebang line like #!/usr/bin/env python3.
The simplest fix for this case, assuming the name mymodule is globally unique, would be to avoid using relative imports, and just use...
from mymodule import as_int
...although, if it's not unique, or your package structure is more complex, you'll need to include the directory containing your package directory in PYTHONPATH, and do it like this...
from mypackage.mymodule import as_int
...or if you want it to work "out of the box", you can frob the PYTHONPATH in code first with this...
import sys
import os
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.dirname(SCRIPT_DIR))
from mypackage.mymodule import as_int
It's kind of a pain, but there's a clue as to why in an email written by a certain Guido van Rossum...
I'm -1 on this and on any other proposed twiddlings of the __main__
machinery. The only use case seems to be running scripts that happen
to be living inside a module's directory, which I've always seen as an
antipattern. To make me change my mind you'd have to convince me that
it isn't.
Whether running scripts inside a package is an antipattern or not is subjective, but personally I find it really useful in a package I have which contains some custom wxPython widgets, so I can run the script for any of the source files to display a wx.Frame containing only that widget for testing purposes.
Explanation
From PEP 328
Relative imports use a module's __name__ attribute to determine that
module's position in the package hierarchy. If the module's name does
not contain any package information (e.g. it is set to '__main__')
then relative imports are resolved as if the module were a top level
module, regardless of where the module is actually located on the file
system.
At some point PEP 338 conflicted with PEP 328:
... relative imports rely on __name__ to determine the current
module's position in the package hierarchy. In a main module, the
value of __name__ is always '__main__', so explicit relative imports
will always fail (as they only work for a module inside a package)
and to address the issue, PEP 366 introduced the top level variable __package__:
By adding a new module level attribute, this PEP allows relative
imports to work automatically if the module is executed using the -m
switch. A small amount of boilerplate in the module itself will allow
the relative imports to work when the file is executed by name. [...] When it [the attribute] is present, relative imports will be based on this attribute
rather than the module __name__ attribute. [...] When the main module is specified by its filename, then the __package__ attribute will be set to None. [...] When the import system encounters an explicit relative import in a
module without __package__ set (or with it set to None), it will
calculate and store the correct value (__name__.rpartition('.')[0]
for normal modules and __name__ for package initialisation modules)
(emphasis mine)
If the __name__ is '__main__', __name__.rpartition('.')[0] returns empty string. This is why there's empty string literal in the error description:
SystemError: Parent module '' not loaded, cannot perform relative import
The relevant part of the CPython's PyImport_ImportModuleLevelObject function:
if (PyDict_GetItem(interp->modules, package) == NULL) {
PyErr_Format(PyExc_SystemError,
"Parent module %R not loaded, cannot perform relative "
"import", package);
goto error;
}
CPython raises this exception if it was unable to find package (the name of the package) in interp->modules (accessible as sys.modules). Since sys.modules is "a dictionary that maps module names to modules which have already been loaded", it's now clear that the parent module must be explicitly absolute-imported before performing relative import.
Note: The patch from the issue 18018 has added another if block, which will be executed before the code above:
if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
PyErr_SetString(PyExc_ImportError,
"attempted relative import with no known parent package");
goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
...
*/
If package (same as above) is empty string, the error message will be
ImportError: attempted relative import with no known parent package
However, you will only see this in Python 3.6 or newer.
Solution #1: Run your script using -m
Consider a directory (which is a Python package):
.
├── package
│ ├── __init__.py
│ ├── module.py
│ └── standalone.py
All of the files in package begin with the same 2 lines of code:
from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())
I'm including these two lines only to make the order of operations obvious. We can ignore them completely, since they don't affect the execution.
__init__.py and module.py contain only those two lines (i.e., they are effectively empty).
standalone.py additionally attempts to import module.py via relative import:
from . import module # explicit relative import
We're well aware that /path/to/python/interpreter package/standalone.py will fail. However, we can run the module with the -m command line option that will "search sys.path for the named module and execute its contents as the __main__ module":
vaultah#base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
-m does all the importing stuff for you and automatically sets __package__, but you can do that yourself in the
Solution #2: Set __package__ manually
Please treat it as a proof of concept rather than an actual solution. It isn't well-suited for use in real-world code.
PEP 366 has a workaround to this problem, however, it's incomplete, because setting __package__ alone is not enough. You're going to need to import at least N preceding packages in the module hierarchy, where N is the number of parent directories (relative to the directory of the script) that will be searched for the module being imported.
Thus,
Add the parent directory of the Nth predecessor of the current module to sys.path
Remove the current file's directory from sys.path
Import the parent module of the current module using its fully-qualified name
Set __package__ to the fully-qualified name from 2
Perform the relative import
I'll borrow files from the Solution #1 and add some more subpackages:
package
├── __init__.py
├── module.py
└── subpackage
├── __init__.py
└── subsubpackage
├── __init__.py
└── standalone.py
This time standalone.py will import module.py from the package package using the following relative import
from ... import module # N = 3
We'll need to precede that line with the boilerplate code, to make it work.
import sys
from pathlib import Path
if __name__ == '__main__' and __package__ is None:
file = Path(__file__).resolve()
parent, top = file.parent, file.parents[3]
sys.path.append(str(top))
try:
sys.path.remove(str(parent))
except ValueError: # Already removed
pass
import package.subpackage.subsubpackage
__package__ = 'package.subpackage.subsubpackage'
from ... import module # N = 3
It allows us to execute standalone.py by filename:
vaultah#base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py
A more general solution wrapped in a function can be found here. Example usage:
if __name__ == '__main__' and __package__ is None:
import_parents(level=3) # N = 3
from ... import module
from ...module.submodule import thing
Solution #3: Use absolute imports and setuptools
The steps are -
Replace explicit relative imports with equivalent absolute imports
Install package to make it importable
For instance, the directory structure may be as follows
.
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module.py
│ │ └── standalone.py
│ └── setup.py
where setup.py is
from setuptools import setup, find_packages
setup(
name = 'your_package_name',
packages = find_packages(),
)
The rest of the files were borrowed from the Solution #1.
Installation will allow you to import the package regardless of your working directory (assuming there'll be no naming issues).
We can modify standalone.py to use this advantage (step 1):
from package import module # absolute import
Change your working directory to project and run /path/to/python/interpreter setup.py install --user (--user installs the package in your site-packages directory) (step 2):
vaultah#base:~$ cd project
vaultah#base:~/project$ python3 setup.py install --user
Let's verify that it's now possible to run standalone.py as a script:
vaultah#base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
Note: If you decide to go down this route, you'd be better off using virtual environments to install packages in isolation.
Solution #4: Use absolute imports and some boilerplate code
Frankly, the installation is not necessary - you could add some boilerplate code to your script to make absolute imports work.
I'm going to borrow files from Solution #1 and change standalone.py:
Add the parent directory of package to sys.path before attempting to import anything from package using absolute imports:
import sys
from pathlib import Path # if you haven't already done so
file = Path(__file__).resolve()
parent, root = file.parent, file.parents[1]
sys.path.append(str(root))
# Additionally remove the current file's directory from sys.path
try:
sys.path.remove(str(parent))
except ValueError: # Already removed
pass
Replace the relative import by the absolute import:
from package import module # absolute import
standalone.py runs without problems:
vaultah#base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
I feel that I should warn you: try not to do this, especially if your project has a complex structure.
As a side note, PEP 8 recommends the use of absolute imports, but states that in some scenarios explicit relative imports are acceptable:
Absolute imports are recommended, as they are usually more readable
and tend to be better behaved (or at least give better error
messages). [...] However, explicit relative imports are an acceptable
alternative to absolute imports, especially when dealing with complex
package layouts where using absolute imports would be unnecessarily
verbose.
Put this inside your package's __init__.py file:
# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
Assuming your package is like this:
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module1.py
│ │ └── module2.py
│ └── setup.py
Now use regular imports in you package, like:
# in module2.py
from module1 import class1
This works in both python 2 and 3.
I ran into this issue. A hack workaround is importing via an if/else block like follows:
#!/usr/bin/env python3
#myothermodule
if __name__ == '__main__':
from mymodule import as_int
else:
from .mymodule import as_int
# Exported function
def add(a, b):
return as_int(a) + as_int(b)
# Test function for module
def _test():
assert add('1', '1') == 2
if __name__ == '__main__':
_test()
SystemError: Parent module '' not loaded, cannot perform relative import
This means you are running a module inside the package as a script. Mixing scripts inside packages is tricky and should be avoided if at all possible. Use a wrapper script that imports the package and runs your scripty function instead.
If your top-level directory is called foo, which is on your PYTHONPATH module search path, and you have a package bar there (it is a directory you'd expect an __init__.py file in), scripts should not be placed inside bar, but should live on in foo at best.
Note that scripts differ from modules here in that they are used as a filename argument to the python command, either by using python <filename> or via a #! (shebang) line. It is loaded directly as the __main__ module (this is why if __name__ == "__main__": works in scripts), and there is no package context to build on for relative imports.
Your options
If you can, package your project with setuptools (or poetry or flit, which can help simplify packaging), and create console script entrypoints; installing your project with pip then creates scripts that know how to import your package properly. You can install your package locally with pip install -e ., so it can still be edited in-place.
Otherwise, never, ever, use python path/to/packagename/file.py, always use python path/to/script.py and script.py can use from packagename import ....
As a fallback, you could use the -m command-line switch to tell Python to import a module and use that as the __main__ file instead. This does not work with a shebang line, as there is no script file any more, however.
If you use python -m foo.bar and foo/bar.py is found in a sys.path directory, that is then imported and executed as __main__ with the right package context. If bar is also a package, inside foo/, it must have a __main__.py file (so foo/bar/__main__.py as the path from the sys.path directory).
In extreme circumstances, add the metadata Python uses to resolve relative imports by setting __package__ directly; the file foo/bar/spam.py, importable as foo.bar.spam, is given the global __package__ = "foo.bar". It is just another global, like __file__ and __name__, set by Python when imported.
On sys.path
The above all requires that your package can be imported, which means it needs to be found in one of the directories (or zipfiles) listed in sys.path. There are several options here too:
The directory where path/to/script.py was found (so path/to) is automatically added to sys.path. Executing python path/to/foo.py adds path/to to sys.path.
If you packaged your project (with setuptools, poetry, flit or another Python packaging tool), and installed it, the package has been added to the right place already.
As a last resort, add the right directory to sys.path yourself. If the package can be located relatively to the script file, use the __file__ variable in the script global namespace (e.g. using the pathlib.Path object, HERE = Path(__file__).resolve().parent is a reference to the directory the file lives in, as absolute path).
For PyCharm users:
I also was getting ImportError: attempted relative import with no known parent package because I was adding the . notation to silence a PyCharm parsing error. PyCharm innaccurately reports not being able to find:
lib.thing import function
If you change it to:
.lib.thing import function
it silences the error but then you get the aforementioned ImportError: attempted relative import with no known parent package. Just ignore PyCharm's parser. It's wrong and the code runs fine despite what it says.
To obviate this problem, I devised a solution with the repackage package, which has worked for me for some time. It adds the upper directory to the lib path:
import repackage
repackage.up()
from mypackage.mymodule import myfunction
Repackage can make relative imports that work in a wide range of cases, using an intelligent strategy (inspecting the call stack).
TL;DR: to #Aya's answer, updated with pathlib library, and working for Jupyter notebooks where __file__ is not defined:
You want to import my_function defined under ../my_Folder_where_the_package_lives/my_package.py
respect to where you are writing the code.
Then do:
import os
import sys
import pathlib
PACKAGE_PARENT = pathlib.Path(__file__).parent
#PACKAGE_PARENT = pathlib.Path.cwd().parent # if on jupyter notebook
SCRIPT_DIR = PACKAGE_PARENT / "my_Folder_where_the_package_lives"
sys.path.append(str(SCRIPT_DIR))
from my_package import my_function
Hopefully, this will be of value to someone out there - I went through half a dozen stackoverflow posts trying to figure out relative imports similar to whats posted above here. I set up everything as suggested but I was still hitting ModuleNotFoundError: No module named 'my_module_name'
Since I was just developing locally and playing around, I hadn't created/run a setup.py file. I also hadn't apparently set my PYTHONPATH.
I realized that when I ran my code as I had been when the tests were in the same directory as the module, I couldn't find my module:
$ python3 test/my_module/module_test.py 2.4.0
Traceback (most recent call last):
File "test/my_module/module_test.py", line 6, in <module>
from my_module.module import *
ModuleNotFoundError: No module named 'my_module'
However, when I explicitly specified the path things started to work:
$ PYTHONPATH=. python3 test/my_module/module_test.py 2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s
OK
So, in the event that anyone has tried a few suggestions, believes their code is structured correctly and still finds themselves in a similar situation as myself try either of the following if you don't export the current directory to your PYTHONPATH:
Run your code and explicitly include the path like so:
$ PYTHONPATH=. python3 test/my_module/module_test.py
To avoid calling PYTHONPATH=., create a setup.py file with contents like the following and run python setup.py development to add packages to the path:
# setup.py
from setuptools import setup, find_packages
setup(
name='sample',
packages=find_packages()
)
TL;DR
You can only relatively import modules inside another module in the same package.
Concept Clarify
We see a lot of example code in books/docs/articles, they show us how to relatively import a module, but when we do so, it fails.
The reason is, put it in a simple sentence, we did not run the code as the python module mechanism expects, even though the code is written totally right. It's like some kind of runtime thing.
Module loading is depended on how you run the code. That is the source of confusion.
What is a module?
A module is a python file when and only when it is being imported by another file. Given a file mod.py, is it a module? Yes and No, if you run python mod.py, it is not a module, because it is not imported.
What is a package?
A package is a folder that includes Python module(s).
BTW, __init__.py is not necessary from python 3.3, if you don't need any package initialization or auto-load submodules. You don't need to place a blank __init__.py in a directory.
That proves a package is just a folder as long as there are files being imported.
Real Answer
Now, this description becomes clearer.
You can only relatively import modules inside another module in the same package.
Given a directory:
. CWD
|-- happy_maker.py # content: print('Sends Happy')
`-- me.py # content: from . import happy_maker
Run python me.py, we got attempted relative import with no known parent package
me.py is run directly, it is not a module, and we can't use relative import in it.
Solution 1
Use import happy_maker instead of from . import happy_maker
Solution 2
Switch our working directory to the parent folder.
. CWD
|-- happy
| |-- happy_maker.py
`-- me.py
Run python -m happy.me.
When we are in the directory that includes happy, happy is a package, me.py, happy_maker.py are modules, we can use relative import now, and we still want to run me.py, so we use -m which means run the module as a script.
Python Idiom
. CWD
|-- happy
| |-- happy_maker.py # content: print('Sends Happy')
| `-- me.py # content: from . import happy_maker
`-- main.py # content: import happy.me
This structure is the python idiom. main is our script, best practice in Python. Finally, we got there.
Siblings or Grandparents
Another common need:
.
|-- happy
| |-- happy_maker.py
| `-- me.py
`-- sad
`-- sad_maker.py
We want to import sad_maker in me.py, How to do that?
First, we need to make happy and sad in the same package, so we have to go up a directory level. And then from ..sad import sad_maker in the me.py.
That is all.
My boilerplate to make a module with relative imports in a package runnable standalone.
package/module.py
## Standalone boilerplate before relative imports
if __package__ is None:
DIR = Path(__file__).resolve().parent
sys.path.insert(0, str(DIR.parent))
__package__ = DIR.name
from . import variable_in__init__py
from . import other_module_in_package
...
Now you can use your module in any fashion:
Run module as usual: python -m package.module
Use it as a module: python -c 'from package import module'
Run it standalone: python package/module.py
or with shebang (#!/bin/env python) just: package/module.py
NB! Using sys.path.append instead of sys.path.insert will give you a hard to trace error if your module has the same name as your package. E.g. my_script/my_script.py
Of course if you have relative imports from higher levels in your package hierarchy, than this is not enough, but for most cases, it's just okay.
I needed to run python3 from the main project directory to make it work.
For example, if the project has the following structure:
project_demo/
├── main.py
├── some_package/
│ ├── __init__.py
│ └── project_configs.py
└── test/
└── test_project_configs.py
Solution
I would run python3 inside folder project_demo/ and then perform a
from some_package import project_configs
I was getting this ImportError: attempted relative import with no known parent package
In my program I was using the file from current path for importing its function.
from .filename import function
Then I modified the current path (Dot) with package name. Which resolved my issue.
from package_name.filename import function
I hope the above answer helps you.
Importing from same directory
Firstly, you can import from the same directory.
Here is the file structure...
Folder
|
├─ Scripts
| ├─ module123.py
|
├─ main.py
├─ script123.py
Here is main.py
from . import script123
from Scripts import module123
As you can see, importing from . imports from current directory.
Note: if running using anything but IDLE, make sure that your terminal is navigated to the same directory as the main.py file before running.
Also, importing from a local folder also works.
Importing from parent directory
As seen in my GitHub gist here, there is the following method.
Take the following file tree...
ParentDirectory
├─ Folder
| |
| ├─ Scripts
| | ├─ module123.py
| |
| ├─ main.py
| ├─ script123.py
|
├─ parentModule.py
Then, just add this code to the top of your main.py file.
import inspect
import os
import sys
current_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parent_dir = os.path.dirname(current_dir)
sys.path.insert(0, parent_dir)
from ParentDirectory import Stuff
I tried all of the above to no avail, only to realize I mistakenly had a - in my package name.
In short, don't have - in the directory where __init__.py is. I've never felt elated after finding out such inanity.
if both packages are in your import path (sys.path), and the module/class you want is in example/example.py, then to access the class without relative import try:
from example.example import fkt
If none of the above worked for you, you can specify the module explicitly.
Directory:
├── Project
│ ├── Dir
│ │ ├── __init__.py
│ │ ├── module.py
│ │ └── standalone.py
Solution:
#in standalone.py
from Project.Dir.module import ...
module - the module to be imported
Here is a three-liner for those who disagree with Guido:
import sys
from pathlib import Path
sys.path.append(str(Path(sys.argv[0]).absolute().parent.parent))
Hope it helps.
I think the best solution is to create a package for your module:
Here is more info on how to do it.
Once you have a package you don't need to worry about relative import, you can just do absolute imports.
I encounter this a lot when I am working with Django, since a lot of functionality is performed from the manage.py script but I also want to have some of my modules runnable directly as scripts as well (ideally you would make them manage.py directives but we're not there yet).
This is a mock up of what such a project might look like;
├── dj_app
│ ├── models.py
│ ├── ops
│ │ ├── bar.py
│ │ └── foo.py
│ ├── script.py
│ ├── tests.py
│ ├── utils.py
│ └── views.py
└── manage.py
The important parts here being manage.py, dj_app/script.py, and dj_app/tests.py. We also have submodules dj_app/ops/bar.py and dj_app/ops/foo.py which contain more items we want to use throughout the project.
The source of the issue commonly comes from wanting your dj_app/script.py script methods to have test cases in dj_app/tests.py which get invoked when you run manage.py test.
This is how I set up the project and its imports;
# dj_app/ops/foo.py
# Foo operation methods and classes
foo_val = "foo123"
.
# dj_app/ops/bar.py
# Bar operations methods and classes
bar_val = "bar123"
.
# dj_app/script.py
# script to run app methods from CLI
# if run directly from command line
if __name__ == '__main__':
from ops.bar import bar_val
from ops.foo import foo_val
# otherwise
else:
from .ops.bar import bar_val
from .ops.foo import foo_val
def script_method1():
print("this is script_method1")
print("bar_val: {}".format(bar_val))
print("foo_val: {}".format(foo_val))
if __name__ == '__main__':
print("running from the script")
script_method1()
.
# dj_app/tests.py
# test cases for the app
# do not run this directly from CLI or the imports will break
from .script import script_method1
from .ops.bar import bar_val
from .ops.foo import foo_val
def main():
print("Running the test case")
print("testing script method")
script_method1()
if __name__ == '__main__':
print("running tests from command line")
main()
.
# manage.py
# just run the test cases for this example
import dj_app.tests
dj_app.tests.main()
.
Running the test cases from manage.py;
$ python3 manage.py
Running the test case
testing script method
this is script_method1
bar_val: bar123
foo_val: foo123
Running the script on its own;
$ python3 dj_app/script.py
running from the script
this is script_method1
bar_val: bar123
foo_val: foo123
Note that you get an error if you try to run the test.py directly however, so don't do that;
$ python3 dj_app/tests.py
Traceback (most recent call last):
File "dj_app/tests.py", line 5, in <module>
from .script import script_method1
ModuleNotFoundError: No module named '__main__.script'; '__main__' is not a package
If I run into more complicated situations for imports, I usually end up implementing something like this to hack through it;
import os
import sys
THIS_DIR = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, THIS_DIR)
from script import script_method1
sys.path.pop(0)
This my project structure
├── folder
| |
│ ├── moduleA.py
| | |
| | └--function1()
| | └~~ uses function2()
| |
│ └── moduleB.py
| |
| └--function2()
|
└── main.py
└~~ uses function1()
Here my moduleA imports moduleB and main imports moduleA
I added the snippet below in moduleA to import moduleB
try:
from .moduleB import function2
except:
from moduleB import function2
Now I can execute both main.py as well as moduleA.py individually
Is this a solution ?
The below solution is tested on Python3
├── classes
| |
| ├──__init__.py
| |
│ ├── userclass.py
| | |
| | └--viewDetails()
| |
| |
│ └── groupclass.py
| |
| └--viewGroupDetails()
|
└── start.py
└~~ uses function1()
Now, in order to use viewDetails of userclass or viewGroupDetails of groupclass define that in _ init _.py of classess directory first.
Ex: In _ init _.py
from .userclasss import viewDetails
from .groupclass import viewGroupDetails
Step2: Now, in start.py we can directly import viewDetails
Ex: In start.py
from classes import viewDetails
from classes import viewGroupDetails
I ran into a similar problem when trying to write a python file that can be loaded either as a module or an executable script.
Setup
/path/to/project/
├── __init__.py
└── main.py
└── mylib/
├── list_util.py
└── args_util.py
with:
main.py:
#!/usr/bin/env python3
import sys
import mylib.args_util
if __name__ == '__main__':
print(f'{mylib.args_util.parseargs(sys.argv[1:])=}')
mylib/list_util.py:
def to_int_list(args):
return [int(x) for x in args]
mylib/args_util.py:
#!/usr/bin/env python3
import sys
from . import list_util as lu
def parseargs(args):
return sum(lu.to_int_list(args))
if __name__ == '__main__':
print(f'{parseargs(sys.argv[1:])=}')
Output
$ ./main.py 1 2 3
mylib.args_util.parseargs(sys.argv[1:])=6
$ mylib/args_util.py 1 2 3
Traceback (most recent call last):
File "/path/to/project/mylib/args_util.py", line 10, in <module>
from . import list_util as lu
ImportError: attempted relative import with no known parent package
Solution
I settled for a Bash/Python polyglot solution. The Bash version of the program just calls python3 -m mylib.args_util then exits.
The Python version ignores the Bash code because it's contained in the docstring.
The Bash version ignores the Python code because it uses exec to stop parsing/running lines.
mylib/args_util.py:
#!/bin/bash
# -*- Mode: python -*-
''''true
exec /usr/bin/env python3 -m mylib.args_util "$#"
'''
import sys
from . import list_util as lu
def parseargs(args):
return sum(lu.to_int_list(args))
if __name__ == '__main__':
print(f'{parseargs(sys.argv[1:])=}')
Output
$ ./main.py 1 2 3
mylib.args_util.parseargs(sys.argv[1:])=6
$ mylib/args_util.py 1 2 3
parseargs(sys.argv[1:])=6
Explanation
Line 1: #!/bin/bash; this is the "shebang" line; it tells the interactive shell how run this script.
Python: ignored (comment)
Bash: ignored (comment)
Line 2: # -*- Mode: python -*- optional; this is called the "mode-line"; it tells Emacs to use Python syntax highlighting instead of guessing that the language is Bash when reading the file.
Python: ignored (comment)
Bash: ignored (comment)
Line 3: ''''true
Python: views this as an unassigned docstring starting with 'true\n
Bash: views this as three strings (of which the first two are empty strings) that expand to true (i.e. '' + '' + 'true' = 'true'); it then runs true (which does nothing) and continues to the next line
Line 4: exec /usr/bin/env python3 -m mylib.args_util "$#"
Python: still views this as part of the docstring from line 3.
Bash: runs python3 -m mylib.args_util then exits (it doesn't parse anything beyond this line)
Line 5: '''
Python: views this as the end of the docstring from line 3.
Bash: doesn't parse this line
Caveats
This doesn't work on Windows:
Workaround: Use WSL or a Batch wrapper script to call python -m mylib.args_util.
This only works if the current working directory is set to /path/to/project/.
Workaround: Set PYTHONPATH when calling /usr/bin/env
#!/bin/bash
# -*- Mode: python -*-
''''true
exec /usr/bin/env python3 \
PYTHONPATH="$(cd "$(dirname "$0")/.." ; pwd)" \
-m mylib.args_util "$#"
'''
I've created a new, experimental import library for Python: ultraimport
It gives the programmer more control over imports and makes them unambiguous. Also it gives better error messages when an import fails.
It allows you to do relative, file-system based imports that always work, no matter how you run your code and no matter what is your current working directory. It does not matter if you run a script or module. You also don't have to change sys.path which might have other side effects.
You would then change
from .mymodule import myfunction
to
import ultraimport
myfunction = ultraimport('__dir__/mymodule.py', 'myfunction')
This way the import will always work, even if you run the code as script.
One issue when importing scripts like this is that subsequent relative imports might fail. ultraimport has a builtin preprocessor to automatically rewrite relative imports.
I had a similar problem: I needed a Linux service and cgi plugin which use common constants to cooperate. The 'natural' way to do this is to place them in the init.py of the package, but I cannot start the cgi plugin with the -m parameter.
My final solution was similar to Solution #2 above:
import sys
import pathlib as p
import importlib
pp = p.Path(sys.argv[0])
pack = pp.resolve().parent
pkg = importlib.import_module('__init__', package=str(pack))
The disadvantage is that you must prefix the constants (or common functions) with pkg:
print(pkg.Glob)
TLDR; Append Script path to the System Path by adding following in the entry point of your python script.
import os.path
import sys
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
Thats it now you can run your project in PyCharma as well as from Terminal!!
Moving the file from which you are importing to an outside directory helps.
This is extra useful when your main file makes any other files in its own directory.
Ex:
Before:
Project
|---dir1
|-------main.py
|-------module1.py
After:
Project
|---module1.py
|---dir1
|-------main.py
I was getting the same error and my project structure was like
->project
->vendors
->vendors.py
->main.py
I was trying to call like this
from .vendors.Amazon import Amazom_Purchase
Here it was throwing an error so I fixed it simply by removing the first . from the statement
from vendors.Amazon import Amazom_Purchase
Hope this helps.
It's good to note that sometimes the cache causes of all it - I've tried different things after re-arranging classes into new directories and relative import started to work after I removed the __pycache__
If the following import:
from . import something
doesn't work for you it is because this is python-packaging import and will not work with your regular implementation, and here is an example to show how to use it:
Folder structure:
.
└── funniest
├── funniest
│ ├── __init__.py
│ └── text.py
├── main.py
└── setup.py
inside __init__.py add:
def available_module():
return "hello world"
text.py add:
from . import available_module
inside setup.py add
from setuptools import setup
setup(name='funniest',
version='0.1',
description='The funniest joke in the world',
url='http://github.com/storborg/funniest',
author='Flying Circus',
author_email='flyingcircus#example.com',
license='MIT',
packages=['funniest'],
zip_safe=False)
Now, this is the most important part you need to install your package:
pip install .
Anywhere else in our system using the same Python, we can do this now:
>> import funnies.text as fun
>> fun.available_module()
This should output 'hello world'
you can test this in main.py (this will not require any installation of the Package)
Here is main.py as well
import funniest.text as fun
print(fun.available_module())
Setup
test/
main.py
pkg/
a.py
__init__.py
main.py contains:
import pkg
pkg.a
__init__.py contains:
from . import a
main.py can be run without errors.
Question
Changing the content of __init__.py to
import a
gives the following error when running main.py:
Traceback (most recent call last):
File "C:/Users/me/PycharmProjects/test/main.py", line 1, in <module>
import pkg
File "C:\Users\me\PycharmProjects\test\pkg\__init__.py", line 1, in <module>
import a
ModuleNotFoundError: No module named 'a'
Interestingly, __init__.py can be executed directly with python __init__.py without errors.
What's going on?
When you run a python script, it's parent folder is added to sys.path
run main.py: sys.path[0] = '../test'
run init.py: sys.path[0] = '../test/pkg'
Your case: You try to "absolute-like" import a in __init__.py but the parent folder of a.py - which is '../test/pkg' - is not in the sys.path when you run main.py. This is why you get an error. However, your absolute import is incomplete as it should always start at the top level folder, e.g.
from test.pkg import a
Final answer to your question: You don't have to use relative imports!
See: PEP-8: Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path).
And keep in mind that relative imports don't work in a top-level-script when __name__ = "__main__", but from imported modules only.
You can learn more about absolute and relative imports here:
Absolute vs. explicit relative import of Python module
https://realpython.com/absolute-vs-relative-python-imports/
I suppose you are using Pycharm? Then that's one of the confusion cause.
For example, let's say your directory looks like this
project1
p1.py
test/
__init__.py
main.py
pkg/
a.py
__init__.py
If you run (F10) the main.py your default working directory will be project1/test, which does not contain the a.py so import a will not find anything.
But if you run (F10) the pkg/__init__.py your working directory will be project1/test/pkg which has the a.py, and it works like what you tested.
So in these situation, if you use from . import a it will look for the directory that file is, project1/test/pkg in this case, which will always work regardless your working directory.
I have a structure such has:
/mainfolder
file.py
//subfolder
test.py
I am trying to import file.py in test.py. for some reason I just can't.
I tried
from .file import *
returning :
Traceback (most recent call last):
ModuleNotFoundError: No module named '__main__.file'; '__main__' is not a package
also tried to add path to sys.path:
import sys
import os
sys.path.extend([os.getcwd()])
doesnt work either
Looks like you're running test.py with python test.py and as such the test module is being treated as a top level module.
You should first make your folders Python packages if they are not by adding __init__.py files:
/mainfolder
__init__.py
file.py
/subfolder
__init__.py
test.py
Then you can append the outer mainfolder to sys.path:
import sys
import os
sys.path.append(os.path.join(os.getcwd(), '..'))
After which from file import someobject without relative import works. Be wary of wild card imports.
See ModuleNotFoundError: What does it mean __main__ is not a package? and How to do relative imports in Python? for more on why your current approach does not work.
What IDE are you using? I am using Pycharm Community IDE with Python 3 and it works with from file import * or from file import some_function (I wanted to comment but I can't since I don't have 50 reputation yet)
I can't make this work..
My structure is:
program_name/
__init__.py
setup.py
src/
__init__.py
Process/
__init__.py
thefile.py
tests/
__init__.py
thetest.py
thetest.py:
from ..src.Process.thefile.py import sth
Running: pytest ./tests/thetest.py from program_name gives :
ValueError: attempted relative import beyond top-level package
I tried also other approaches but i am receiving various errors.
But I would expect for the above to work.
ValueError: Attempted relative import in non-package
States that you're trying to use relative import in the module, which are to be used for packages i.e. to make it a package add __init__.py and call the thetest.py from some file outside the package.
Directly running thetest.py from interpreter won't work.
Relative imports require that the module which uses them is being
imported itself either as package module.
Suggestion 1:
The current tests directory has a __init__.py file but that doesn't allow you to run it as a module (via shell) - to make your current (relative) import work, you need to import it in an external (to package) file/module - let's create a main.py (can name it anything you like):
main.py
program_name/
__init__.py
setup.py
src/
__init__.py
Process/
__init__.py
thefile.py
tests/
__init__.py
thetest.py
src/Process/thefile.py:
s = 'Hello world'
tests/thetest.py:
from ..src.Process.thefile import s
print s
main.py:
from program_name.tests.thetest import s
Executing main.py:
[nahmed#localhost ~]$ python main.py
Hello world
Suggestion 2:
Execute the file just above root dir i.e. one level up the program_name/ , in the following fashion:
[nahmed#localhost ~]$ python -m program_name.tests.thetest
Hell World
P.S. relative imports are for packages, not modules.
Just solved a similar problem with a lot of googling.
Here's two solutions without changing the existing file structor:
1
The way to import module from parent folder from ..src.Process.thefile.py import sth is called "relative import".
It's only supported when launching as a package from the top-level package. In your case, that is launching command line from the directory which contains program_name/ and type (for win environment)
python -m program_name.tests.thetest
or simply (useful for many pytest files):
python -m pytest
2
Otherwise -- when trying to run a script alone or from a non top-level package --
you could manually add directory to the PYTHONPATH at run time.
import sys
from os import path
sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
from src.Process.thefile import s
Try the first one first see if it's compatiable with the pytest framework. Otherwise the second one should always solve the problem.
Reference (How to fix "Attempted relative import in non-package" even with __init__.py)
When importing a file, Python only searches the current directory, the directory that the entry-point script is running from.
you can use sys.path to include different locations
import sys
sys.path.insert(0, '/path/to/application/app/folder')
import thefile