Reputation: 326
My folder structure is as follows
./fff
├── __init__.py
├── fg
│ ├── __init__.py
│ └── settings
│ ├── __init__.py
│ └── settings.py
└── obng
└── test.py
I want to import the settings.py inside fg/settings as a module into the test.py
I have added the line
from ..fg.settings import settings
But when I run it, it gives me the following error
Traceback (most recent call last): File "/mnt/d/Repos/fff/obng/test.py", line 1, in from ..fg.settings import settings ImportError: attempted relative import with no known parent package
This style of relative importing is supported as per https://docs.python.org/3/reference/import.html#package-relative-imports
What am I doing wrong here?
Upvotes: 4
Views: 13228
Reputation: 139
In Linux, you could create a symbolic link:
$ ln -s ../folder1 mymodules
$ python
>>> import mymodules.myfancymodule as fancy
Upvotes: 0
Reputation: 16476
Normally you can't use relative imports when you run your python module as main module like python filename.py
but there is a hack using __package__
to achieve this. Remember __package__
is how python resolves relative imports:
1- Create a file called __init__.py
in your root directory - fff
. ( I can see that you have it, I mentioned for completeness)
2- Put this code on top of your test.py
module:
if __name__ == '__main__' and not __package__:
import sys
sys.path.insert(0, <path to parent directory of root directory - fff>)
__package__ = 'fff.obng'
Note: sys.path
is where python searches for modules to import them.
3- Now place your relative import statement after the code above (inside the if statement, because we don't wanna mess when your test.py
is being imported) :
from ..fg.settings import settings
Now you can call you test.py
, it will run without problem. I don't recommend using these hacks but showing the flexibility of the language and doing exactly what you wanna do in some cases is beneficial.
Other good solutions: Absolute import I think is easier and cleaner than this. In addition take a look at @Mr_and_Mrs_D's answer another good solution would be to run your module with -m
command-line flag.
Upvotes: 6
Reputation: 34016
It is a matter of how you run your project - you should run from the parent directory of the top-level package as in
$ cd ../fff
$ python -m fff.obng.test # note no py
Then relative imports will be resolved correctly. It is an antipattern running a script directly from its folder
Upvotes: 7
Reputation: 700
Relative imports are based on the name of the current module. When running
python fff/obng/test.py
the name of test.py will be __main__
and the import will not work.
What will work is having another script called "test.py" outside the fff module that imports the fff.obng.test
fff_top
├── fff
│ ├── fg
│ │ ├── __init__.py
│ │ └── settings
│ │ ├── __init__.py
│ │ └── settings.py
│ ├── __init__.py
│ └── obng
│ ├── __init__.py
│ └── test.py
└── test.py
with fff_top/test.py:
import fff.obng.test
Then, running the "external" test.py should be ok:
python fft_top/test.py
Alternatively, I would recommend dropping relative imports entirely. One way to do this is using a virtual environment for every package you write, using for example the venv library:
python -m venv venv
Then, add a setup.py in the root folder with the content:
from setuptools import setup, find_packages
setup(name="fff", packages=find_packages())
and change the imports in obng/test.py
:
from fff.fg.settings import settings
Finally, activate your virtual environment:
source venv/bin/activate
and install your package in editable mode:
pip install -e .
Then, after you have completed all the steps above:
python fff/obng/test.py
should work.
Upvotes: 1