Search code examples
pythonpython-3.xpython-importrelative-import

Relative import problem with python packages


First of all, I have look through a lot of question-answer regarding this issue but I couldn't find a solution to my problem.


I am on Python 3.7.9 and my file structure looks as in the following

generator/
    __init__.py
    main.py
    summarygenerator/
        __init__.py
        utils.py
        summary_generator.py

The summary_generator.py looks like

from summarygenerator.utils import solver

def sum_gen():
   pass
if __name__ == '__main__':
   sum_gen()

With this approach, from the 'generator' directory I am able to run main.py with:

python main.py

and summary_generator.py with

python -m summarygenerator.summary_generator

However, when I would like to run summary_generator.py from the generator/summarygenerator directory then I face with:

ModuleNotFoundError: No module named summarygenerator

Relative imports as in the below doesn't solve the issue as well.

from .utils import solver

Solution

  • Python modules are meant to be run from the parent directory of their root package. So the correct way of running the scripts would be (starting from the generator directory):

    $ cd ..
    $ python -m generator.main
    $ python -m generator.summarygenerator.summary_generator
    

    The imports are meant to work out of the box and you can even use relative imports. Now you seem to want to be able to run the python script with the same code from two different locations out of the box (with the same code). That is not supported and indeed makes no sense. In the imports case it would mean that python should be able to record the name of the module in two different ways and everything (all other module names) should work with both names. Or take the (simpler) case of defining relative paths in your file (like open('some_file')) - this is doomed if the file is run in two ways. In both cases the problem is the change in the current working directory - the directory the script is run from is set as the current working directory relative to which paths (including module paths) are calculated. You can make this "run me from whatever folder" work by messing with the current working dir and creating even more subtle bugs - or (and this is the answer I think) stop trying to be able to run the same script from different folders, write the imports so they work with the commands above which is the recommended way of running a python script (so all documentation on imports assume this way of running it)