cannot import submodule from a module [duplicate] - python

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.

Related

New module in Python

I've tried to create a new module in Python. It's git link : https://github.com/Sanmitha-Sadhishkumar/strman
After uploading and installing that using pip, I found that I could access that module as
import strman.strman as s
s.func_name
What are the changes to be made to access that as
import strman
strman.func_name
In your __init__.py file, you want to use a relative import.
from .strman import *
You have a strman package (the outer directory) and within it a strman module (the strman.py file). That's a perfectly common pattern. But without the relative import your __init__.py wasn't importing from deep enough in the hierarchy.
More generally, whenever you import from a sibling module within a project, you almost always should use a relative import, because it's explicit and avoids various complications, such as the example in your case.
You have to move the files into the main directory. Your directory will look like this
\myProject
- init.py
- strman.py
- main.py # <-- this would be the file your programming is
Read more about modules in the docs

Why does importing modules result in a circular import error

I have this for the layout of my project:
projectFolder /
setup/
__init__.py
setup.py
Utils /
__init__.py
cloudmanager.py
startup.py
I am trying to import the Setup Module inside my cloudmanager.py script (which is nested in one more directory). I can easily import both the setup module and the Utils module inside my startup.py script since it's in the root directory.
I've tried (inside my cloudmanager.py script):
from . import setup
Which gives me the error of:
ImportError: cannot import name 'setup' from partially initialized module 'Utils' (most likely due to a circular import)
and I've tried:
from .. import setup
Which gives me the error of:
ValueError: attempted relative import beyond top-level package
Any help? There are questions like this out there but they steer towards to using OS, which I'd like to avoid...
Okay, so the reason you're getting an error importing .. setup is indeed that you can't do relative imports when the parent directory is a package. A package is any directory with a __init__.py file in it.
You could solve this by doing one of two things:
You could make sure the root of your project is in the Python path and import everything in the root.
You could make your project's root directory itself a package and then use relative imports.
Option 1: Importing from the project root
If your projectFolder folder lives at /home/you/projects/projectFolder, make sure your PYTHONPATH has /home/you/projects/projectFolder in it. For example, when you run your main script, you could set it before hand. In bash (assuming a Unix environment):
export PYTHONPATH=/home/you/projects/projectFolder
python /home/you/projects/projectFolder/startup.py
You could also do that inside startup.py, if you want to avoid changing the external environment:
# startup.py
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__)))
If you do that in startup.py, the directory of startup.py will always be in the Python path.
Once you one of those, you can base all your imports on the relative location of your project. Eg:
import setup.setup
import Utils.cloudmanager
(That will work in every file you import after the sys.path mutation runs)
Option 2: Relative imports
If you make your project's root a Python package, you can use relative imports entirely. Eg, you'd have these files:
projectFolder/__init__.py
projectFOlder/setup/__init__.py
projectFolder/setup/setup.py
projectFolder/Utils/__init__.py
projectFolder/Utils/cloudmanager.py
If you do that, inside cloudmanager.py, you could run from .. import setup just fine.
What do you do?
Both of these are valid options. In general relative imports have less ambiguity, since they avoid name collisions, but they're a newer feature of Python so option #1 is more common, in general.
Try to use:
import setup.setup

python import from sibling folder

I am trying to import a module from a python file that is in a sibling folder. I read several similar questions here and tried to apply solutions listed there, but I wasn't able to solve the problem.
The structure is as follows:
parentfolder/gfolder/codefolder/fileA.py
parentfolder/gfolder/utilfolder/util.py
gfolder, codefolder and utilfolder all have an __init__.py.
I'm trying to do in fileA.py:
import gfolder.utilfolder.util as util
I also tried adding before the import statement:
sys.path.append(".../parentfolder/")
And that didn't work either:
import gfolder.utilfolder.util as util
ModuleNotFoundError: No module named 'gfolder'
The solution in a similar question says to include __init.py__ in the directories, which I already have.
EDIT:
Now both sys.append and sys.insert work and the problem was that I included a slash at the end of the path. When I took it out, everything worked.
First of all, let me describe you the differences between a Python module & a Python package so that both of us are on the same page. โœŒ
A module is a single .py file (or files) that are imported under one import and used. โœ”
import aModuleName
# Here 'aModuleName' is just a regular .py file.
Whereas, a package is a collection of modules in directories that give a package hierarchy. A package contains a distinct __init__.py file. โœ”
from aPackageName import aModuleName
# Here 'aPackageName` is a folder with a `__init__.py` file
# and 'aModuleName', which is just a regular .py file.
Therefore, when we have a project directory named proj-dir of the following structure โคต
proj-dir
--|--__init__.py
--package1
--|--__init__.py
--|--module1.py
--package2
--|--__init__.py
--|--module2.py
๐Ÿ”Ž Notice that I've also added an empty __init__.py into the proj-dir itself which makes it a package too.
๐Ÿ‘ Now, if you want to import any python object from module2 of package2 into module1 of package1, then the import statement in the file module1.py would be
from proj-dir.package2.module2 import object2
# if you were to import the entire module2 then,
from proj-dir.package2 import module2
I hope this simple explanation clarifies your doubts on Python imports' mechanism. ๐Ÿ˜Š
As Andrew Cox answerd int the following thread Import a module from a relative path
You can add the subdirectory to your Python path so that it imports as a normal script
import sys
sys.path.insert(0, <path to gfolder>)
import gfolder
you can also add the directory to the PATH var of the Linux system (I use it while I'm working on a project, at the end i modified the PATH to it's origin value)
if you maintain the following structre than it is working out side the box
parentfolder/gfolder/codefolder/fileA.py
parentfolder/gfolder/utilfolder/util.py
parentfolder/gfolder/main.py
run main.py

Importing from a git sub-module (ImportError)

I get an ImportError when I am importing from a sub-module in the way I thought One Was Supposed To Do It.
I have the following package:
pkg/
__init__.py
cow.py
pizza.py
pkg.py
components/
components.py
otherstuff.py
__init__.py
cow.py:
print "Hello"
from components import foodle
components.py:
foodle=5
and the __init__'s are empty.
I am having trouble putting things in the right place or organizing them properly. When, from the pkg directory, I try
from pkg import foodle
I get "ImportError: cannot import name foodle"
What is the right way to arrange files and import from submodules? I have read How to import python file from git submodule ; I have tried messing with sys.path in components/__init__.py and in cow.py, to no avail.
This package is shared on git, so it needs to be portable. components is actually a git sub-module.
Putting from components import * in the __init__py in components/ seems to work, but I thought usually that file stays empty.
The elements I was missing are (these are my interpretation, may still be incorrect):
If it's a package (with __init__.py), use it from outside the pkg folder, not from inside. ie, using a package both ways (calling from outside and using modules from within) might be hard to set up, so don't. This is the main insight that solves my problem.
the dot notation for getting submodules and subpackages works both for files and for folders within pkg. Thus, from some other folder, but with pkg in my path, I can call any of the following:
import pkg
from pkg.cow import foodle
from pkg.components import foodle
from pkg.components.components import foodle

Python: Importing from module that is executed

I am creating module (with submodules). Lets call it lib. I am trying to make it work as following:
I am able to run it (there is lib.__main__). It uses lib.utils inside.
When executed part of its job is to load other file/module passed by user. Currently it does it by importlib.import_module( name ).
This loaded module also needs to use lib.utils.
I am having following choice:
In loaded module use import utils instead of import lib.utils. I find it somehow misleading and would like to aviod this.
Run module in any external way, even using file with only import lib.__main__ inside.
Only other thing I have tought of was doing sys.path.append(os.getcwd()). Not only it seems very dirty, but also makes log.utils module to load twice.
Is there anything that would allow me to execute lib.__main__, but require using import lib.utils in loaded module?
From the docs
If the script name refers to a directory or zipfile, the script name is added to the start of sys.path and the main.py file in that location is executed as the main module.
In your case, if you run python lib mymodule, lib is added to sys.path and __main__.py is executed. lib is not a package, its simply a directory in sys.path. __main__.py is not in a package and so package-relative imports don't work.
Since lib is in sys.path, its top level .py files can be imported directly and any subdirectories with __init__.py are importable packages. So, both __main__.py and mymodule could do import utils and get the same thing.
Now it gets confusing. Because you are sitting in lib's parent directory and because there is a lib.__init__.py, lib.utils is also valid. Its only that way because of your current directory (or maybe you added the directory to PYTHONPATH or something). So, you've got two different modules as far as python is concerned because you got there on two different paths.
The solution is to delete lib/__init__.py. lib shouldn't be package. Then you have the question of what to do with the modules like lib/utils.py. Normally, one would create a package directory and move the scripts there so that you get namespace encapsulation. Supposing you call that directory mypackages, then __main__.py and mymodule.py could both import mypackages.utils.

Categories