Search code examples
pythonrelative-import

Python error - ImportError: attempted relative import with no known parent package


So, my files/folders structure is the following:

project/
├─ utils/
│  ├─ module.py
├─ server/
│  ├─ main.py

Inside project/server/main.py I'm trying to import project/utils/module.py using this syntax: from ..utils.module import my_function.

I'm using VSCode, and it even autocomplete for me as I type the module path. But when I run the file project/server/main.py, I get the error in the title.

I've read dozens of answers here on stack overflow about this topic but none of them used an example like this.


Solution

  • Here is a reference that explains this problem well. Basically, the problem is that __package__ is not set when running standalone scripts.

    File structure

    .
    └── project
        ├── server
        │   └── main.py
        └── utils
            └── module.py
    

    project/server/main.py

    if __name__ == '__main__':
        print(__package__)
    

    Output

    $ python3 project/server/main.py
    None
    

    As we can see, the value of __package__ is None. This is a problem because it is the basis of relative imports as stated here:

    __package__

    ... This attribute is used instead of __name__ to calculate explicit relative imports for main modules, as defined in PEP 366...

    Where PEP 366 explains this further:

    The major proposed change is the introduction of a new module level attribute, __package__. When it is present, relative imports will be based on this attribute rather than the module __name__ attribute.

    To resolve this, you can run it as a module via -m flag instead of a standalone script.

    Output

    $ python3 -m project.server.main  # This can be <python3 -m project.server> if the file was named project/server/__main__.py
    project.server
    

    project/server/main.py

    from ..utils.module import my_function
    
    if __name__ == '__main__':
        print(__package__)
        print("Main")
        my_function()
    

    Output

    $ python3 -m project.server.main
    project.server
    Main
    My function
    

    Now, __package__ is set, which means it can now resolve the explicit relative imports as documented above.