How does one use absolute imports from a module of a sibling package?
Package file structure:
.
├── a
│ ├── __init__.py
│ └── modulea.py
├── b
│ ├── __init__.py
│ ├── moduleb.py
├── __init__.py
└── test.py
Files test.py and a/modulea.py:
from b.moduleb import f
if __name__ == '__main__':
f()
File b/moduleb.py:
def f():
print('hello')
This works:
% python test.py
hello
This does not:
% python a/modulea.py
Traceback (most recent call last):
File "a/modulea.py", line 1, in <module>
from b.moduleb import f
ImportError: No module named 'b'
As far as I can tell from the documentation it should work: http://docs.python.org/3.3/tutorial/modules.html#intra-package-references. Am I missing something?
You need an __init__.py in whatever . is.
Use python -ma.modulea.
Running python a/modulea.py adds a directory to sys.path instead of the parent (.).
Don't run scripts from inside Python packages directly. See Traps for the Unwary.
Related
I am setting up a sample python package using the "Package Relative Imports" syntax, referring to this document. And it is not working, the Relative Imports in b.py ran into problems. Here are my file structure (all __init.py__ are empty)
lib/
dir1/
__init.py__
a.py
dir2/
__init.py__
b.py
__init.py__
c.py
File a.py
def a_foo(a, b):
return a + b
File b.py
from ..dir1.a import a_foo
def b_bar():
return a_foo(1,2)
File c.py
from dir2.b import b_bar
print(b_bar())
I ran c.py and got the following error
PS D:\tmp\py> python c.py
Traceback (most recent call last):
File "D:\tmp\py\c.py", line 1, in <module>
from dir2.b import b_bar
File "D:\tmp\py\dir2\b.py", line 1, in <module>
from ..dir1.a import a_foo
ImportError: attempted relative import beyond top-level package
I think I structured everything according to the document. Not sure why the relative import is not working. I have a Python 3.9.7 running in Windows 10.
I think your from dir2.b is being interpreted as an absolute import, not relative. The docs you refer to say:
Try:
from .dir2.b import b_bar
Note the preceding period. It means look in the current directory for "dir2"
Then call it using
python -c "import lib.c"
To get a simple idea Lets look at the directory tree again
lib
├── c.py
├── dir1
│ ├── a.py
│ └── __init__.py
├── dir2
│ ├── b.py
│ └── __init__.py
└── __init__.py
Important things
In this tree, the top most __init__.py file is in the root directory.
All other subfolders with python scripts are included __init__.py
OK, Here comes the point. When you are trying to do relative import with .. it tries to import from lib.dir1.a, But there is no __init__.py at the same level with lib folder. That's why you get ImportError: attempted relative import beyond top-level package error. Because of python package importer doesn't identify lib folder as the top level package.
When you are trying to relative import with . , you checks dir2.dir1.a , which doesn't exit. Sow it will give you ModuleNotFoundError: No module named 'dir2.dir1' error
OK lets check whether it's true or not. lets add new folder dir3 within dir1 and d.py,e.py and __init__.py inside it
Here is the NEW directory tree
lib
├── c.py
├── dir1
│ ├── a.py
│ ├── dir3
│ │ ├── d.py
│ │ ├── e.py
│ │ └── __init__.py
│ └── __init__.py
├── dir2
│ ├── b.py
│ └── __init__.py
└── __init__.py
And here are the NEW file contents
a.py
def a_foo(a, b):
return a + b
b.py
from dir1.a import a_foo
def b_bar():
return a_foo(1,2)
e.py
def e_foo(a, b):
return a + b
d.py
from ..a import a_foo
from .e import e_foo
def d_bar():
return a_foo(1,2)
def d_foo():
return e_foo(1,2)
.. , Which tries to import from dir1.a, which exists and also which is accessible.
. , Which tries to import from dir3.e, which exists and also which is accessible.
c.py
from dir2.b import b_bar
from dir1.dir3.d import d_bar,d_foo
print("b_bar:", b_bar())
print("d_bar:", d_bar())
print("d_foo:", d_foo())
Now lets run c.py. The result is
b_bar: 3
d_bar: 3
d_foo: 3
Which indicates our relative import has been successful inside d.py.
OK then. I think this will solve your problem. We can use relative import in files which are in depth from the root-package. But when they are too close (within one or two levels), it's impossible.
Actually we can use . to import from python scripts in same level but not when the script is in the top most directory.
My Directory structure:
├── common
│ ├── common.py
│ └── __init__.py
├── project1
│ ├── __init__.py
│ └── scripts
│ ├── example_import.py
│ └── __init__.py
└── project2
├── __init__.py
└── scripts
└── __init__.py
I need to import common/common.py module in project1/scripts/example_import.py file
example_import.py:
import sys
sys.path.append("../common")
from common import Test
print("Module Not import error")
Error:
Traceback (most recent call last):
File "project1/scripts/example_import.py", line 3, in <module>
from common import Test
ImportError: No module named common
How to fix a issue?
Understanding how Python imports work is tricky in the beginning but makes sense once you understand how.
There are different way to fix your import issue. I would not recommend messing up with sys.path. Depending on where you are calling your script, you have multiple choice at hand.
Your Directory structure.
├── common
│ ├── common.py
│ └── __init__.py
├── project1
│ ├── __init__.py
│ └── scripts
│ ├── example_import.py
│ └── __init__.py
└── project2
├── __init__.py
└── scripts
└── __init__.py
On the root of directory
python project1/scripts/example_import.py
Will work, assuming that the imports in example_import.py looks like
from common.common import Test
If you want to use from common import Test, you need to add from common.common import Test in __init__.py file in common folder.
You can also use PYTHONPATH environment variable to tell Python where to look for the base module.
PYTHONPATH=/pathto/basefolder python folder/filesx.py
Another way is to create a setup.py on base and do development installation python -m pip install --editable . on environment you are working on.
Example of setup.py
#!/usr/bin/env python
from distutils.core import setup
setup(name='projectX',
version='1.0',
description='The World is not Enoug',
author='James Bond',
author_email='agent#007.net',
url='https://www.python.org/sigs/distutils-sig/',
packages=['common', 'project1', 'project2],
)
See Python Documentation for more setup.py options.
Python 3.6
I've written some components and I'm trying to import one of them in the other.
Below is what my project structure looks like:
.
└── components
├── __init__.py
├── extract
│ └── python3
| ├── __init__.py
│ └── extract.py
└── transform
└── python3
├── __init__.py
└── preprocess.py
extract.py
from components.transform.python3.preprocess import my_function
if __name__ == '__main__':
my_function()
preprocess.py
def my_function():
print("Found me")
When I run python components/extract/python3/extract.py
I see the following error:
ModuleNotFoundError: No module named 'components'
I've added an empty __init__.py file to the directories that contain modules as well as the top level package directory.
Ok, imports require the top level package to be available in Python PATH (sys.path).
So to make it work, you should:
cd to the directory containing components
add . to the Python PATH:
export PYTHONPATH='.'
launch your script:
python components/extract/python3/extract.py
On my system, it successfully displays:
Found me
I have the following structure for my Python modules:
.
├── a
│ ├── __init__.py
│ ├── aa.py
│ └── b
│ ├── __init__.py
│ └── bb.py
└── root.py
Contents of aa.py
from b.bb import hello_bb
def hello_aa():
hello_bb()
print("hello from aa.py")
Contents of bb.py
def hello_bb():
print("hello from bb.py")
Contents of root.py
from a.aa import hello_aa
hello_aa()
With Python 3.5.1, executing python root.py gives the following error:
Traceback (most recent call last):
File "root.py", line 1, in <module>
from a.aa import hello_aa
File ".../a/aa.py", line 1, in <module>
from b.bb import hello_bb
ImportError: No module named 'b'
Both the __init__.py are empty.
Anything else I am missing to make this work?
Use relative import inside a package (see PEP 328)
aa.py
from .b.bb import hello_bb
root.py
from .a.aa import hello_aa
In the aa.py file you must import hello_bb like so:
from .b.bb import hello_bb
def hello_aa():
hello_bb()
print("hello from aa.py")
I am importing a package foo1.foo2, whose __init__.py is importing a submodule foo1.foo2.foo3.bar1, which is a file. If I try to import foo1.foo2.foo3.bar2 inside that file I get the following error:
AttributeError: module 'foo1' has no attribute 'foo2'
Given that the use of relative imports is discouraged, how can I solve this issue without using relative imports?
Here is the package structure and file contents that I have:
/
├── foo1
│ ├── __init__.py:
│ └── foo2
│ ├── __init__.py: "import foo1.foo2.foo3.bar1"
│ └── foo3
│ ├── __init__.py
│ ├── bar1.py: "import foo1.foo2.foo3.bar2 as bar2"
│ └── bar2.py:
└── main.py: "import foo1.foo2"
Running python main.py generates the following error:
Traceback (most recent call last):
File "main.py", line 1, in <module>
import foo1.foo2
File "/foo1/foo2/__init__.py", line 1, in <module>
import foo1.foo2.foo3.bar1
File "/foo1/foo2/foo3/bar1.py", line 1, in <module>
import foo1.foo2.foo3.bar2 as bar2
AttributeError: module 'foo1' has no attribute 'foo2
I'm using Python 3.6.0 :: Anaconda 4.3.1.
Thanks!
Change import foo1.foo2.foo3.bar2 as bar2 into from foo1.foo2.foo3 import bar2.
Then it works.