How to manage relative imports in python? - python

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.

Related

Python, absolute/relative import not working as expected

I apologize for the millionth post about this topic.
I thought I had a good grip of the whole absolute/relative import mechanism - I even replied to a couple of questions about it myself - but I'm having a problem with it and I can't figure out how to solve it.
I'm using Python 3.8.0, this is my directory structure:
project_folder
scripts/
main.py
models/
__init__.py
subfolder00/
subfolder01/
some_script.py --> contains def for some_function
I need to import some_function from some_script.py when running main.py, so I tried:
1) relative import
# in main.py
from ..models.subfolder00.subfolder01.somescript import some_function
but when I run (from the scripts/ folder)
python main.py
this fails with error:
ImportError: attempted relative import with no known parent package
This was expected, because I'm running main.py directly as a script, so its _name_ is set to _main_ and relative imports are bound to fail.
However, I was expecting it to work when running (always from within the scripts folder):
python -m main
but I'm getting always the same error.
2) absolute import
I tried changing the import in main.py to:
# in main.py
from models.subfolder00.subfolder01.somescript import some_function
and running, this time from the main project folder:
python scripts/main.py
so that - I was assuming - the starting point for the absolute import would be the project folder itself, from which it could get to models/....
But now I'm getting the error:
ModuleNotFoundError: No module named 'models'
Why didn't it work when using the -m option in the case of relative import, and it's not working when using absolute ones either? Which is the correct way to do this?
I think quite likely you missed python's official doc ( that even come offline )
https://docs.python.org/3/tutorial/modules.html
you'll need a dummy __init__.py within your module, at same level of some_script.py
I think your "absolute" import may not have been absolute in the truest sense.
Prior to running the python scripts/main.py command, you would have needed to setup PYTHONPATH environment variable to include the path to project_folder.
Alternatively I do something like this in main.py:
import sys
import os
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','models','subfolder00','subfolder01'))
from somescript import some_function
Maybe it is a little pedantic, but it makes sense to me.

How to import relative module from __main__ in python

I have two file
foo.py
main.py
while executing python main.py, I want main.py to import foo.py.
I tried
from . import foo
But python complains
Attempted relative import beyond top-level package
I also tried
from foo import func_name
It works, but that means I can only directly import what get exposed. I want to use it like foo.func_name
Is it possible to import the whole module in a relative way (regardless what the current working directory is)?
The script directory is already a part of the import path. Simply use
import foo

How to Correctly Import Python Modules and Avoid Import Errors

I have a custom python module I'm working on and am confused how I should import modules into other modules. I want to use bits and pieces of some modules within others and keep getting an error: ImportError: cannot import name NameOfModule
I'm assuming there's some sort of circular reference that's causing the issue but I'm not sure if I need to add something to __init__.py, or if there's a specific way of importing the modules into each other, or if I should change my folder structure?
If I want to be able to use some function from mod1.py within mod2.py how should I go about setting up the import statements?
My current folder structure is:
FolderName
-__init__.py
-mod1.py
-mod2.py
-mod3.py
-mod4.py
Sample code:
__init__.py is empty
mod1.py: from . import mod2
mod2.py: from . import mod1
You should be using relative imports for files within the current module, like so:
from . import mod2
Or:
from .mod2 import foo
And unless you have a VERY good reason, you should be using Python 3.

dot_module and dot_dot_module when import module

I see many people use the following import methods in their projects:
from .module1 import a,b
from ..module2 import *
The module1 and module2 are a .py file but not a folder for package. What's the differences to the import module? Does it mean to import the module in current and ../ folder? But when I try to import another file in same folder, it said:
import .other
>>> SyntaxError: Invalid syntax
from .other import *
>>> ValueError: Attempted relative import in non-package
I'm curious on it. Thanks~
What you see is relative imports. They allow you to import modules by specifying their relative paths, without hard-coding the name of the package in which the modules are defined.
Does it mean to import the module in current and ../ folder?
Yes.
See PEP 328 for more details. Note it says:
Relative imports must always use from <> import; import <> is always
absolute.
which is why you get the SyntaxError when trying import .foo.
The ValueError is probably because you are running the importing file as a script (and it used to confuse me a lot). You need to run it as a package (using the -m switch) for relative imports to work. That is, suppose foo.py relative-imports other modules, you can't run it by
$ python foo.py # non-package error
Instead you do
$ python -m foo
See the related question: How to do relative imports in Python.

python packaging for relative imports

First off all: I'm sorry, I know there has been lots of question about relative imports, but I just didn't find a solution. If possible I would like to use the following directory layout:
myClass/
__init__.py
test/
demo.py
benchmark.py
specs.py
src/
__init__.py
myClass.py
Now my questions are:
How do the test files from within the package properly import myClass.py?
How would you import the package from outside, assuming you take myClass as submodule in libs/myClass or include/myClass?
So far I couldn't find an elegant solution for this. From what I understand Guido's Decision it should be possible to do from ..src import myClass but this will error:
ValueError: Attempted relative import in non-package
Which looks as it doesn't treat myClass as packages. Reading the docs:
The __init__.py files are required to make Python treat the directories as containing packages;
It seems I'm missing something that specifies where the scripts of the package are, should I use .pth ?
ValueError: Attempted relative import in non-package
Means you attempt to use relative import in the module which is not package. Its problem with the file which has this from ... import statement, and not the file which you are trying to import.
So if you are doing relative imports in your tests, for example, you should make your tests to be part of your package. This means
Adding __init__.py to test/
Running them from some outside script, like nosetests
If you run something as python myClass/test/demo.py, relative imports will not work too since you are running demo module not as package. Relative imports require that the module which uses them is being imported itself either as package module, from myClass.test.demo import blabla, or with relative import.
After hours of searching last night I found the answer to relative imports in python!! Or an easy solution at the very least. The best way to fix this is to have the modules called from another module. So say you want demo.py to import myClass.py. In the myClass folder at the root of the sub-packages they need to have a file that calls the other two. From what I gather the working directory is always considered __main__ so if you test the import from demo.py with the demo.py script, you will receive that error. To illustrate:
Folder hierarchy:
myClass/
main.py #arbitrary name, can be anything
test/
__init__.py
demo.py
src/
__init__.py
myClass.py
myClass.py:
def randomMaths(x):
a = x * 2
y = x * a
return y
demo.py:
from ..src import myClass
def printer():
print(myClass.randomMaths(42))
main.py:
import test.demo
demo.printer()
If you run demo.py in the interpreter, you will generate an error, but running main.py will not. It's a little convoluted, but it works :D
Intra-package-references describes how to myClass from test/*. To import the package from outside, you should add its path to PYTHONPATH environment variable before running the importer application, or to sys.path list in the code before importing it.
Why from ..src import myClass fails: probably, src is not a python package, you cannot import from there. You should add it to python path as described above.

Categories