Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relative import problems in Python 3

Python imports drive me crazy (my experience with python imports sometime doesn't correspond at all to idiom 'Explicit is better than implicit' :( ):

[app]
    start.py
        from package1 import module1
    [package1]
        __init__.py
            print('Init package1')
        module1.py
            print('Init package1.module1')
            from . import module2
        module2.py
            print('Init package1.module2')
            import sys, pprint
            pprint.pprint(sys.modules)
            from . import module1

I get:

vic@ubuntu:~/Desktop/app2$ python3 start.py 
Init package1
Init package1.module1
Init package1.module2
{'__main__': <module '__main__' from 'start.py'>,
 ...
 'package1': <module 'package1' from '/home/vic/Desktop/app2/package1/__init__.py'>,
 'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>,
 'package1.module2': <module 'package1.module2' from '/home/vic/Desktop/app2/package1/module2.py'>,
 ...
Traceback (most recent call last):
  File "start.py", line 3, in <module>
    from package1 import module1
  File "/home/vic/Desktop/app2/package1/module1.py", line 3, in <module>
    from . import module2
  File "/home/vic/Desktop/app2/package1/module2.py", line 5, in <module>
    from . import module1
ImportError: cannot import name module1
vic@ubuntu:~/Desktop/app2$ 

import package1.module1 works, but i want to use from . import module1 because i want to make package1 portable for my other applications, that's why i want to use relative paths.

I am using python 3.

I need circular imports. A function in module1 asserts that one of its parameter is instance of a class defined in module2 and viceversa.

In other words:

sys.modules contains 'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>. I want to get a reference to it in form from . import module1, but it tries to get a name, not a package like in case import package1.module1 (which works fine). I tried import .module1 as m1 - but that's a syntax error.

Also, from . import module2 in module1 works fine, but from . import module1 in module2 doesn't work...

UPDATE:

This hack works (but i am looking for the 'official' way):

print('Init package1.module2')

import sys, pprint
pprint.pprint(sys.modules)

#from . import module1
parent_module_name = __name__.rpartition('.')[0]
module1 = sys.modules[parent_module_name + '.module1']
like image 549
warvariuc Avatar asked Nov 06 '11 20:11

warvariuc


People also ask

How do I resolve Python import errors?

Python's ImportError ( ModuleNotFoundError ) indicates that you tried to import a module that Python doesn't find. It can usually be eliminated by adding a file named __init__.py to the directory and then adding this directory to $PYTHONPATH .

How do you use relative import in Python?

Relative imports make use of dot notation to specify location. A single dot means that the module or package referenced is in the same directory as the current location. Two dots mean that it is in the parent directory of the current location—that is, the directory above.

Why are Python imports so confusing?

Imports are difficult because there are so many factors interacting with each other to make things work when they shouldn't, and make things fail/get a warning when they should not.

How do I fix Attempted relative import in non package?

Since the issue revolves around the relative import, an easy fix to this issue is to use the absolute path to import the necessary module, as shown below. What is this? print("Trying to import value from mod!") Let's visualize the output of this code when we use the absolute path to import the module.


1 Answers

A better solution for your problem is to put package1 in it's own separate package. Of course then it can't import package2, but then again if it is reusable, why would it?

like image 189
Lennart Regebro Avatar answered Sep 21 '22 00:09

Lennart Regebro