简体   繁体   中英

Python + Submodules: ImportError: attempted relative import with no known parent package

I've been struggling with relative imports on python.

My project structure looks like this:

root_dir
├── main.py
├── Pipfile
├── Pipfile.lock
├── unit_tests
│   ├── __init__.py
│   ├── test_first.py
│   └── test_second.py
└── my_package
    ├── __init__.py
    ├── first.py
    ├── second.py
    └── third.py

I want to import a set of functions from a file that is located in my_package into test_first.py .

According to the official documentation the syntax should be the following:

from ..my_package import first

When I do that, I get the following exception:

Traceback (most recent call last):
  File "/home/user/dev/root_dir/my_package/unit_tests/first.py", line 8, in <module>
    from ..my_package import first
ImportError: attempted relative import with no known parent package

I have also tried to import the file by using the following syntax:

from root_dir.my_package import first

When I do that, I get the following exception:

ModuleNotFoundError: No module named 'root_dir'

It is important to mention that I am using pipenv to handle the virtual environment. Any idea why this is happening?

Thanks.

First, I'll give you the code that worked for me. Then, I'll give a brief explanation. Here's a short function that should let you import from the root directory.

Solution

import os, sys

def access_root_dir(depth = 1):
    current_dir = os.path.dirname(os.path.realpath(__file__))
    parent_dir = os.path.dirname(current_dir)
    args: list = [parent_dir]
    for _ in range(depth):
        args.append('..')
    
    rel_path = os.path.join(*args)
    sys.path.append(rel_path) 

# At the top of test_first.py
access_root_dir(2)
import root_dir   

Since the root directory is a grandparent of test_first.py , you need to go to depth 2:

Explanation

I encountered the same problem in one of my projects and found that imports from a parent directory were fixed by altering the sys.path . Appending an absolute path to the root directory with something like sys.path.append(abs_path_to_root) doesn't seem to work unless everything is part of a package. Python won't access parent directories in imports by default.

# Case 1: Relative path to parent - works
current_dir = os.path.dirname(os.path.realpath(__file__))
relative_path = os.path.join(current_dir, '..')
sys.path.append(relative_path)
import parent_module_name # This works for me (Python 3.9)

# Case 2: Absolute path to parent - Doesn't work 
current_dir = os.path.dirname(os.path.realpath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.append(parent_dir)
import parent_module_name # raises ModuleNotFoundError

I think you need to do "...my_package". Use three "..."

".." implies the parent root_dir. The last "." Is accessing the child folder my_package.

The current working directory is not a package . Use os.getcwd() to see what it is, but it is likely going to be root_dir .

In that case, you can import top-level packages directly by name without a relative import; you should directly import from my_package , like so:

from my_package import first

...or:

from my_package.first import do_something

Replicated file tree:

root_dir
├── main.py
├── my_package
│   ├── __init__.py
│   └── first.py
└── unit_tests
    ├── __init__.py
    └── test_first.py

Contents of main.py :

from unit_tests import test_first

if __name__ == "__main__":
    test_first.test_something()

If you attempt to do a relative import, ie,: from..my_package import first you'll get:

ImportError: attempted relative import beyond top-level package

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM