[ERROR FIXED] “Attempted relative import in non-package” even with __init__.py

[toc]

Understanding the Error

Problem Formulation: How to fix or deal with the following error – ” Attempted relative import in non-package”?

Let’s say you have been working on your new project, and now you have decided to organize your project files properly. Hence, you move certain functions to another file to make your code look cleaner. Now, you go ahead and execute your code once again after you have finished the clean-up task. But Wait!!! What just happened!!! 😧 A few minutes ago, your code was working fine, but now it is no longer working. Instead, you got the following error:

ImportError: attempted relative import with no known parent package

Example

The error in discussion mostly occurs when you follow a directory structure as described in PEP 328, but you miss the trick to properly import the required module in your script. Let’s consider that you have the following structure for your project –

# app.py
from ..components import mod

print("Trying to import value from mod!")
mod.foo()
# mod.py
def foo():
    print("Hey Finxter!")

Output:

Traceback (most recent call last):
  File "C:\Users\SHUBHAM SAYON\PycharmProjects\Finxter\Errors\Tests\app.py", line 1, in <module>
    from ..components import mod
ImportError: attempted relative import with no known parent package

The Reason

In Python, the import mechanism works in accordance with the name of the current file. So, when a file is executed directly, then the name of the file being executed is not its actual name. Instead, the name of this file will be “main”. Since the script that contains the relative path import can only be referenced as a module and cannot be executed directly, hence, the import mechanism will fail and you will encounter a relative import error.

Now that we have a clear idea about why the error occurs let’s dive into the solutions to avoid or fix this error. (If you want to dive into the concepts behind the fixes proposed below, please read further here.)

Video Walkthrough

#FIX 1: Import Using The Absolute Path

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.

# app.py
from Errors.components import mod # absolute import

print("Trying to import value from mod!")
mod.foo()

Let’s visualize the output of this code when we use the absolute path to import the module.

Eureka! We resolved the issue.

#FIX 2: Using sys.path.append()

Another approach to deal with this error is to use the sys.path.append() function to add the directory of the required module to the environment variable. The list of directories that Python searches for the required modules and files are stored in the path attribute of the sys module. Now path is a list and we can use the append method to add new directories.

The following snippet demonstrates how to use the sys module to overcome the error.

# app.py
import sys
sys.path.append("C:\\Users\\SHUBHAM SAYON\\PycharmProjects\\Finxer"
                "\\Errors\\components")
import mod
print("Trying to import value from mod!")
mod.foo()

Output:

#FIX 3: Using the “m” Switch

Another workaround to this issue is to use the “-m”switch to execute your code. It is a command-line switch that allows Python to locate modules using the Python module namespace for execution as scripts.

Note: The path from where we are executing this code is outside the Errors directory. In case you are executing this from the Errors directory itself, then use this command: python -m Tests.app

Further Reading

Absolute PathRelative Path
Import using the full path. (For e.g., from projects root folder to the desired module.)Import relative to the current location with respect to the location of the module to be imported. Relative imports use the dot notation.  
Absolute import will remain valid even when the location of the import statement changes.  Relative import will not work if the location of the import statement changes.
Example: considering the same directory arrangement as given at the beginning of the article.

from calculator import add

x = int(input(“first no.”))
y = int(input(“second no.”))
r = add(x, y)
print(“Sum: “, r)
Example: considering the same directory arrangement as given at the beginning of the article.  


from calculator import add

x = int(input(“first no.”))
y = int(input(“second no.”))
r = add.add(x, y)
print(“Sum: “, r)  

When using relative imports you can use more than one dot to refer to the parent folders within your packages. For example, two dots in from .. import your_module would import the module from the parent folder, and three dots in from ... import your_module would import the module from the parent of the parent.

from .. import your_module      # searches "your_module.py" in the parent folder
from ... import your_module     # searches "your_module.py" in the grandparent folder

Conclusion

To sum things up, you can avoid this error by simply importing the module using the absolute path instead of the relative path. The other options are:

  • to use the "-m" switch while executing the script using the command prompt
  • using sys.path.append()

To get a deeper understanding of packages and imports, please go through these tutorials –


Where to Go From Here?

Door 1: The Finxter App
Are you better than you think? Test and train your Python skills to find out!
Door 2: The Finxter Blog
Do you want to boost your skills in Blockchain development, coding, or freelancing? Check out our helpful expert tutorials!