Relative imports for the trillionth time - python

I have the following data structure:
project/
folder_a/
file.py
folder_b/
useful_functions.py
I am running my file.py and attempting to import a set of functions I have written within useful_functions.py.
At first I tried the following:
from ..folder_b.useful_functions import function_a
But got the following error:
ValueError: attempted relative import beyond top-level package
I then removed the two dots at the beginning of the import statement which initially worked. I have since revisited this project with no changes and I am faced with a new error message. The following code:
from folder_b.useful_functions import function_a
Gives me the following error message:
ModuleNotFoundError: No module named 'folder_b'
I find it very strange that one time it works and later with no changes the import fails. I really would like to solve this with relative imports as I would like the code to work other machines with different absolute file paths.
Thanks in advance.

Well for the trillionth time running a script directly inside a package is considered an antipattern. I do not know how spyder runs stuff but presumably does
python file.py # from inside folder_a
This should be changed to
python -m folder_a.file # from inside project
This would resolve relative imports among packages inside project folder alright and will not need any sys.path or PYTHONPATH hacks

Related

cannot import submodule from a module [duplicate]

This question already has answers here:
Attempted relative import with no known parent package [duplicate]
(4 answers)
Closed 1 year ago.
I am having following structure for my project
Object_Detection/
setup.py
setup.cfg
requirement.txt
object_detection/
models
__init__.py #contains from . import models
tests/
# inside tests dir
test_utils_image.py
__init__.py #empty
utils/
# inside utils dir
__init__.py #inside
utils_image_preprocess.py
utils_image.py
utils_tfrecord.py
Now init.py inside utils directory contains the following code.
# inside __init__.py
from . import utils_image_preprocess
from . import utils_image
from . import utils_tfrecord
Running above init.py files gives me an error:
ImportError: attempted relative import with no known parent package
test_utils.py inside tests dir contains the following code
# inside test_utils.py
from object_detection.utils import utils_image
While running test_utils.py I got the following error
ImportError: cannot import name 'utils_image' from 'object_detection.utils'
I have gone through this and this and tried to follow every aspect mentioned there but details about what to put inside init.py is not clear.
This problem seems to be associated with the structuring of init.py in different dir.
I have gone through various and got to know that if we keep even an empty init.py file then things will work out but I am not sure about my understanding.
Please let me know
what I am missing here and whether I am following the correct structure for packaging my code or not?
How to resolve these two errors?
Is this issue related to setting up source in IDE as I am using Vscode and I have also seen this has been mentioned at many places. See here? (But also tried the same code with PyCharm and encountered same error )
If you want to be able to say ...
from object_detection.utils import utils_image
... then clearly the utils directory must be a subdirectory of the object_detection directory and not a sibling directory, i.e. at the same level.
Now for your other error:
ImportError: attempted relative import with no known parent package
You did not really specify under what circumstances you get this error other than saying "Running above init.py files gives me an error:". But how are you "running" these py files or what does that even mean?
If you are executing a script when this occurs (how else would you be getting this error?), the script must be invoked as a module (because scripts cannot have relative imports -- see below) as follows (we will assume that the script you are trying to execute is test_utils_image.py):
First, the parent directory of object_detection, which is Object_Detection, must be in the system path of directories to be searched for finding modules and packages referenced in import statements. In general, this can be accomplished several ways, for instance
The script you are executing is in Object_Detection (the directory of the script is automatically added to the sys.path list of directories to be searched by the interpreter).
Dynamically appending Object_Detection to the sys.path list of directories at runtime by your script.
Appending Object_Detection to the PYTHONPATH environment variable.
Item 1 above would not be applicable for this specific case since the module we are executing by definition is not in the Object_Detection directory.
Note that if your classes will eventually be installed with pip, then site-packages will be the parent directory of object_detection, which is already in sys.path.
Then you can execute your script as:
python -m tests.test_utils_image
If you want to execute this .py file as a script, for example by right-mouse clicking on it is VS Code, then see Relative imports for the billionth time, in particular the section Scripts can't import relative, which says it all -- it cannot work!
To invoke this as a script, just convert the relative imports to absolute imports. In fact, the PEP 8 Style Guide says:
Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path):
Have you tried to do the following?
inside your utils __init__.py import your modules as follows:
from .utils_image_preprocess import <func1>... <rest of functions/classes you want to import>
from .utils_image import <func1>... <rest of functions/classes you want to import>
from .utils_tfrecord import <func1>... <rest of functions/classes you want to import>
And then in your test file do:
from object_detection.utils.utils_image import *
OR
from object_detection.utils.utils_image import <func1>,...
Also, make sure you don't have any circular dependencies in your modules. for example importing of function from your tests to your util module and vise versa
Python3 has two types of packages
Regular Packages
Namespace Packages
Regular packages contains init.py and namespace packages don't need to have init.py
Regarding your folder structure, it is correct, no change needed. You just need to import like this
from utils import utils_image
without mentioning the objects_detection as objects_detection is just a namespace package.
So it would be usefull when you would refer to the utils module from outside the objects_detection folder.
Here what python docs say about the namespace packages:
A namespace package is a composite of various portions, where each portion contributes a subpackage to the parent package.

Working around "ModuleNotFoundError: ...'__main__' is not a package" error

I've got a project running on a server with the structure
proj
__init__.py
module_a.py
module_b.py
main.py
And in the header of main.py, I import from other modules with the format
from .module_a import func1
from .module_b import func2
This runs fine on the server, but when I'm testing things on my local machine it raises the error:
ModuleNotFoundError: No module named '__main__.module_a'; '__main__' is not a package
There have been a lot of questions asked regarding this error and the accepted solution is almost always to replace the import statement with
from proj.module_a import func1
Is there something I can do to configure my local environment to allow this type of syntax without having a completely different set of import statements depending on whether the code is running locally or remotely?
Keep your imports relative, without using the package full path, so that you have the flexibility of renaming it as you wish, like in
from .module_a import func1
Then in your local environment, change your current dir to the proj parent folder and run:
python -m proj.main
An alternative would be to rename main.py to __main__.py and then just writing
python -m proj
will do. But that may affect the behaviour on the server if you copy the files as is.
Packages are usually to be imported. This is a common problem when we start running from arbitrary scripts located inside the package (in this case main.py). If the package is simply imported from outside, everything works.

How do I find details of this python package (__main__)? [duplicate]

Currently trying to work in Python3 and use absolute imports to import one module into another but I get the error ModuleNotFoundError: No module named '__main__.moduleB'; '__main__' is not a package. Consider this project structure:
proj
__init__.py3 (empty)
moduleA.py3
moduleB.py3
moduleA.py3
from .moduleB import ModuleB
ModuleB.hello()
moduleB.py3
class ModuleB:
def hello():
print("hello world")
Then running python3 moduleA.py3 gives the error. What needs to be changed here?
.moduleB is a relative import. Relative only works when the parent module is imported or loaded first. That means you need to have proj imported somewhere in your current runtime environment. When you are are using command python3 moduleA.py3, it is getting no chance to import parent module. You can:
from proj.moduleB import moduleB OR
You can create another script, let's say run.py, to invoke from proj import moduleA
Good luck with your journey to the awesome land of Python.
Foreword
I'm developing a project which in fact is a Python package that can be installed through pip, but it also exposes a command line interface. I don't have problems running my project after installing it with pip install ., but hey, who does this every time after changing something in one of the project files? I needed to run the whole thing through simple python mypackage/main.py.
/my-project
- README.md
- setup.py
/mypackage
- __init__.py
- main.py
- common.py
The different faces of the same problem
I tried importing a few functions in main.py from my common.py module. I tried different configurations that gave different errors, and I want to share with you with my observations and leave a quick note for future me as well.
Relative import
The first what I tried was a relative import:
from .common import my_func
I ran my application with simple: python mypackage/main.py. Unfortunately this gave the following error:
ModuleNotFoundError: No module named '__main__.common'; '__main__' is not a package
The cause of this problem is that the main.py was executed directly by python command, thus becoming the main module named __main__. If we connect this information with the relative import we used, we get what we have in the error message: __main__.common. This is explained in the Python documentation:
Note that relative imports are based on the name of the current module. Since the name of the main module is always __main__, modules intended for use as the main module of a Python application must always use absolute imports.
When I installed my package with pip install . and then ran it, it worked perfectly fine. I was also able to import mypackage.main module in a Python console. So it looks like there's a problem only with running it directly.
Absolute import
Let's follow the advise from the documentation and change the import statement to something different:
from common import my_func
If we now try to run this as before: python mypackage/main.py, then it works as expected! But, there's a caveat when you, like me, develop something that need to work as a standalone command line tool after installing it with pip. I installed my package with pip install . and then tried to run it...
ModuleNotFoundError: No module named 'common'
What's worse, when I opened a Python console, and tried to import the main module manually (import mypackage.main), then I got the same error as above. The reason for that is simple: common is no longer a relative import, so Python tries to find it in installed packages. We don't have such package, that's why it fails.
The solution with an absolute import works well only when you create a typical Python app that is executed with a python command.
Import with a package name
There is also a third possibility to import the common module:
from mypackage.common import my_func
This is not very different from the relative import approach, as long as we do it from the context of mypackage. And again, trying to run this with python mypackage/main.py ends similar:
ModuleNotFoundError: No module named 'mypackage'
How irritating that could be, the interpreter is right, you don't have such package installed.
The solution
For simple Python apps
Just use absolute imports (without the dot), and everything will be fine.
For installable Python apps in development
Use relative imports, or imports with a package name on the beginning, because you need them like this when your app is installed. When it comes to running such module in development, Python can be executed with the -m option:
-m mod : run library module as a script (terminates option list)
So instead of python mypackage/main.py, do it like this: python -m mypackage.main.
In addition to md-sabuj-sarker's answer, there is a really good example in the Python modules documentation.
This is what the docs say about intra-package-references:
Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.
If you run python3 moduleA.py3, moduleA is used as the main module, so using the absolute import looks like the right thing to do.
However, beware that this absolute import (from package.module import something) fails if, for some reason, the package contains a module file with the same name as the package (at least, on my Python 3.7). So, for example, it would fail if you have (using the OP's example):
proj/
__init__.py (empty)
proj.py (same name as package)
moduleA.py
moduleB.py
in which case you would get:
ModuleNotFoundError: No module named 'proj.moduleB'; 'proj' is not a package
Alternatively, you could remove the . in from .moduleB import, as suggested here and here, which seems to work, although my PyCharm (2018.2.4) marks this as an "Unresolved reference" and fails to autocomplete.
Maybe you can do this before importing the moduleļ¼š
moduleA.py3
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from moduleB import ModuleB
ModuleB.hello()
Add the current directory to the environment directory
Just rename the file from where you run the app to main.py:
from app import app
if __name__ == '__main__':
app.run()
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
will solve the issue of import path issue.

Python Import From Module

I know this question has been asked many times in the similiar fashion but I want to understand the import mechanism of Python in the simplest example.
Suppose I have the following directory structure:
.\Project\moduleOne.py
.\Project\moduleTwo.py
Basically I import a function from moduleTwo while being in moduleOne:
from moduleTwo import myFunction
Everything works as intended, I can use myFunction. However, if I change the import statement, like below:
from .moduleTwo import MyFunction
I receive the following error:
ValueError: Attempted relative import in non-package
Even if I have a __init__.py file to make a project directory a package I still receive the same error.
Any help would be really appreciated. Thanks!
I imagine that the current directory when you do this is .\Project, and that you are running
python3 moduleOne.py
You are therefore importing moduleTwo as an independent module rather than as a submodule of a package.
If you were, for example, to ascend the directory hierarchy so that your current directory is the Project directory's parent, and execute
python3 -m Project.moduleOne
you will find that the relative import from .moduleTwo executes perfectly well.

__init__ file doesn't work as expected in python

I have some folders and .py files in the following structure:
parent/
__init__.py
test.ipynb
code/
__init__.py
common.py
subcode/
__init__.py
get_data.py
In the __init__ file under the parent folder, I have import code and in the one of code, I have import subcode. But when I tried import code.subcode, I got such an error:
ImportError: No module named 'code.subcode'; 'code' is not a package
But when I just import code, no error is thrown. However, when I call code.subcode, this error happens:
AttributeError: module 'code' has no attribute 'subcode'
I try all of those mentioned above in the test.ipynb, which is at the root of the directory.
Do you know what is the reason and how can I fix it? Thanks!
The problem is that you are importing another module named code that is installed on your system rather than your own module. You can verify this by checking the module file path in code.__file__ after you import code.
The first thing to do is change the name of your module to avoid namespace collisions with the other code package on your system. If your new package name doesn't collide with something else, you should now either successfully be importing it and have it behave as expected, or it fails to import entirely.
If it fails to import, it is most likely because your parent directory is not in your PYTHONPATH environment variable.
There can potentially also be other more technical reasons that a module is not recognized by the interpreter such as old definitions being cached (in which case restarting the interpreter is often enough. Possibly after deleting any precompiled versions of the module). Another problem I have seen ended up being that a module contained a bug that made the interpreter unable to parse it. I am sure there are other odd possibilities out there.
You're on Python 3. You need to perform relative imports explicitly:
from . import code
The code module you're currently getting is the standard library code module.

Categories