Python Subpackages - Absolute Import Failure - python

This question has been asked in different contexts, but I still am unable to get a successful absolute import.
I have this directory structure
21:48:07$ tree
start_dir
└── top_package
├── README.md
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-37.pyc
│   └── secrets.cpython-37.pyc
├── subpackage1
│   ├── __init__.py
│   └── test.py
├── requirements.txt
├── secrets.py
└── subpackage2
    └── __init__.py
All I want to be able to do is from test.py be able to import from secrets. Here is the contents of test.py:
# import top_package # ImportError: No module named top_package
# from top_package import secrets # ImportError: No module named top_package
import top_package.secrets # ImportError: No module named top_package
None of these have worked. I've read through multiple pages on having multiple subpackages in a top level package but still no dice.
Is this simply because I'm trying to execute the file directly by running python test.py instead of calling this from start_dir? If so, what's the best way to develop and work around this?
Goal: I want to be able to absolute import secrets from test.py. If possible, I do not want to do anything with the site-packages or with the setup.py. I want to be able to run python test.py and have the line: import top_package not give a ImportError no module found. Please advise the best course of action.

So you created top_package and want to import it anywhere within your system. You can do so by copying the package folder to the site-packages folder of your environment. This is a path where python would look while importing packages.

Related

How to run Python files in example folder?

I am creating a Python package and want to make the example files in the example folder runnable with something like python example_file.py. How do I do it? My example_file.py and __init__.py look like below:
# example_file.py
from demandforecast import DemandForecast # module coded in demandforecast.py
if __name__ == '__main__':
# Example code here
# __init__.py
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
When I navigate to the examples directory and run python example_file.py I get the following error:
Exception has occurred: ModuleNotFoundError
No module named 'demandforecast'
This can be solved by adding using the old sys.path.insert() trick mentioned in Importing files from different folder, but I would rather not include the absolute path because this will vary from user to user.
Here is my directory structure:
├───demandforecast
│ demandforecast.py
│ __init__.py
│
└───examples
example_file.py
I have tried a few posts here, such as Relative imports in Python 3, but without luck. Adding sys.path.append('../') to the example file before the demandforecast import also did not work.
I think your import is simply incorrect, and should be:
from demandforecast.demandforecast import DemandForecast
Since demandforecast is both the package name (the directory is definitely a package, with the __init__.py file) and a module name within that package. (I assume DemandForecast is a class within the demandforecast module.)
from src.pro.demandforecast.demandforecast import foo
if __name__ == '__main__':
foo()
output:
foo
create a folder src and inside of it create a package pro and now inside pro create two packages demandforecast and examples.
Directory structure:
/src$ tree
.
└── pro
├── demandforecast
│   ├── demandforecast.py
│   ├── __init__.py
│   └── __pycache__
│   ├── demandforecast.cpython-38.pyc
│   └── __init__.cpython-38.pyc
├── examples
│   ├── example_file.py
│   └── __init__.py
├── __init__.py
└── __pycache__
└── __init__.cpython-38.pyc
IDE:

relative import in python 3.9.5

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?
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
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.
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.
In Linux, you could create a symbolic link:
$ ln -s ../folder1 mymodules
$ python
>>> import mymodules.myfancymodule as fancy

ModuleNotFoundError python : No module named 'project.utils'

└── Project
├── __init__.py
├── main.py
├── utils.py
└── auth
├── __init__.py
└── users.py
In my users.py file, I want to import data from project/utils.py, but when I am running imports it says module not found.
/users.py
from project.utils import data #have tried
from .. import utils #have tried
it will be great if anyone can tell me how do I make my project globally available so I can import stuff directly from it.

What 'Attempted relative import beyond top-level package' error means in Python?

I'm using python 3.7 and ran into a relative import error "Attempted relative import beyond top-level package" with the following folder structure:
├── app
│   ├── __init__.py
│   ├── services
│   │   └── item_service.py
│   └── views
│   ├── home.py
│   ├── __init__.py
My goal: import variable foo from the top level _init_.py to item_service.py using
from .. import foo
Pylint gives the error when trying this.
However the same exact import statement works in home.py, and if I add a empty _init_.py file to the services folder, the import works.
So my my question is, why? Does python require your module to be in a subpackage in order to relatively import parent package's contents?
For me it got resolved in following ways:
First import the directory (import dir)
Then try to import the views/class (from dir import views/class)
To solve:
Add init.py to all directories involved.
Add
sys.path.append("..")
BEFORE importing from sibling directory.

Import python project modules from tests subdirectory

├── ledger
│   ├── __init__.py
│   ├── ledger_data.py
│   └── ledger_model.py
├── main.py
├── sscommon
│   ├── __init__.py
│   └── logging.py
└── tests
└── test_ledger_data.py
I need to import classes from ledger_data module when running test_ledger_data.py. I currently do sys.path.append("../") in test_ledger_data.py or I have to add symbolik links to all modules being used to tests directory. Both options seem incorrect. How to do it correctly?
If I just run the file either from project root or tests directories I get error:
from ledger.ledger_data import LedgerData
ImportError: No module named 'ledger'
You can create an __init__.py file in your folder, and import the parent dir using:
parent_dir = os.path.abspath(os.path.join(os.path.abspath(__file__), os.pardir))
sys.append(parent_dir)
This uses os.path to find out the directory based on your file location.
Update: create the above __init__.py and reside it inside tests/ folder.
Then, in your test_ledge_data.py put at the head of the file from __init__ import *; this will import everything in your init file to your module namespace.

Categories

Resources