Context
Let's say I have the following module:
.
└── my_module
├── __init__.py
├── my_module_A.py (defines ClassA)
└── my_module_B.py (defines ClassB, which needs ClassA)
and the files are the following:
# __init__.py
from .my_module_A import ClassA
from .my_module_B import ClassB
# my_module_A.py
from my_module import ClassB
class ClassA:
def __init__(self, class_b: ClassB):
pass
# my_module_B.py
class ClassB:
def __init__(self):
pass
The important thing is that ClassB requires an instance of ClassA to be
instantiated.
Problem
Importing the module my_module raises an ImportError:
>>> # Working directory is the parent of my_module
>>> import my_module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "foo/Module/my_module/__init__.py", line 3, in <module>
from .my_module_A import ClassA
File "foo/Module/my_module/my_module_A.py", line 3, in <module>
from my_module import ClassB
ImportError: cannot import name 'ClassB' from partially initialized module 'my_module' (most likely due to a circular import) (foo/Module/my_module/__init__.py)
The problem seems to be the following. When importing my_module, Python goes
through its __init__.py and starts by importing ClassA from my_module_A.
This file imports itself ClassB from my_module_B so this class is imported
for my_module as well. After my_module_A, Python tries to import ClassB
from my_module ; but it was already imported by my_module_A, so Python
raises ImportError.
Python suggests that the error may come from a circular import, but this is not
the case here. I really think that the problem is that the class ClassB is
imported twice: if I do not import my_module_B in __init__.py and use a
relative import for my_module_B in my_module_A, the import is successful
and there is no exception raised.
Finding a solution
A possible solution is to use only relative imports in python files in
my_module. The problem is that some submodules in my_module required
themselves a lot of classes from my_module (about 20 for some of them) and it
is ugly and inconvenient for maintainers having to know precise file names
where classes are defined. So my question is: how can I keep using from my_modyle import … imports in my_module submodules? Thanks a lot.
P.S. Some of you may suggest to rethink my module organization. I thought of
that but there is no canonical way to do it and this flat structure is truly
easier and clearer. So if possible I would like to avoid this.
Python version: 3.9.1
The source of the problem is ClassB hasn't yet been loaded into my_module (in __init__.py) when my_module_A is being imported (this is hinted by the "partially initialized" bit in the error message).
You'll need to manually order the imports in __init__.py so that dependencies come before the modules that use them:
# __init__.py
from .my_module_B import ClassB
from .my_module_A import ClassA # uses ClassB
A more robust solution is to skip __init__.py and import directly from my_module_B, but as you say, this gets unwieldy with lots of modules.
# my_module_A.py
# relative imports also work here
from my_module.my_module_B import ClassB
class ClassA:
def __init__(self, class_b: ClassB):
pass
Related
I read all the other SO posts about this and it either doesn't work or uses sys.path.append.
Below is a replica of the official documentation:
All other files not shown are empty
moduleA.py
from ..subB.moduleB import MyClass
moduleB.py
class MyClass:
def __init__(self):
pass
package/subB/__init__.py
from .moduleB import MyClass
Traceback from running moduleA.py
Traceback (most recent call last):
File "path\to\my\projects\folder\package\subA\moduleA.py", line 1, in <module>
from ..subB.moduleB import MyClass
ImportError: attempted relative import with no known parent package
File Structure
The Python docs unfortunately forget to mention that their example only works if you run your code in a very specific way using the '-m' switch. So you would have to do python -m subA.moduleA and you need to ensure that your current working directory is package. Otherwise it will fail.
If you don't like these restrictions (like me), I've created an experimental import library: ultraimport
It gives you more control over your imports and lets you do file system based imports.
In moduleA.py you could then write:
import ultraimport
MyClass = ultraimport('__dir__/../subB/moduleB.py', 'MyClass')
This will always work, no matter how you run your code or what is your current working directory. Also no need to change sys.path. It will actually go to the file system and load the very file you've specified.
I am developing a Django project and I am trying to run a test file but an error in the import occurre.
My folder hierarchy to be like the image:
see the image of function process_data inside of core.py
I am in the test directory trying to run my test file.
My import to be like the code:
from coordenadas.core import process_data
but, when I run my code an error is showed:
Traceback (most recent call last):
File "tests_class_moviment.py", line 1, in <module>
from coordenadas.core import process_data
ModuleNotFoundError: No module named 'coordenadas'
I am tryed use relative import
from .coordenadas.core import process_data
from .core import process_data
from ..coordenadas.core import process_data
from ..core import process_data
but the only way that no error is showed in pycharm is the
from coordenadas.core import process_data
Some idea how can I solve it?
On a partially unrelated note, absolute imports are definitely recommended over relative imports. PEP8:
Relative imports for intra-package imports are highly discouraged. Always use the absolute package path for all imports. Even now that PEP 328 [7] is fully implemented in Python 2.5, its style of explicit relative imports is actively discouraged; absolute imports are more portable and usually more readable.
As for the module error itself, adding an __init__.py file to the "coordenadas" directory will turn it into a module, which is exactly what you need.
The file structure for a module im creating goes as follows:
PIV
| __init__.py
| base.py
| core.py
| exceptions.py
.gitignore
LICENSE
requirements.txt
But whenever I run a file like core.py, I get the following error:
Traceback (most recent call last):
File "c:/Users/ghub4/OneDrive/Desktop/Python-Image-and-Video-tools/PIV/core.py", line 33, in <module>
from . import base
ImportError: attempted relative import with no known parent package
The same thing happens when I run the __init__.py file. I'm not sure on what went wrong because all of the python files are in the same folder. Can someone clarify what's the problem and explain how I should fix it?
Import code for core.py file:
from __future__ import absolute_import
import sys
import os
from PIL import Image
import io
from . import base
from . import exceptions
(The __init__.py folder has the same relative imports as in the core file but also including: from . import core)
Based upon the two links you will given below, here is what needed for the problem to solve:
Relative Imports error rectified
No module named base
You need to import the package as this
from mymodule import some_useful_method
Sometimes, we get the no module error, in this case, we can import like this
from module_name.classname import some_useful_method
I have a folder
/
alphabet/
__init__.py
a.py
b.py
...
main.py
The modules in alphabet/ have to be unknown to me, and I want to access them when importing from main.py, so this is what alphabet/__init__.py looks like
from os import listdir, path
onlyfiles = [f for f in listdir('alphabet') if path.isfile(path.join("alphabet", f))]
__all__ = [f[:-3] for f in onlyfiles if f != '__init__.py' and f[-2:] == "py"]
And that how main.py calls them
import alphabet
modules = [l for l in alphabet.__all__]
print(modules)
["a", "b", ...]
Now I want to run a function named sound() from a.py
for m in modules:
alphabet.m.sound()
But it gives this error AttributeError: module 'alphabet' has no attribute 'm'
There are so many things wrong with this it's difficult to begin. You can reference the following to begin debugging your application:
In your for loop, you cannot use the variable m in a dotted notation, as the interpreter will try to access the literal m module and not the variable name. A valid way to try that would be to call alphabet.__all__[m].sound(). But it won't actually work since you never imported that part of the code. The correct way is to use the importlib module and load submodules on the fly, something like
import importlib
module = importlib.import_module('alphabet.a')
How you build the function attribute for import_module is up to you.
Furthermore putting the submodule names in __all__ only exposes them to the importer (or hides them) and doesn't actually import them at runtime. You have to use import * from alphabet to import all the submodules in __all__.
I would strongly recommend you research package development for python and return to this.
I found an easier solution in which I use eval()
for m in modules:
eval('alphabet.{}.sound()'.format(m))
I was wondering if it was possible for modules in a project to be smart about their imports...
Say I have the following data structure :
/parent-directory
/package
__init__.py
main.py
/modules
__init__.py
one.py
/submodules-one
__init__.py
oneone.py
onetwo.py
two.py
Files higher in the hierarchy are supposed to import Classes from those lower in the hierarchy.
For instance main.py has
import modules.one
import modules.two
Now I'd like to be able to directly run not only main.py, but also one.py (and all the others)
Except that it doesn't work like I hoped :
If I run from main.py, I need to have in one.py
import modules.submodules-one.oneone
import modules.submodules-one.onetwo
But if I run from one.py, I'll get an error, and I need to have instead
import submodules-one.oneone
import submodules-one.onetwo
I've found a hacky way to get around it using in one.py :
if __name__ == '__main__':
import submodules-one.oneone
import submodules-one.onetwo
else:
import modules.submodules-one.oneone
import modules.submodules-one.onetwo
But isn't there a better solution?
P.S.: I also have an additional complication, I'm using pint,
which to work properly only needs to have a single instance of the unit registry, so I have in the top ____init____.py :
from pint import UnitRegistry
ur = UnitRegistry()
And obviously
from .. import ur
will fail if running from one of the files of the subfolders.
Thank you in advance for your answer.