How to fix "Attempted relative import in non-package" even with __init__.py

586,607

Solution 1

Yes. You're not using it as a package.

python -m pkg.tests.core_test

Solution 2

To elaborate on Ignacio Vazquez-Abrams's answer:

The Python import mechanism works relative to the __name__ of the current file. When you execute a file directly, it doesn't have its usual name, but has "__main__" as its name instead. So relative imports don't work.

You can, as Igancio suggested, execute it using the -m option. If you have a part of your package that is meant to be run as a script, you can also use the __package__ attribute to tell that file what name it's supposed to have in the package hierarchy.

See http://www.python.org/dev/peps/pep-0366/ for details.

Solution 3

It depends on how you want to launch your script.

If you want to launch your UnitTest from the command line in a classic way, that is:

python tests/core_test.py

Then, since in this case 'components' and 'tests' are siblings folders, you can import the relative module either using the insert or the append method of the sys.path module. Something like:

import sys
from os import path
sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
from components.core import GameLoopEvents

Otherwise, you can launch your script with the '-m' argument (note that in this case, we are talking about a package, and thus you must not give the '.py' extension), that is:

python -m pkg.tests.core_test

In such a case, you can simply use the relative import as you were doing:

from ..components.core import GameLoopEvents

You can finally mix the two approaches, so that your script will work no matter how it is called. For example:

if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )
        from components.core import GameLoopEvents
    else:
        from ..components.core import GameLoopEvents

Solution 4

You can use import components.core directly if you append the current directory to sys.path:

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))

Solution 5

In core_test.py, do the following:

import sys
sys.path.append('../components')
from core import GameLoopEvents
Share:
586,607
skytreader
Author by

skytreader

Chocolate-consuming, code-churning creature. Check my code at GitHub. #SOreadytohelp ... I hope I'm doing this right!

Updated on July 27, 2022

Comments

  • skytreader
    skytreader almost 2 years

    I'm trying to follow PEP 328, with the following directory structure:

    pkg/
      __init__.py
      components/
        core.py
        __init__.py
      tests/
        core_test.py
        __init__.py
    

    In core_test.py I have the following import statement

    from ..components.core import GameLoopEvents
    

    However, when I run, I get the following error:

    tests$ python core_test.py 
    Traceback (most recent call last):
      File "core_test.py", line 3, in <module>
        from ..components.core import GameLoopEvents
    ValueError: Attempted relative import in non-package
    

    Searching around I found "relative path not working even with __init__.py" and "Import a module from a relative path" but they didn't help.

    Is there anything I'm missing here?

  • mindthief
    mindthief over 11 years
    A gotcha: Note that there is no '.py' at the end!
  • Aram Kocharyan
    Aram Kocharyan over 11 years
    Took a while for me to realize you can't run python -m core_test from within the tests subdirectory - it has to be from the parent, or you have to add the parent to the path.
  • Danny Staple
    Danny Staple almost 11 years
    So can I therefore use package to ensure executable script files are able to relative import from the rest of the system regardless of their level in the hierarchy? This would be very useful indeed.
  • BrenBarn
    BrenBarn almost 11 years
    @DannyStaple: Not exactly. You can use __package__ to ensure executable script files can relatively import other modules from within the same package. There's no way to relatively import from "the whole system". I'm not even sure why you'd want to do this.
  • Danny Staple
    Danny Staple almost 11 years
    I mean if the __package__ symbol is set to "parent.child" then you'd be able to import "parent.other_child". Perhaps I didn't phrase it so well.
  • BrenBarn
    BrenBarn almost 11 years
    @DannyStaple: Well, how it works is described in the linked documentation. If you have a script script.py in package pack.subpack, then setting it's __package__ to pack.subpack will let you do from ..module import something to import something from pack.module. Note that, as the documentation says, you still have to have the top-level package on the system path. This is already the way things work for imported modules. The only thing __package__ does is let you use that behavior for directly-executed scripts as well.
  • ajay
    ajay over 10 years
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname‌​(__file__), '..'))) this will also work
  • flying sheep
    flying sheep over 10 years
    from os import sys looks like cheating :)
  • Mark Amery
    Mark Amery over 10 years
    I'm not either of the downvoters, but I feel this could use quite a bit more detail, given the popularity of this question and answer. Noting stuff like from what directory to execute the above shell command, the fact that you need __init__.pys all the way down, and the __package__-modifying trickery (described below by BrenBarn) needed to allow these imports for executable scripts (e.g. when using a shebang and doing ./my_script.py at the Unix shell) would all be useful. This whole issue was quite tricky for me to figure out or find concise and understandable documentation on.
  • Piotr Dobrogost
    Piotr Dobrogost over 10 years
    @ajay And yours is better because of what?
  • martineau
    martineau about 10 years
    @Piotr: It's might be considered better because it slightly shows more clearly what is being being appended to sys.path -- the parent of the directory the current file is in.
  • Piotr Dobrogost
    Piotr Dobrogost about 10 years
    @martineau I think you are right :)
  • martineau
    martineau about 10 years
    @Piotr: Ah, yes, I would have to agree that sys.path.append(path.dirname(path.dirname(__file__))) would be even more clear -- and with a comment, perfect.
  • martineau
    martineau about 10 years
    @flyingsheep: Agreed, I'd just use a regular import sys, os.path as path.
  • Racing Tadpole
    Racing Tadpole about 10 years
    FYI, to use this in an ipython notebook, I adapted this answer to: import os; os.sys.path.append(os.path.dirname(os.path.abspath('.'))). Then a straight import components.core works for me, importing from the notebook's parent directory as desired.
  • andy
    andy about 9 years
    Great things for nested usage of dirname function. Haven't seen that before.
  • J Richard Snape
    J Richard Snape almost 9 years
    There is a nicely elaborated recent answer below with a link to the docs as suggested by the upvoted comment.
  • danny
    danny almost 9 years
    what shall i do if i am trying to use the pdb for debugging? since you use python -m pdb myscript.py to launch the debugging session.
  • mgilson
    mgilson almost 9 years
    @dannynjust -- That's a good question since you can't have 2 main modules. Generally when debugging, I prefer to drop into the debugger manually at the first point where I want to start debugging. You can do that by inserting a import pdb; pdb.set_trace() into the code (inline).
  • Blairg23
    Blairg23 over 8 years
    Note: you need to be outside of the directory pkg at the point where you call this line from the CLI. Then, it should work as expected. If you are inside pkg and you call python -m tests.core_test, it will not work. At least it didn't for me.
  • Ville Miekk-oja
    Ville Miekk-oja over 8 years
    This does not work if you run the script inside components dir for example
  • shad0w_wa1k3r
    shad0w_wa1k3r over 8 years
    I coupled this with cding into the project's parent directory. cd /path/to/project && python -m project.module.submodule. You may want to add && cd ~ in the end if you are testing this out multiple times on local system.
  • SparkAndShine
    SparkAndShine about 8 years
    Is it better to use insert instead of append? That is, sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
  • Jonathan Ray
    Jonathan Ray about 8 years
    When they designed the language, why didn't they just make "python pkg/test/core_test.py" do the same thing as "python -m pkg.test.core_test"? Why do they deliberately break relative imports whenever you run anything as a script?
  • Ignacio Vazquez-Abrams
    Ignacio Vazquez-Abrams about 8 years
    @JonathanRay: Because having them do the same thing makes execution ambiguous; what sense does it make for python /usr/share/someapp/somescript.py to be usr.share.someapp.somescript?
  • Alison S
    Alison S about 8 years
    There is no sample code in the PEP-0366 linked documentation @BrenBarn. Where can I find sample code?
  • BrenBarn
    BrenBarn about 8 years
    @AlisonS: Sample code to do what? There is a small snippet in the PEP that explains how to set __package__.
  • Alison S
    Alison S about 8 years
    But there is no context to where that snippet belongs @BrenBarn. Does it go in the file you're importing? In the file that is doing the import? Where in the relevant file does it go?
  • BrenBarn
    BrenBarn about 8 years
    @AlisonS: It says right there: "To allow relative imports when the module is executed directly, boilerplate similar to the following would be needed before the first relative import statement". I think that is pretty clear that you put it in the module you are executing directly, before that module attempts any relative imports.
  • Charlie Parker
    Charlie Parker almost 8 years
    Seriously, can you explain whats going on in your answer?
  • Stefan Monov
    Stefan Monov almost 8 years
    How does from os import sys work? os is a module outside the sys module.
  • Alex Dupuy
    Alex Dupuy almost 8 years
    Using insert is a better match for the relative import semantics, where local package names take precedence over installed packages. Especially for tests, you usually want to test the local version, not the installed one (unless your test infrastructure installs the code under test, in which case relative imports are unneeded and you won't have this problem).
  • AdjunctProfessorFalcon
    AdjunctProfessorFalcon almost 8 years
    @MarkAmery Almost lost my mind trying to grok how all this works, relative imports within a project with subdirectories with py files that have __init__.py files yet you keep getting the ValueError: Attempted relative import in non-package error. I would pay really good money for someone, somewhere, to finally explain in plain English how all of this works.
  • Joseph Garvin
    Joseph Garvin over 7 years
    you should also mention that you can't be in the directory containing core_test when you run as a module (that would be too easy)
  • xyman
    xyman over 7 years
    Your approach wont work in all cases because '../' part is resolved from directory from which you run your script(core_test.py). With your approach you are forced to cd to 'tests' before running the core_test.py scritp.
  • Prahalad Deshpande
    Prahalad Deshpande over 7 years
    Contrary to the answer for an FAQ in Python this answer gives no clue what is happening and from where to execute this command
  • mononoke
    mononoke over 6 years
    I use __package__ in the script which is executed directly but Unfortunately, I get the the following error: "Parent module 'xxx' not loaded, cannot perform relative import"
  • Jabb
    Jabb over 6 years
    May I add another trick... I tried every advise that I could find on SO regarding a similar issue and finally found that I had some old .pyc files that were causing conflicts. So if anyone tries the above solution and it fails, check if you need to delete your .pyc files.
  • Eswar
    Eswar over 5 years
    for running on jupyter notebook %run <filename/path> -m
  • user2589273
    user2589273 about 5 years
    I'm not sure how running it as a module helps @skytreader 's import problem from within another script...
  • Mohammad Mahjoub
    Mohammad Mahjoub about 5 years
    This did not work for me. Did you have to set the path in your configuration?
  • Philip
    Philip about 5 years
    Maybe I don't really understand the cultural norms around the wiki-like features on SO, but it's notable that no one pointing out how Ignacio's answer could be improved actually improved it in-place. (Mind you, I agree 100% with the comments that an explanation would be extremely helpful.)
  • mhstnsc
    mhstnsc almost 5 years
    doing sys.path.append is not cool to do because generating a standalone installer with pyinstall... fails miserably. I switched to file system links
  • subtleseeker
    subtleseeker over 4 years
    -m flag is used to run the file as a script. It indicates the module name and starts from the parent module and goes deeper in the directory to run the script.
  • user48956
    user48956 over 4 years
    I don't think having if __name__ == "__main__" in your file makes a difference to anything related to importing.
  • James Hulse
    James Hulse about 4 years
    In the example from .. import how, how do you import a specific class / method from the 'how' file. when I do the equivalent of from ..how import foo then I get "attempted relative import beyond top-level package"
  • Isi
    Isi over 3 years
    @JamesHulse Does from .. import how work but the second statement not? I would have assumed that both statements won't work, if the folder that contains the hi folder does not contain an _ _ init _ _.py file. In other words, if there is only an init file in the hi folder, then the hi folder is the top level package and you cannot address beyond it.
  • Isi
    Isi over 3 years
    @MohammadMahjoub You need all the init files that he also has to make this work... Don't forget the one in cnn_scratch
  • Cyebukayire
    Cyebukayire almost 3 years
    What does the answer actually mean?
  • Shi B.
    Shi B. almost 3 years
    This is a seriously undervalued gem! I can't understand why there are not enough up-votes to make this answer near the top!
  • Nevermore
    Nevermore about 2 years
    @Philip Probably because no one actually knows how or why it works? That's the reason people want OP to add detail to the answer. If people already knew the details, they wouldn't need OP to add the detail themselves.
  • Philip
    Philip almost 2 years
    @Nevermore -- fair point. My perception is probably biased slightly by my observation people seem generally slow to view the questions as wiki-like. And I don't want to start riding roughshod over cultural norms.
  • Karl Knechtel
    Karl Knechtel almost 2 years
    @AramKocharyan aside from hacking the path within the script, it should also work to set the PYTHONPATH environment variable appropriately.
  • Karl Knechtel
    Karl Knechtel almost 2 years
    @Philip part of the problem is that answers (and questions) accumulate reputation for the original author over time, which isn't shared by editors. Even if it were, there wouldn't be a tractable way to assess how much of the credit should go to each participant. There are some norms around authorial intent, but I honestly think people are mainly held back by a poor incentive structure.