Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yet another ImportError: attempted relative import with no known parent package [duplicate]

I have the following directory structure:

py_test
├── __init__.py
├── dir1
│   ├── __init__.py
│   └── script1.py
└── dir2
    ├── __init__.py
    └── script2.py

In script2 I want to "import ..\script1".

What I tried in script2:

  1. Does not work

    from ..dir1 import script1
    ImportError: attempted relative import with no known parent package`
    
  2. Works

    import sys, os
    path2add = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'dir1')))
    if (not (path2add in sys.path)) :
        sys.path.append(path2add)
    

If I want to go with option 1, what is the simplest (i.e., with the least files) file/dir structure that makes it work? I am aware of this, but I wonder if creating that directory structure can be avoided, and still use type-1 import.

I am currently using this workaround, which uses type-2 import.

Related:

How to import a Python class that is in a directory above?

Import a module from a directory (package) one level up

Getting "ImportError: attempted relative import with no known parent package" when running from Python Interpreter

Using importlib to dynamically import module(s) containing relative imports

How to import variables in a different python file

like image 650
sancho.s ReinstateMonicaCellio Avatar asked Dec 26 '19 14:12

sancho.s ReinstateMonicaCellio


People also ask

How do you use relative import in Python?

Relative imports use dot(.) notation to specify a location. A single dot specifies that the module is in the current directory, two dots indicate that the module is in its parent directory of the current location and three dots indicate that it is in the grandparent directory and so on.

What is Python parent package?

It is an environment variable that contains the list of packages that will be loaded by Python. The list of packages presents in PYTHONPATH is also present in sys. path, so will add the parent directory path to the sys. path.


1 Answers

As mentioned in the comments, attempting to import modules a directory up will not work if script2.py is your entry point.

As mentioned in this link you included:

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.

The module's __name__ is set to __main__ if it is the entry point, or the one that you pass to the interpreter with something like python script2.py.

Any python module run as such no longer has the information needed to import files from higher directories.

Therefore you have two options:

Option 1: Keep using the workaround with sys.path.append

This will work how you want it to, but it is rather cumbersome.

Option 2: Make your entry point at the top level

Assuming your package has more than one script that needs to be run, you could create a new file that imports both script1 and script2 and then calls the functionality you want based on a command line argument. Then you will be able to keep your current directory structure and have your relative imports work just fine, without any kind of fiddling with sys.path.

like image 134
Aposhian Avatar answered Oct 09 '22 12:10

Aposhian