Categories
import python python-packaging relative-import relative-path

Relative imports for the billionth time

1398

I’ve been here:

and plenty of URLs that I did not copy, some on SO, some on other sites, back when I thought I’d have the solution quickly.

The forever-recurring question is this: how do I solve this “Attempted relative import in non-package” message?

ImportError: attempted relative import with no known parent package

I built an exact replica of the package on pep-0328:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

The imports were done from the console.

I did make functions named spam and eggs in their appropriate modules. Naturally, it didn’t work. The answer is apparently in the 4th URL I listed, but it’s all alumni to me. There was this response on one of the URLs I visited:

Relative imports use a module’s name attribute to determine that module’s position in the package hierarchy. 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 above response looks promising, but it’s all hieroglyphs to me. So my question, how do I make Python not return to me “Attempted relative import in non-package”? has an answer that involves -m, supposedly.

Can somebody please tell me why Python gives that error message, what it means by “non-package”, why and how do you define a ‘package’, and the precise answer put in terms easy enough for a kindergartener to understand.

16

  • 6

    How are you attempting to use the files you show? What is the code you are running?

    – BrenBarn

    Jan 3, 2013 at 3:51

  • 7

    See my answer. You still haven’t fully clarified what you’re doing, but if you’re trying to do from .something import something in the interactive interpreter, that won’t work. Relative imports can only be used within modules, not interactively.

    – BrenBarn

    Jan 3, 2013 at 4:47

  • 543

    The mere fact that “billions” of people — ok 83,136 as of this comment — are having enough difficulty with imports to search out this question; we can only conclude that python imports are counter-intuitive for many, if not most programmers. Guido, perhaps you should accept this and ask for a committee to redesign the import mechanism. At a minimum, this syntax ought to work if x.py and z.py are in the same directory. Namely if x.py has the statement, “from .z import MyZebraClass” x should import z EVEN if it’s being run as main! Why is that so hard?

    – Steve L

    Sep 11, 2018 at 16:53


  • 27

    After reading through much of this thread, although not an answer to the question, “just use absolute imports” seems to be the solution…

    Nov 20, 2018 at 15:03

  • 4

    @SteveL It’s closer to “billlions” now: 404k. And I’m pretty sure this is not my first visit.

    Apr 11 at 20:21

1828

Script vs. Module

Here’s an explanation. The short version is that there is a big difference between directly running a Python file, and importing that file from somewhere else. Just knowing what directory a file is in does not determine what package Python thinks it is in. That depends, additionally, on how you load the file into Python (by running or by importing).

There are two ways to load a Python file: as the top-level script, or as a
module. A file is loaded as the top-level script if you execute it directly, for instance by typing python myfile.py on the command line. It is loaded as a module when an import statement is encountered inside some other file. There can only be one top-level script at a time; the top-level script is the Python file you ran to start things off.

Naming

When a file is loaded, it is given a name (which is stored in its __name__ attribute).

  • If it was loaded as the top-level script, its name is __main__.
  • If it was loaded as a module, its name is [ the filename, preceded by the names of any packages/subpackages of which it is a part, separated by dots ], for example, package.subpackage1.moduleX.

But be aware, if you load moduleX as a module from shell command line using something like python -m package.subpackage1.moduleX, the __name__ will still be __main__.

So for instance in your example:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

if you imported moduleX (note: imported, not directly executed), its name would be package.subpackage1.moduleX. If you imported moduleA, its name would be package.moduleA. However, if you directly run moduleX from the command line, its name will instead be __main__, and if you directly run moduleA from the command line, its name will be __main__. When a module is run as the top-level script, it loses its normal name and its name is instead __main__.

Accessing a module NOT through its containing package

There is an additional wrinkle: the module’s name depends on whether it was imported “directly” from the directory it is in or imported via a package. This only makes a difference if you run Python in a directory, and try to import a file in that same directory (or a subdirectory of it). For instance, if you start the Python interpreter in the directory package/subpackage1 and then do import moduleX, the name of moduleX will just be moduleX, and not package.subpackage1.moduleX. This is because Python adds the current directory to its search path when the interpreter is entered interactively; if it finds the to-be-imported module in the current directory, it will not know that that directory is part of a package, and the package information will not become part of the module’s name.

A special case is if you run the interpreter interactively (e.g., just type python and start entering Python code on the fly). In this case, the name of that interactive session is __main__.

Now here is the crucial thing for your error message: if a module’s name has no dots, it is not considered to be part of a package. It doesn’t matter where the file actually is on disk. All that matters is what its name is, and its name depends on how you loaded it.

Now look at the quote you included in your question:

Relative imports use a module’s name attribute to determine that module’s position in the package hierarchy. 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…

Relative imports use the module’s name to determine where it is in a package. When you use a relative import like from .. import foo, the dots indicate to step up some number of levels in the package hierarchy. For instance, if your current module’s name is package.subpackage1.moduleX, then ..moduleA would mean package.moduleA. For a from .. import to work, the module’s name must have at least as many dots as there are in the import statement.

… are only relative in a package

However, if your module’s name is __main__, it is not considered to be in a package. Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the “relative-import in non-package” error.

Scripts can’t import relative

What you probably did is you tried to run moduleX or the like from the command line. When you did this, its name was set to __main__, which means that relative imports within it will fail, because its name does not reveal that it is in a package. Note that this will also happen if you run Python from the same directory where a module is, and then try to import that module, because, as described above, Python will find the module in the current directory “too early” without realizing it is part of a package.

Also remember that when you run the interactive interpreter, the “name” of that interactive session is always __main__. Thus you cannot do relative imports directly from an interactive session. Relative imports are only for use within module files.

Two solutions:

  1. If you really do want to run moduleX directly, but you still want it to be considered part of a package, you can do python -m package.subpackage1.moduleX. The -m tells Python to load it as a module, not as the top-level script.

  2. Or perhaps you don’t actually want to run moduleX, you just want to run some other script, say myfile.py, that uses functions inside moduleX. If that is the case, put myfile.py somewhere elsenot inside the package directory – and run it. If inside myfile.py you do things like from package.moduleA import spam, it will work fine.

Notes

  • For either of these solutions, the package directory (package in your example) must be accessible from the Python module search path (sys.path). If it is not, you will not be able to use anything in the package reliably at all.

  • Since Python 2.6, the module’s “name” for package-resolution purposes is determined not just by its __name__ attributes but also by the __package__ attribute. That’s why I’m avoiding using the explicit symbol __name__ to refer to the module’s “name”. Since Python 2.6 a module’s “name” is effectively __package__ + '.' + __name__, or just __name__ if __package__ is None.)

27

  • 272

    This should be the answer to all Python relative imports questions. This should be in the docs, even.

    – edsioufi

    May 13, 2014 at 19:19

  • 14

    See python.org/dev/peps/pep-0366 — “Note that this boilerplate is sufficient only if the top level package is already accessible via sys.path . Additional code that manipulates sys.path would be needed in order for direct execution to work without the top level package already being importable.” — this is the most disturbing bit to me since this “additional code” is actually quite long and can’t be stored elsewhere in package to run easily.

    Aug 29, 2015 at 8:04

  • 27

    I keep coming back to this post despite being a Python veteran. The main message for me is: Either fiddle around with sys.path and __package__ (which is rather ugly, see the other answers) or simply create a “main script” main.py in the root directory of your project and put all modules to be imported in subdirectories. main.py can then access all modules directly through their package names (= the names of the respective folders they’re in).

    – balu

    Mar 27, 2017 at 12:29

  • 42

    This answer is currently off on a few important details regarding __name__ and sys.path. Specifically, with python -m pkg.mod, __name__ is set to __main__, not pkg.mod; relative imports are resolved using __package__ rather than __name__ in this case. Also, Python adds the script’s directory rather than the current directory to sys.path when running python path/to/script.py; it adds the current directory to sys.path when running most other ways, including python -m pkg.mod.

    Oct 5, 2018 at 19:22


  • 12

    Finally understand after hours of reading… Worth noting that code under if __name__ == '__main__' will still run when using -m. See the comment from @user2357112

    – adamF

    Jan 22, 2019 at 20:18


78

This is really a problem within python. The origin of confusion is that people mistakenly takes the relative import as path relative which is not.

For example when you write in faa.py:

from .. import foo

This has a meaning only if faa.py was identified and loaded by python, during execution, as a part of a package. In that case,the module’s name
for faa.py would be for example some_packagename.faa. If the file was loaded just because it is in the current directory, when python is run, then its name would not refer to any package and eventually relative import would fail.

A simple solution to refer modules in the current directory, is to use this:

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo

1

  • 13

    The correct solution is from __future__ import absolute_import and force the user to use your code correctly… so that you can always do from . import foo

    Jul 16, 2018 at 12:13

15

There are too much too long anwers in a foreign language. So I’ll try to make it short.

If you write from . import module, opposite to what you think, module will not be imported from current directory, but from the top level of your package! If you run .py file as a script, it simply doesn’t know where the top level is and thus refuses to work.

If you start it like this py -m package.module from the directory above package, then python knows where the top level is. That’s very similar to java: java -cp bin_directory package.class

2

  • 2

    This is in @BrenBarn’s answer, but it’s the TL;DR of it. OP and anyone else looking for answers, this is it. Took me forever to find this elsewhere.

    Jun 11, 2021 at 19:48

  • What is even more confusing is that when you install a package, absolute imports don’t work for me. i need to use from .submodule import module. When i use import submodule.module or from submodule import module, it can’t be found, even when the folder is right in the package folder.

    – Spartan

    Jun 17 at 17:53