Why relative import errors in python are raised? Using relative imports in python seems to be a straightforward task. However, when you misuse relative import, you may find that the exception raised by the python interpreter is obscure.
Relative Import Exceptions
Sometimes, when you inappropriately use relative import, you may get the exception ValueError: attempted relative import beyond top-level package, or the exception ImportError: attempted relative import with no known parent package. It is not easy to understand those odd exceptions and their unclear and vague messages.
What “ValueError: attempted relative import beyond top-level package” means?
In python2, I sometimes get ValueError: attempted relative import beyond top-level package. It is strange. Why is ValueError Exception raised? I did not call any function at this line – I try to do a simple relative import. In python docs, we know that ValueError should be raised when an operation or function receives an argument with the right type but an inappropriate value.
Fortunately, the exception’s message gives you some hints and makes this exception less obscure. It is related to the relative import I tried to do. However, what is a top-level package, and why is it forbidden to import beyond this top-level package?
What “ImportError: attempted relative import with no known parent package” means?
In python3, Sometimes I get ImportError: attempted relative import with no known parent package. It seems there were some efforts to resolve the mystery.
First, in this case, a specific exception is raised, and its name clarifies that this exception is related to the import statement. However, the exception’s message is still unclear. What a package with no known parent package means?
Fixing Python Relative Import Errors
You can understand those mysterious exceptions. I also recommend first reading the following articles which explain how relative imports work and how to fix those issues.
- How to fix: ImportError: attempted relative import with no known parent package
- How to Fix ValueError: attempted relative import beyond top-level package
Understanding the syntax of relative import in python
It is surprising how easy it is to misuse relative imports. You probably understand the syntax of relative imports in python since it resembles the well-known syntax of relative paths in your filesystem. However, there are some differences between the relative import syntax and relative paths syntax in your filesystem
Let’s see some examples.
Examples For For Relative Import Syntax
Example 1 For Relative Import Syntax
Suppose you want to refer to config.txt in your favorite shell. If the config.txt is located at the parent directory of the shell’s current directory, You can refer to it via the relative path “../config.txt”
Similarly, suppose you want to import the config module from the current module. If config is located in the package’s parent package (that is, the package the module belongs to), you can write the statement “from . import config”
Example 2 For Relative Import Syntax
The relative path “../../data/config.txt” refers to the file located in the subdirectory data of the grandparent directory of the current directory (that is, the current directory associated with the current process – each process has its current directory).
Similarly, the statement “from ..data import config” imports the module data. The data module is a member of the grandparent package of the current package (that is, the package the module belongs to)
Example 3 for relative import syntax
Suppose there is a class Car a member of the vehicles module. The statement “from ..vehicles import Car”, import the Car class from the vehicles module. The vehicle module is the grandparent package of the current package.
Difference 1: The Base Entity
If try to relative import from main script, you will get relative import errors.
In the filesystem, the file we refer to with the relative path is relative to the current directory. In other words, the relative base is the current directory.
It is guaranteed the there will be a relative base since each process is associated with its current directory.
In python, the entities we import to the current module are relative to the current package – that is, the current package of the current module belongs to. In other words, the relative base is the current package.
Not all modules belong to a package. The main module (The script you invoked the python interrupter with) does not belong to a package. Therefore, you probably get the above exceptions. See How to fix: ImportError: attempted relative import with no known parent package and How to Fix ValueError: attempted relative import beyond top-level package for more details.
Difference 2: The Entities
If try to import from inseparable entities, you will get relative import errors.
In the filesystem, we can use the relative path to refer to two types of entities: files and directories. The directory is a container and can contain files and other directories (a.k.a as subdirectories).
In python, we can use the relative import to the current module several entities:
- We can import packages. From the import perspective, the package is container and can contain other packages, modules, and other inseparable entities.
- We can import modules. From the import perspective, the module is also container type. However, it can only contain other inseparable entities. That is, It can not contain packages and other modules.
- We can import other inseparable entities such as classes, functions, and variables. From the import perspective, an inseparable entity is an entity that we can not import its members. For example, a class is an inseparable entity since we can not import its attributes.
Difference 3: Parent Package Only In The Start
One dot (.) at the begging of the imported name means the parent package. One dot (.) in the middle of the imported name is separator.
In the filesystem, we refer to the parent directory double dot (“..”), and we separate each directory with a backslash (“/”). We can refer to parent directory even in the middle of path.
In python, we refer to the parent package with one dot (“.”), and we use the one dot (“.”) as a separator between the packages and the modules. How can one character have several rules? We can refer to the parent package only at the beginning of the path.
Avoid Relative Import Errors
As we see the syntax of relative import and the relative path in filesystem are similar. However, It can lead to 3 misconceptions relative import errors and exceptions. if you understand the differences, you can easily avoid relative import errors.