Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use relative importing in Python3 with an if __name__='__main__' block?

I am making a package, and the modules within this package have code inside if __name__=='__main__': blocks for testing purposes. But my attempts to use relative imports in these modules causes errors.

I have read this thread and the billion others: Relative imports for the billionth time

Before you mark this as a duplicate, if what I want to do is not possible in Python3 then my question is why did it work in Python2 and what motivated the decision to make this such a hassle in Python3?


This is my sample Python project:

mypackage
- module1.py
- module2.py
- __init__.py

__init__.py and module2.py are empty

module1.py contains:

import module2

# module1 contents

if __name__=="__main__":
    # Some test cases for the contents of this module
    pass

This works fine in Python2. I am able to import module1 from other projects anywhere on my computer, and I'm also able to run module1 directly and have the code in the if block run.

However, this structure doesn't work in Python3. If I try import the module somewhere else it fails:

>>> from mypackage import module1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\_MyFiles\Programming\Python Modules\mypackage\module1.py", line 1, in <module>
    import module2
ModuleNotFoundError: No module named 'module2'

So I tried changing the first line to from . import module2, and that fixed it so I could import the module from anywhere successfully. But then when I try running module1 directly as a script I get this error:

Traceback (most recent call last):
  File "C:/_MyFiles/Programming/Python Modules/mypackage/module1.py", line 1, in <module>
    from . import module2
ImportError: cannot import name 'module2' from '__main__' (C:/_MyFiles/Programming/Python Projects/pgui/mypackage/module1.py)

I don't want to have to open a console and type python -m myfile every time I'm working on a module and want to run it directly as a script.

I want to be able to work on modules without adding their parent folder to PYTHONPATH by using relative imports like in Python2

Is there any better workaround or solution to these problems?

like image 698
pyjamas Avatar asked Feb 02 '19 03:02

pyjamas


1 Answers

According to the Module documentation, for __main__ modules, you have to use absolute imports.

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.

So just change the import line in module1.py to:

from mypackage import module2

Everything else remains the same.

like image 59
Anoop R Desai Avatar answered Sep 18 '22 16:09

Anoop R Desai