Python gives relative import error for package? [duplicate] - python

This question already has answers here:
Relative imports for the billionth time
(12 answers)
Closed 2 years ago.
I can't for the life of me get python's relative imports to work. I have created a simple example of where it does not function:
The directory structure is:
__init__.py
start.py
parent.py
sub/
__init__.py
relative.py
/start.py contains just: import sub.relative
/sub/relative.py contains just from .. import parent
All other files are blank.
When executing the following on the command line:
$ cd /
$ python start.py
I get:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: Attempted relative import beyond toplevel package
I am using Python 2.6. Why is this the case? How do I make this sandbox example work?

You are importing from package "sub". start.py is not itself in a package even if there is a __init__.py present.
You would need to start your program from one directory over parent.py:
./start.py
./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py
With start.py:
import pkg.sub.relative
Now pkg is the top level package and your relative import should work.
If you want to stick with your current layout you can just use import parent. Because you use start.py to launch your interpreter, the directory where start.py is located is in your python path. parent.py lives there as a separate module.
You can also safely delete the top level __init__.py, if you don't import anything into a script further up the directory tree.

If you are going to call relative.py directly and i.e. if you really want to import from a top level module you have to explicitly add it to the sys.path list.
Here is how it should work:
# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')
# Now you can do imports from one directory top cause it is in the sys.path
import parent
# And even like this:
from parent import Parent
If you think the above can cause some kind of inconsistency you can use this instead:
sys.path.append(sys.path[0] + "/..")
sys.path[0] refers to the path that the entry point was ran from.

Checking it out in python3:
python -V
Python 3.6.5
Example1:
.
├── parent.py
├── start.py
└── sub
└── relative.py
- start.py
import sub.relative
- parent.py
print('Hello from parent.py')
- sub/relative.py
from .. import parent
If we run it like this(just to make sure PYTHONPATH is empty):
PYTHONPATH='' python3 start.py
Output:
Traceback (most recent call last):
File "start.py", line 1, in <module>
import sub.relative
File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
If we change import in sub/relative.py
- sub/relative.py
import parent
If we run it like this:
PYTHONPATH='' python3 start.py
Output:
Hello from parent.py
Example2:
.
├── parent.py
└── sub
├── relative.py
└── start.py
- parent.py
print('Hello from parent.py')
- sub/relative.py
print('Hello from relative.py')
- sub/start.py
import relative
from .. import parent
Run it like:
PYTHONPATH='' python3 sub/start.py
Output:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 2, in <module>
from .. import parent
ValueError: attempted relative import beyond top-level package
If we change import in sub/start.py:
- sub/start.py
import relative
import parent
Run it like:
PYTHONPATH='' python3 sub/start.py
Output:
Hello from relative.py
Traceback (most recent call last):
File "sub/start.py", line 3, in <module>
import parent
ModuleNotFoundError: No module named 'parent'
Run it like:
PYTHONPATH='.' python3 sub/start.py
Output:
Hello from relative.py
Hello from parent.py
Also it's better to use import from root folder, i.e.:
- sub/start.py
import sub.relative
import parent
Run it like:
PYTHONPATH='.' python3 sub/start.py
Output:
Hello from relative.py
Hello from parent.py

Related

Python modules import problem: import statement in different location

Here's my folder structure:
main.py
tools/
sub1.py
sub2.py
where main.py:
import tools.sub1
import tools.sub2
and sub1.py:
a = 'abc'
and sub2.py (directly import sub1 is not working, is it because I am running main.py from the root directory?):
import tools.sub1
print(tools.sub1)
from here, I knew that in order to correctly call sub1, sub2 from main, we have to add the statement import tools.sub1 in sub2, however, if I want to run sub2 individually, error occurs
Traceback (most recent call last):
File "sub2.py", line 1, in <module>
import tools.sub1 as sub1
ModuleNotFoundError: No module named 'tools'
So, My question is that is it possible to directly run sub2 individually, while keeping the current design that we can properly run main.py?. Thanks in advance.
You can run sub2 using python -m tools.sub2
More info on using -m https://docs.python.org/3/using/cmdline.html#cmdoption-m
You can do this by making tools a python module. Adding an __init__.py file (can be empty) in your tools directory will make Python consider the "tools" folder a module. You can then reference sub1 from both main.py and sub2.py with:
from tools import sub1

Python imports with __init__.py in a sibling directory

My directory structure looks like this:
- scripts
- script.py
- app
- foo
- connect.py
- bar
- __init__.py
- random.py
The __init__.py file in bar/ looks like
from bar.random import Random
__all__ = [ "Random" ]
and connect.py has an import
from bar import Random
I'm trying to execute script.py from the root directory via python scripts/script.py which is attempting to import from foo.py
from os import getcwd
from sys import path
path.append(getcwd())
from app.foo.connect import Connect
and getting:
Traceback (most recent call last):
File "scripts/script.py", line 19, in <module>
from app.foo.connect import Connect
File "/home/user/project/app/foo/connect.py", line 17, in <module>
from bar import Random
ModuleNotFoundError: No module named 'bar'
When running the app through its main, everything works. But when trying to execute a specific script attempting to import from a subdirectory in app/ I get the traceback.
What am I doing wrong?
The correct import of Random in connect.py is from app.bar.random import Random.
Also include __init__.py file in the app folder and connect folder.
You also do not need the __all__ statement in the one __init__.py file you have. All the __init__.py files can be left blank.

Pycharm cannot import module from Parent folder name

I have project defined in below way:
project/
__init__.py
dog.py
cat.py
In my dog.py, I'm calling:
import project.cat
which gives me this error:
ModuleNotFoundError: No module named 'project'
However, I have setup PYTHONPATH to the parent of project directory, which if I run dog.py outside of Pycharm (for example on the command line) it works well without exceptions.
Now even if I added project folder as Source Root, Pycharm still labels my import statement as wrong (red color) and also doesn't allow me to run it inside Pycharm for dog.py program. This is so confusing. Can anyone help?
*PS: I don't want to use relative imports in dog.py like 'from .cat import *' because I have if name == main statement in dog.py, which python doesn't allow me to run the relative imports inside dog.py.
===============
Adding more information:
I noticed if I made the src folder under project to make the structure like:
project/
__init__.py
src/
__init__.py
dog.py
cat.py
then I can call this in dog.py:
import src.cat
But this way, I am still troubling myself because when I run program in Pycharm, I have to use this way:
import src.cat
when I run program in ipython notebook, I have to import like:
import project.src.cat
This cause me constantly switch my code when I have to run in different places.
=====================
If I simply do this in dog.py
import cat
It will work in Pycharm. But when I call in command line, it's going wrong there now:
In [10]: import project.dog
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-10-be5ebc05b4b0> in <module>
----> 1 import project.dog
~/PycharmProjects/project/dog.py in <module>
2 import pandas as pd
3 import numpy as np
----> 4 import cat
5 from datetime import datetime
6
ModuleNotFoundError: No module named 'cat'
Issue resolved by making my parent folder of my project as the root folder and make root as Source Root.
parent-folder\
project\
__init__.py
dog.py
cat.py
Now it works well on both command line and Pycharm by simply adding one line in .bashrc:
export PYTHONPATH=$PYTHONPATH:~/project

Understanding module & absolute / relative package imports

I have created a package containing sub-folders and I would like to include a parent module from a sub-package module.
I have tried to follow the project structure suggested here https://docs.python-guide.org/writing/structure/ and attempted to replicate the step-by-step procedure as listed here http://zetcode.com/lang/python/packages/ but it seems that I am missing something obvious about python's package system
Here's my project structure
watches/
-- ...
-- watches/
---- __init__.py (empty)
---- Logger.py
---- main.py
---- db/
------ __init__.py (empty)
------ EntryPoint.py
Logger.py contains a single class :
class Logger:
...
I try to import Logger.py's class and methods from db/EntryPoint.py as follow :
from watches.Logger import Logger
class EntryPoint:
...
Then, I want to wrap-up everything in main.py as follow:
from db.EntryPoint import EntryPoint
if __name__ == "__main__":
t = EntryPoint("local")
and finally, when I try to execute main.py as follow python3 main.py (so I am located in watches/watches directory as you can guess), I guet the following error stack trace :
Traceback (most recent call last):
File "main.py", line 1, in <module>
from db.EntryPoint import EntryPoint
File "some/absolute/path/watches/watches/db/EntryPoint.py", line 4, in <module>
from watches.Logger import Logger
ModuleNotFoundError: No module named 'watches'
Every import will be relative to the location where the script is being run, in your case, main.py.
So, the point of view of your program is:
-logger.py
-__init__.py
-db/
---__init__.pt
---EntryPoint.py
The program is not aware that he is an module called watches, so if you want to import the logger.py in your main, simply do:
from Logger import Logger
Or move your main to the parent folder.

Import from different directories in python

This is my folder structure:
src/
__init__py
Lowlevel/
__init__.py
ModuleToCheck.Py
Test/
__init__.py
ModuleToCheck_test.py
(__init__.py are empty files)
Now I want to import ModuleToCheck.py in ModuleToCheck_test.py
How am I able to do this without appending anything to sys.path?
Update:
from ..Lowlevel import ModuleToCheck leads to:
src$ python Test/ModuleToCheck_test.py
Traceback (most recent call last):
File "Test/ModuleToCheck_test.py", line 6, in <module>
from ..Lowlevel import ModuleToCheck
ValueError: Attempted relative import in non-package
The following is from http://docs.python.org/tutorial/modules.html#intra-package-references
Note that both explicit and implicit
relative imports are based on the name
of the current module. Since the name
of the main module is always
"__main__", modules intended for use
as the main module of a Python
application should always use absolute
imports.
You're running your module ModuleToCheck_test.py as the main module, hence the exception.
One solution is to create a test.py module in your src directory containing the following:
import Test.ModuleToCheck_test
You can then run that module using python test.py

Categories

Resources