Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

beyond top level package error in relative import

It seems there are already quite some questions here about relative import in python 3, but after going through many of them I still didn't find the answer for my issue. so here is the question.

I have a package shown below

package/
   __init__.py
   A/
      __init__.py
      foo.py
   test_A/
      __init__.py
      test.py

and I have a single line in test.py:

from ..A import foo

now, I am in the folder of package, and I run

python -m test_A.test

I got message

"ValueError: attempted relative import beyond top-level package"

but if I am in the parent folder of package, e.g., I run:

cd ..
python -m package.test_A.test

everything is fine.

Now my question is: when I am in the folder of package, and I run the module inside the test_A sub-package as test_A.test, based on my understanding, ..A goes up only one level, which is still within the package folder, why it gives message saying beyond top-level package. What is exactly the reason that causes this error message?

like image 334
shelper Avatar asked Jun 05 '15 14:06

shelper


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 __ init __ py?

The __init__.py file makes Python treat directories containing it as modules. Furthermore, this is the first file to be loaded in a module, so you can use it to execute code that you want to run each time a module is loaded, or specify the submodules to be exported.

Why do I get ValueError attempted relative import beyond top-level package?

If you try to do relative import in a module that does not belong to a package, you will get the ValueError: Attempted relative import beyond top-level package exception. Let’s see why. In PEP 328 (Imports: Multi-Line and Absolute/Relative), we can find how the python interpreter should resolve the relative modules.

Why do I get import error when importing a package?

It just causes a different type of ImportError. As the most popular answer suggests, basically its because your PYTHONPATH or sys.path includes . but not your path to your package. And the relative import is relative to your current working directory, not the file where the import happens; oddly.

How do I resolve relative imports?

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. Relative imports work from the filename ( __name__ attribute), which can take two values:

Can You import packages relatively inside a Python project?

You can import packages relatively inside a Python project. If you make a mistake in importing a package relatively, you’ll encounter the beyond top level package error in relative import error. In this guide, we’re going to discuss what this error means and why it is raised.


Video Answer


4 Answers

EDIT: There are better/more coherent answers to this question in other questions:

  • Sibling package imports
  • Relative imports for the billionth time

Why doesn't it work? It's because python doesn't record where a package was loaded from. So when you do python -m test_A.test, it basically just discards the knowledge that test_A.test is actually stored in package (i.e. package is not considered a package). Attempting from ..A import foo is trying to access information it doesn't have any more (i.e. sibling directories of a loaded location). It's conceptually similar to allowing from ..os import path in a file in math. This would be bad because you want the packages to be distinct. If they need to use something from another package, then they should refer to them globally with from os import path and let python work out where that is with $PATH and $PYTHONPATH.

When you use python -m package.test_A.test, then using from ..A import foo resolves just fine because it kept track of what's in package and you're just accessing a child directory of a loaded location.

Why doesn't python consider the current working directory to be a package? NO CLUE, but gosh it would be useful.

like image 108
Multihunter Avatar answered Oct 07 '22 17:10

Multihunter


import sys
sys.path.append("..") # Adds higher directory to python modules path.

Try this. Worked for me.

like image 30
jenish Sakhiya Avatar answered Oct 07 '22 15:10

jenish Sakhiya


Assumption:
If you are in the package directory, A and test_A are separate packages.

Conclusion:
..A imports are only allowed within a package.

Further notes:
Making the relative imports only available within packages is useful if you want to force that packages can be placed on any path located on sys.path.

EDIT:

Am I the only one who thinks that this is insane!? Why in the world is the current working directory not considered to be a package? – Multihunter

The current working directory is usually located in sys.path. So, all files there are importable. This is behavior since Python 2 when packages did not yet exist. Making the running directory a package would allow imports of modules as "import .A" and as "import A" which then would be two different modules. Maybe this is an inconsistency to consider.

like image 56
User Avatar answered Oct 07 '22 16:10

User


None of these solutions worked for me in 3.6, with a folder structure like:

package1/
    subpackage1/
        module1.py
package2/
    subpackage2/
        module2.py

My goal was to import from module1 into module2. What finally worked for me was, oddly enough:

import sys
sys.path.append(".")

Note the single dot as opposed to the two-dot solutions mentioned so far.


Edit: The following helped clarify this for me:

import os
print (os.getcwd())

In my case, the working directory was (unexpectedly) the root of the project.

like image 45
Jason DeMorrow Avatar answered Oct 07 '22 17:10

Jason DeMorrow