There are quite a few questions regarding python relative paths, but I have not found anything for the following situation:
src/
__init__.py
notebook.ipynb
A/
__init__.py
foo.py
B/
__init__.py
bar.py
I'm trying to import in notebook.ipynb:
from A.foo import Foo
which has a subdirectory/subpackage import to make:
foo.py
from ..B.bar import Bar
I'm getting a ValueError: Attempted relative import beyond toplevel package.
If I had only a few files, I would try to hack a solution using sys and os. However, I got quite a few in deeper directories and am looking for a more elegant way. Any ideas?
I saw that you said you are looking for a more elegant solution than using sys, however using sys gives a solution for this example.
foo.py:
import sys
sys.path.append('..')
from A.foo import foo
notebook.ipynb
import sys
sys.path.append('..')
from B.bar import Bar
Related
Let's consider very simple package with the following folder/file hierarchy:
package_tutorial (folder)
├── mypackage(folder)
└── file.py
└──__init__.py
I'm curious about possiblities to refer to this package from any location. I was searching for such and I found solution:
import sys
sys.path.insert(1, 'path/to/mypackage')
import mypackage as mp
But is there any solution that will not force to me specify path every time I run spyder ? i.e. If I want to import mypackage after restarting spyder I have to rehearse code:
import sys
sys.path.insert(1, 'path/to/mypackage')
import mypackage as mp
and it's not exactly convenient for me. Preferably I want to have just
import mypackage as mp
Is there any possibility to do such from any location ?
Read the value of sys.path (will return a list of directories) and make sure to place your package in one of those directories so it will be in the path by default.
I have a project which is structured as below:
/project
/src
__init__.py
my_module.py
/notebooks
my_notebook.ipynb
I wanted to import my_module.py in my_notebook.ipynb, so I first tried import src.my_module getting ModuleNotFoundError: No module named 'src' and from ..src import my_module getting ImportError: attempted relative import with no known parent package. From several similar topics I found that adding /project location to SYSPATH would be a quick hack and it works indeed:
import sys
sys.path.insert(1, '/project')
from src import my_module
However, interfering with SYSPATH seems to be a nasty way and I wonder - does a safer/cleaner solution exists. Also, I don't quite get why from ..src import my_module doesn't work in the first place?
Let's say I have the following directory structure:
parent_dir/
foo_dir/
foo.py
bar_dir/
bar.py
If I wanted to import bar.py from within foo.py, how would I do that?
If all occurring directories are Python packages, i.e. they all contain __init__.py, then you can use
from ..bar_dir import bar
If the directories aren't Python packages, you can do this by messing around with sys.path, but you shouldn't.
You can use the sys and os modules for generalized imports. In foo.py start with the lines
import sys
import os
sys.path.append(os.path.abspath('../bar_dir'))
import bar
Let's say if you have following structure:
root
|_ productconst.py
|_ products
|_ __init__.py
And if you would like to import productconst in products.__init__, then following can be used :
from ..productconst import *
If you're having issues in python 3+, the following worked for me using sys.path.append("..").
sys.path.append("..")
from bar_dir import bar
I have a project like:
project/
foo/
other.py
bar/
baz.py
If I code something like:
import sys
sys.path.insert(0, '../foo')
from foo import other
It doesn't work. But if I move foo into the bar directory it works. I realize this is bad code style, but how is this relative path searched and where does the documentation define it?
from foo import other will append foo to each of the directories in sys.path. So it's looking for ../foo/foo/other.py, but the actual path is just ../foo/other.py.
You should just insert .. into sys.path, then it will look for ../foo/other.py. Or if you only want to include that directory in the path, just use import other, without from foo.
Assuming you are in the baz directory, you need to include your parent directory .. in the path. Then when you do from foo, the foo directory in your parent directory is found.
This works:
import sys
sys.path.insert(0, '..')
from foo import other
Read more:
Stackoverflow Answer
The Definitive Guide to Python import Statements
Alternatively, since you included ../foo in the path, you could simply do import other, like so:
import sys
sys.path.insert(0, '..\foo')
import other
I have a code with following structure:
mainDir/
/foo/ __init__.py
/foo/foo.py (i am importing bar here)
/__init__.py
/bar.py
Now, foo.py has an import like
from ..bar import *
And inside mainDir I am trying to run: python -m foo.foo. But I am getting:
ValueError: Attempted relative import beyond toplevel package in foo.py for trying to import bar
I am not looking for sys.path solutions but rather creating modules? Any suggestions?
Use an absolute import:
from bar import * # though you shouldn't be using import * anyway
Relative imports have to stay within a package. You can't step out of the package heirarchy entirely and import a top-level module with a relative import.