У меня вот такая структура проекта
---package1/code.py
---package2/ext.py
Как мне импортировать переменную из ext.py в code.py ?
from ext import var
— не срабатывает, говорит что не существует модуля ext
from ..package2.ext import var
— тоже не срабатывает выдаётся ошибка: ImportError: attempted relative import with no known parent package
insolor
46.1k16 золотых знаков54 серебряных знака96 бронзовых знаков
задан 1 мар 2020 в 7:37
Greed WizardGreed Wizard
1981 золотой знак2 серебряных знака9 бронзовых знаков
1
Всё работает.
-
В файлах указывать
import
иfrom
без ведущих точек:from package2.ext import var
а не
from ..package2.ext import var
-
Вызывать нужно из папки ваш_проект вот такую команду:
python -m package1.code
Можно путь к python указать полностью, типа usr/bin/python
.
Важно указать -m
и точку .
между package1
и code
, а не /
, и после code
не писать .py
.
Вот так:
путь_к_вашему_проекту> python -m package1.code
insolor
46.1k16 золотых знаков54 серебряных знака96 бронзовых знаков
ответ дан 27 мая 2022 в 12:38
Python просматривает список каталогов определенный в sys.path
.
Ошибка: ImportError: attempted relative import with no known parent package
говорит о том что модуль не был найден в sys.path
(вывод ее на печать поможет прояснить ситуацию).
При такой структуре желательно использовать main.py
для запуска и импорта дочерних модулей:
project_folder/
main.py
package1/
__init__.py
code.py
package2/
__init__.py
ext.py
Если вам нужно запустить code.py
и при этом импортировать данные из ext.py
, то нужно:
- запустить
code.py
как модульpython -m package1.code
- или добавить
sys.path.append(os.getcwd())
в самое началоcode.py
ответ дан 10 апр 2021 в 14:43
StepanStepan
1192 бронзовых знака
1
- в пакетах package1 и package2 должен быть пустой файл
__init__.py
(если его нет) - такая структура будет:
ваш_проект/
package1/
__init__.py
code.py
package2/
__init__.py
ext.py
- я тестировал на таких файлах:
code.py
var = "code.py"
ext.py
from package1.code import var
print(var) # выводит code.py
P.S. Надеюсь чем-то помогло
ответ дан 1 мар 2020 в 9:21
2
Table of Contents
Hide
- How does module import work in Python?
- Absolute vs. Relative imports
- How to fix ImportError: attempted relative import with no known parent package?
- Option 1 – Use absolute imports
- Option 2 – Get rid of from keyword
- Option 3 – Import inside package init file
Module imports sometimes can cause too much frustration if you are a Python beginner. This tutorial will learn how imports work and the solution for ImportError: attempted relative import with no known parent package.
Before getting into the solution, let’s first understand few basic terminologies in Python.
Python Module: A module is a file in Python containing definitions and statements. A module can contain executable statements as well as function definitions. In simple terms, think as a single .py file with some functionality.
Python Package: A Python package consists of one or more modules, and it contains one file named __init__.py
that tells Python that this directory is a package. The init file may be empty, or it may include code to be executed upon package initialization.
imports: Imports in Python are essential for structuring your code effectively, and by using the import keyword, you can import any module and reuse it effectively. There are two types of import, Relative and Absolute, which will look in-depth.
Let’s consider a simple example.
└── myproject
├── firstpackage
│ ├── a.py
└── secondpackage
├── b.py
├── c.py
└── subpackage
└── d.py
The above project has two packages named firstpackage and secondpackage. Each of these contains some modules, and the secondpackage also has a subpackage that includes its own module. Typically the project structure goes something like this, and it may grow pretty complex.
How does module import work in Python?
Now, let’s say if you import module b in one of your files using the import statement as shown below.
import b
Python will perform the following operations to import the module:
- Locate, load, and initialize (if required) the requested module
- Define necessary names in the local namespace and corresponding scope
Now Python interpreter is going to follow the following steps in an attempt to resolve module b .
Step 1: sys.modules
lookup
Python will try to look at the module first in the sys.modules
, which is a dictionary that has a mapping of key-value pairs of modules. If it finds, then the module is resolved and loaded.
Step 2: Python Standard Library lookup
Python Standard Library contains built-in modules (written in C) that provide access to system functionality such as file I/O that would otherwise be inaccessible to Python programmers. Modules are written in Python that provides standardized solutions for many problems that occur in everyday programming. Some of these modules are explicitly designed to encourage and enhance the portability of Python programs by abstracting away platform-specifics into platform-neutral APIs.
If the name is not found in the sys.modules
, it will search in the standard library. If it cannot find over there, then it goes to the next step.
Step 3: sys.path
lookup
Python will look into the sys.path as the last step to resolve the module. This is where things can go wrong, and you will get ModuleNotFoundError: No module named ‘b’
Absolute vs. Relative imports
In absolute imports, you need to specify the explicit path from the project’s root directory.
Example – If we have to import module b then we can use the following way to import
import secondpackage.b
Other ways of importing modules in Python
# importing modules a.py
import secondpackage.subpackage.d
import secondpackage.c
In case of relative imports, we need to specify the module’s path relative to the current module’s location.
Example –
# in module a.py
from ..secondpackage import b
from ..secondpackage.b import another_function
# in module b
from . import c
from .c import my_function
Option 1 – Use absolute imports
For instance, the directory structure may be as follows
.
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module.py
│ │ └── standalone.py
│ └── setup.py
where setup.py is
from setuptools import setup, find_packages
setup(
name = 'your_package_name',
packages = find_packages(),
)
Option 2 – Get rid of from keyword
Remove the from keyword and use the standard way of import as shown below.
import secondpackage.c
Option 3 – Import inside package init file
Put this inside your package’s __init__.py file:
# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))
Assuming your package is like this:
├── project
│ ├── package
│ │ ├── __init__.py
│ │ ├── module1.py
│ │ └── module2.py
│ └── setup.py
Now use regular imports in you package, like:
# in module2.py
from module1 import class1
Srinivas Ramakrishna is a Solution Architect and has 14+ Years of Experience in the Software Industry. He has published many articles on Medium, Hackernoon, dev.to and solved many problems in StackOverflow. He has core expertise in various technologies such as Microsoft .NET Core, Python, Node.JS, JavaScript, Cloud (Azure), RDBMS (MSSQL), React, Powershell, etc.
This article will discuss the error – ImportError: Attempted Relative Import With No Known Parent Package. The primary reason for this error is that the specified module does not exist within the Python library.
In Python, the failure to import a module, module member, or other python files results in ImportError.
What Causes This Error?
Let’s take the following file structure as an example to better understand the reasons for this error.
->ProjectDirectory
|
|
|
---->myPackage1
- __init__.py
- runCode.py
|
|
|
---->myPackage2
- __init__.py
- function.py
ProjectDirectory
Consists of 2 folders : myPackage1
(runCode.py) and myPackage2
(function.py).
runCode.py
from .myPackage2 import runFunction print("Running Code") function.runFunction()
function.py
def runFunction(): print("Running Function")
Note that the runCode.py
program makes use of the function from function.py
by importing.
Now, let’s discuss what’s relative importing.
In runCode.py, note that a dot(.) is used in the import statement. This usage of the dot indicates a relative import. As we call a function from a different package(directory), the caller program (runCode.py) has to call one level above. Multiple directory levels require multiple dots. This is the concept of relative importing. Its counter-technique. Absolute importing requires the complete path.
Let’s look at the actual error produced by runCode.py
C:UsersSampleFolderPythonProgramsProjectDirectorymyPackage > python runCode.py Traceback (most recent call last): File "C:UsersSampleFolderPythonProgramsProjectDirectorymyPackagerunCode.py", line 1m in <module> from myPackage2 import runFunction ImportError: attempted relative import with no parent package
This is due to the fact that a parent package doesn’t exist.
How To Solve This Error?
The most straightforward approach is to make the particular package global using a setup.py file. Let’s look at the following steps to achieve the same.
Creating a Setup File
Create a Setup file using the setuptools
module from Python. The setup file defines the package to be made global.
from setuptools import setup, find_packages setup(name = "myPackage2", packages = find_packages())
The above lines import the module from myPackage2.
Running the Setup File
Access your project directory and run the following command in your command terminal.
python setup.py install
Changing the Caller Program (runCode.py)
Remove the dot from the import statement now that the package is global.
from myPackage2 import function print("Running Code") function.runFunction()
Output
C:UsersSampleFolderPythonProgramsProjectDirectorymyPackage > python runCode.py Running Code Running Function
Let’s look at the following program that deals with unit testing.
import unittest from ..programUtil import util class TestUrlUtilities(unittest.SampleTestCase): def test_simple(self): result = name_from_link("https://pythonpool.com") self.assertEqual(result, "Python") if __name__ == "__main__": unittest.main()
Output
ERROR: program_utilities(unittest.loader._FailedTest) ImportError: Failed to import test module: program_utilities Traceback (most recent call last): File "C:Python37libunittestloader.py", line 13, in loadTestsFromName module = __import__(module_name) ImportError: attempted relative import with no known parent package
What do we do in this situation? As the error says, the test folder doesn’t contain a parent package. This means using double dots (..) to import relatively will not work.
Go to the project source directory and run the following command:
python -m unittest
This creates a src
folder for our project path. Now that our module is in the path, there is no need for a relative import (..).
ImportError: Attempted Relative Import With No Known Parent Package Django
When you import a function into your Django project, you may receive the ImportError. This is due to the fact that you cannot import relatively from a direct run script. Relative imports work only if the package has been imported completely as a module.
For example, if a code is passed through /user/stdin
, there isn’t a reference for the file’s location.
Use relative imports when running .py programs. If a relative import is a must, convert the program file as a __main__.py file within the package directory while passing the Python -m command to run the module.
ImportError: Attempted Relative Import With No Known Parent Package IntelliJ (PyCharm IDE)
In this scenario, the program files may run without error. However, the unit test can fail and produce relative import errors when run from the program file’s directory.
To solve this problem, set the working directory as the top-level project directory. After this, any unit tests or relative imports will run properly. In summary, resetting the working directory should fix the relative import errors.
Attempted Relative Import Beyond Top Level Package Error
Let’s take the following file structure as an example
myModule/ __init__.py P/ __init__.py program.py testProgram_P/ __init__.py testCode.py
testCode.py
from ..P import program
To run tests, you may pass the following command within the myModule
directory
python -m testProgram_P.testCode
This can result in the following error:
"ValueError: attempted relative import beyond top-level package"
However, within the parent folder of myModule
, testProgram_P.testCode
will run perfectly.
Why does this error occur?
This is due to the fact that Python doesn’t keep track of the package location. Therefore, upon running python -m testProgram_P.testCode
Python doesn’t take into account that the file is located in myModule
. This means writing from ..P import program
is basically trying to fetch information that does not exist anymore.
FAQs
What is a Relative Import?
A relative import in Python specifies the content to be imported into the project, which is relative to its exact location.
What should __init___.py contain?
__init__.py file may contain Python code that a python package would have. However, Python will add extra attributes to the package whenever imported.
What is __import__() in Python?
The __import__() function is used by the Python import statement to import packages into the Python project. It takes the following parameters:name
– name of the module to be importedglobals/locals
– Determines the nature of the package.fromlist
– extra objects or submodules to be imported by the modulelevel
– specifies the type of import (absolute/relative)
Conclusion
In this article, we have looked at the exception: ImportError: Attempted Relative Import With No Known Parent Package. This error shows us how much the structure of a working directory matters in Python. We have learned that Python does not consider the current working directory to be a package itself, therefore hindering relative imports.
Trending Python Articles
-
[Solved] typeerror: unsupported format string passed to list.__format__
●May 31, 2023
-
Solving ‘Remote End Closed Connection’ in Python!
by Namrata Gulati●May 31, 2023
-
[Fixed] io.unsupportedoperation: not Writable in Python
by Namrata Gulati●May 31, 2023
-
[Fixing] Invalid ISOformat Strings in Python!
by Namrata Gulati●May 31, 2023
- Why “ImportError: attempted relative import with no known parent package” is Raised?
- Avoid ImportError: attempted relative import with no known parent package
- 2 Ways to Check Whether the module belongs to a package
- Sample for “ImportError: attempted relative import with no known parent package”
- Review the __name__ and __package__ variables
- How to fix “ImportError: attempted relative import with no known parent package”
- Solution 1 : Change Directory Structure
- Solution 2 : Use the -m option
- Solution 3 : Workaround Without Changing Directory Structure
- Summary
Relative imports in python can be frustrated from time to time. Therefore, from time to time, you may meet the mysterious and obscure exception “ImportError: attempted relative import with no known parent package” Let’s see what this exception means, why it is raised. Finally, we see how to get rid of the “ImportError: attempted relative import with no known parent package” exception
As a rule of thumb – If you try to do relative import in a module that does not belong to a package, you will get the “ImportError: attempted relative import with no known parent package” exception.
Why? The reasons beyond this rule of thumb are related to how relative import works in python.
In PEP 328 (Imports: Multi-Line and Absolute/Relative) that add the support of relative imports, we can find how the python interpreter should resolve the relative modules.
Relative imports use a module’s
__name__
attribute to determine that module’s position in the package hierarchy.PEP 328
First, this statement implies that relative import is relative to the current package. What is the current package? The current package is the package the current module belongs to. However, you probably know that not all modules belong to a package. Therefore, the module where we do the relative import must belong to a package, or otherwise, the python interrupter will scream that you are doing something wrong.
Second, this statement describes how the python interrupter should find the current package when it searches for the imported module. When the Python interrupter tries to find out the current package, It obtains the package information by checking the value of the __name__ variable (the module’s name).
What should the interrupter do when the module’s name does not contain any package information?
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.PEP 328
If __name__ variable does not have any package information, the python interpreter should treat the module as a top-level module (a module that does not belong to any package). In that case, the current package does not exist. Therefore, the python interpreter can not resolve the location of the imported module and you get “ImportError: attempted relative import with no known parent package“
This description shows one of the best example of a module that does not belong to a package : the __main__ module. The __main__ module, the script you invoked the python interrupter with, does not belong to any package. We use this example later to demonstrate how to get rid of “ImportError: attempted relative import with no known parent package” exception.
Avoid ImportError: attempted relative import with no known parent package
As we see, when you try to do relative import in a module that does not belong to a package, you will get the “ImportError: attempted relative import with no known parent package” exception. It is essential to know that the module where you do relative import belongs to a package; otherwise, you get this irritating exception.
2 Ways to Check Whether the module belongs to a package
One way to check if a module belongs to a package is to review the value of __name__ variable. If the __name__ variable contains a dot, the module belongs to a package.
Another way to check if a module belongs to a package is to review the value of __package__
variable. if the __package__
variable do not equal to None
, the module belongs to a package.
Sample for “ImportError: attempted relative import with no known parent package”
The following sample demonstrates that the main module (The script you invoked the python interrupter with) does not belong to a package.
Suppose you have a project with the following simple directory structure:
Sample Directory Structure
root
├── config.py
└── package
├── __init__.py
└── program.py
You are trying access variables defined in the config.py
in your program.py
. It seems a straightforward task and you choose to use relative import:
root/package/program.py
from .. import config
print("config.count => {0}".format(config.count))
However, when invoking program.py
script, An exception is raised :
“ImportError: attempted relative import with no known parent package” Is Raised
Y:/root>python package/program.py
Traceback (most recent call last):
File "package/program.py", line 1, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
Review the __name__ and __package__ variables
Let’s review the values of the __name__
and __package__
variables by adding some log messages at the top of the above modules:
root/config.py with logs
print('__file__={0:<35} | __name__={1:<25} | __package__={2:<25}'.format(__file__,__name__,str(__package__)))
count = 5
root/package/program.py with logs
print('__file__={0:<35} | __name__={1:<25} | __package__={2:<25}'.format(__file__,__name__,str(__package__)))
from .. import config
print("config.count => {0}".format(config.count))
Invoking program.py
Y:/root>python package/program.py
__file__=package/program.py | __name__=__main__ | __package__=None
Traceback (most recent call last):
File "package/program.py", line 3, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
As we can see in the above output, the value of the value of __package__
is None
and the value of __name__
variable is __main__
.
Since, the value __package__
is None
and the value of the variable __name__
does not contains any dot, we can know that module does not belong to any package. Therefore, the python interrupter raises the unclear exception.
How to fix “ImportError: attempted relative import with no known parent package”
Solution 1 : Change Directory Structure
In this solution, we need to change directory structure and create a new script
- First, create a new directory named
new_root
and move theroot
directory tonew_root
- Create
main.py
innew_root
directory - Create a new empty
__init__.py
inside theroot
directory. This will signal to the python interrupter that this directory is a package.
The sample directory
new_root
├── main.py
└── root
├── __init__.py
├── config.py
└── package
├── __init__.py
└── program.py
Updating new_root/main.py
print('__file__={0:<35} | __name__={1:<25} | __package__={2:<25}'.format(__file__,__name__,str(__package__)))
import root.package.program
When we invoke the new script, we get the following output:
Invoking program.py
Y:/new_root>python main.py
__file__=main.py | __name__=__main__ | __package__=None
__file__=Y:/new_root/root/package/program.py | __name__=root.package.program | __package__=root.package
__file__=Y:/new_root/root/config.py | __name__=root.config | __package__=root
config.count => 5
It works. Let’s see why?
Now, the module root.package.program
belongs to root.package
.
We can see it in the second line (The print from the top of new_root/root/package/program.py).
__file__=Y:/new_root/root/package/program.py | __name__=root.package.program | __package__=root.package
Now, when this module belong to a package, the python interpreter has all the information has all the information to resolve the relative import in root/package/program.py
successfully.
Solution 2 : Use the -m option
In the first solution, we need to create a new script. In this solution, we use -m option without creating a new script.
Let’s change directory structure and use -m option
- First, create a new directory named
new_root
and move theroot
directory tonew_root
- Create a new empty
__init__.py
inside theroot
directory. This will signal to the python interrupter that this directory is a package.
The sample directory
new_root
└── root
├── __init__.py
├── config.py
└── package
├── __init__.py
└── program.py
Now, we invoke python with -m option and provide the module root.package.program
.
The python -m option allows modules to be located using the Python module namespace for execution as scripts. As the following output demonstrate, It will also set the package information:
Invoking program.py with -m option
Y:/new_root>python -m root.package.program
__file__=Y:/new_root/root/package/program.py | __name__=__main__ | __package__=root.package
__file__=Y:/new_root/root/config.py | __name__=root.config | __package__=root
config.count => 5
It works. Let’s see why?
Now, the module root.package.program
belongs to root.package
.
We can see it in the first line (The print from the top of new_root/root/package/program.py).
__file__=Y:/new_root/root/package/program.py | __name__=__main__ | __package__=root.package
Now, when this module belong to a package, the python interpreter has all the information has all the information to resolve the relative import in root/package/program.py
successfully.
Note: Unlike PEP 328, the python interpreter do not rely on the value of __name__ to find the package information and uses the value of __package__.
Solution 3 : Workaround Without Changing Directory Structure
In previous solutions, we needed to change the directory structure. Sometimes, you want to avoid changing the directory structure. For example, the framework you use in your code (such as django, pytest, airflow, fastapi or flask) or the environment you work with (such as pycharm, vscode or jupyter notebook) depend on this directory structure. In those cases, you may consider the following workaround.
As we see in solution 2, the python interrupter relies on the __package__ variable to extract the package information. Therefore, when the __package__ is none, the python interrupter will cry that you are doing something wrong.
So, Let’s use this observation and enclose the relative import with the following if statement based on the value of the __package__ variable.
Invoking program.py with -m option
if __package__:
from .. import config
else:
sys.path.append(os.dirname(__file__) + '/..')
import config
It works. Let’s see why?
If the __package__ is not None, we can safely use relative import. However, if __package__ is None, we can not use relative import anymore. Therefore we add the directory of the module to sys.path and import the required module. Since sys.path is a list of paths that specify where the python interrupter should search for imported modules, python interrupter will find the required module.
How to generate the directory?
First, replace the first dot in the relative import with os.dirname(__file__) and then replace each successive dot with “../”. Now append successive part between the dots.
from . import config | sys.path.append( os.dirname(__file__) ) import config |
from .. import config | sys.path.append( os.path.join( os.dirname(__file__), ‘..’ ) ) import config |
from … import config | sys.path.append( os.path.join( os.dirname(__file__), ‘..’ , ‘..’ )) import config |
from ..a.b.c import config | sys.path.append( os.path.join( os.dirname(__file__), ‘..’ , ‘a’ ,’b’ ,’c’ )) import config OR better (less chance for name clashing) sys.path.append( os.path.join( os.dirname(__file__), ‘..’ )) |
However, this method is very fragile. If a module with the required name (in our case, config) already exists in the sys path’s previous paths, the python interrupter will import it instead of our module. It can be a source of nasty and mysterious bugs.
So use this workaround with caution and only when necessary.
Summary
We see how the python interrupter resolve relative imports. Then, we see why the “ImportError: attempted relative import with no known parent package” exception is raised. Finally we see how to get rid of “ImportError: attempted relative import with no known parent package”
One error you might encounter when working with a Python project is:
ImportError: attempted relative import with no known parent package
This error usually occurs when you try to import a module in Python using the relative import path (using a leading dot .
or ..
)
This tutorial shows an example that causes this error and how to fix it in practice.
How to reproduce this error
First, suppose you have a Python project with the following file structure:
.
└── project/
├── helper.py
└── main.py
The helper.py
script contains a function as follows:
def greet():
print("Hello World!")
Next, you tried to import helper.py
into main.py
as follows:
from .helper import greet
print("Starting..")
greet()
The output will be:
Traceback (most recent call last):
File "main.py", line 1, in <module>
from .helper import greet
ImportError: attempted relative import with no known parent package
This error occurs because we used a relative import, which doesn’t work when you’re importing a module in the same directory as the main script you executed using Python.
Python doesn’t consider the current working directory to be a package, so you can’t do a relative import unless you run your main.py
script from the parent directory.
How to fix this error
To resolve this error, you need to change the relative import to an absolute import by removing the leading dot:
from helper import greet
print("Starting..")
greet()
The output will be:
Python is able to find the helper
module, so we didn’t get any errors this time.
If you still want to use the relative import path, then you need to run the main script as a module from its parent directory.
Since the main.py
file is located inside the project
directory, you can run the script with this command:
python -m project.main
# or
python3 -m project.main
This time, the relative import works because Python considers the project
directory to be a package. It keeps track of what’s inside the directory.
If you run the script directly without specifying the parent directory as follows:
Then the relative import error will occur again.
The same solution also works when you try to do sibling imports. Suppose you have the following file structure in your project:
.
└── project/
├── lib
│ └── helper.py
└── src
└── main.py
And you try to import the helper.py
script into the main.py
script as follows:
from ..lib.helper import greet
print("Starting...")
greet()
To make the relative import successful, you need to run the main
script from the project
directory like this:
python -m project.src.main
# or
python3 -m project.src.main
If you run the main.py
script directly, you’ll get the same error:
$ python3 main.py
Traceback (most recent call last):
File "/main.py", line 1, in <module>
from ..lib.helper import greet
ImportError: attempted relative import with no known parent package
The internal workings of Python doesn’t allow you to do relative import unless you specify the top-level directory where all your modules are located.
By adding the root directory of the project when running the main script, you can solve the relative import error.
I hope this tutorial is helpful. Happy coding! 👍