You are trying to use relative imports in python but you encounter the ImportError: attempted relative import with no known parent package exception. Why the python interpreter complains ? What did you do wrong ?

Why python can’t resolve relative import ?

Let’s see an example how we get this exception. Suppose you have the following directory structure:

project
├── config.py
└── package
    ├── __init__.py
    └── demo.py

The config.py contains some variables which should be used in the demo.py

  • project/config.py
count = 5
  • project/package/demo.py
from .. import config
print("The value of config.count is {0}".format(config.count))

When we try to run demo, we encounter the following error:

E:\project> python demos/demo.py
Traceback (most recent call last):
  File "demos/demo.py", line 1, in <module>
    from .. import config
ImportError: attempted relative import with no known parent package

You may also encounter the following error if you use newer version of python:

E:\project> python demos/demo.py
Traceback (most recent call last):
  File "demos/demo.py", line 1, in <module>
    from .. import config
SystemError: Parent module '' not loaded, cannot perform relative import  

The python interpreter complains that there is no parent package or that Parent module ‘’ not loaded. Why?

Let’s see how python interpreter resolve relative module. From PEP 328 which introduce the relative imports we found that:

Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to __main__) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

In other words, the algorithm to resolve the module is based on the values of __name__ and __package__ variables. Sometimes those variables does not contain any package information – When __name__ = __main__ and __package__ = None the python interpreter does not know the package the module is belong to. In this case, any relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.

Let update the source to demonstrate this:

  • project/config.py
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
count = 5
  • project/package/demo.py
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
from .. import config
print("The value of config.count is {0}".format(config.count))

When we try to run demo, we encounter the following output:

E:\project> python demos/demo.py
__file__=demos/demo.py                       | __name__=__main__             | __package__=None
Traceback (most recent call last):
  File "demos/demo.py", line 3, in <module>
    from .. import config
ImportError: attempted relative import with no known parent package
E:\project> python demos/demo.py
__file__=demos/demo.py                       | __name__=__main__             | __package__=None
Traceback (most recent call last):
  File "demos/demo.py", line 3, in <module>
    from .. import config
SystemError: Parent module '' not loaded, cannot perform relative import  

As we can see, the python interpreter does not have any information about the package the module belong to (__name__ = __main__ and __package__ = None).Therefore it complains that it can not find the parent package.

Solution 1

  • We convert project directory to a package by creating a new empty __init__.py in it.
  • We create main.py in parent directory of project directory

    toplevel
    ├── main.py
    └── project
      ├── __init__.py
      ├── config.py
      └── package
          ├── __init__.py
          └── demo.py
    
  • toplevel/main.py

    print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
    import project.demos.demo
    

When we run demo, we get the following output:

E:\toplevel>python main.py
__file__=main.py                             | __name__=__main__             | __package__=None
__file__=E:\toplevel\project\demos\demo.py   | __name__=project.demos.demo   | __package__=project.demos
__file__=E:\toplevel\project\config.py       | __name__=project.config       | __package__=project
The value of config.count is 5

Importing project.demos.demo in main.py will set package information (__name__ and __package__ variables). Now, the python interpreter can resolve the relative import in project\demos\demo.py successfully.

Solution 2

  • We convert project directory to a package by creating a new empty __init__.py in it.
  • We using -m switch of python interpreter with project.demos.demo

    toplevel
    └── project
      ├── __init__.py
      ├── config.py
      └── package
          ├── __init__.py
          └── demo.py
    

When we run demo, we get the following output:

E:\toplevel>python -m project.demos.demo
__file__=E:\toplevel\project\demos\demo.py   | __name__=__main__             | __package__=project.demos
__file__=E:\toplevel\project\config.py       | __name__=project.config       | __package__=project
The value of config.count is 5

Running the command will set package information (__package__ variable). Now, the python interpreter can resolve the relative import in project\demos\demo.py successfully (even thought __name__=__main__).