How to fix "Attempted relative import in non-package" even with __init__.py
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
skytreader
Chocolate-consuming, code-churning creature. Check my code at GitHub. #SOreadytohelp ... I hope I'm doing this right!
Updated on July 27, 2022Comments
-
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 statementfrom ..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 over 11 yearsA gotcha: Note that there is no '.py' at the end!
-
Aram Kocharyan over 11 yearsTook a while for me to realize you can't run
python -m core_test
from within thetests
subdirectory - it has to be from the parent, or you have to add the parent to the path. -
Danny Staple almost 11 yearsSo 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 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 almost 11 yearsI 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 almost 11 years@DannyStaple: Well, how it works is described in the linked documentation. If you have a script
script.py
in packagepack.subpack
, then setting it's__package__
topack.subpack
will let you dofrom ..module import something
to import something frompack.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 over 10 years
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
this will also work -
flying sheep over 10 years
from os import sys
looks like cheating :) -
Mark Amery over 10 yearsI'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__.py
s 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 over 10 years@ajay And yours is better because of what?
-
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 about 10 years@martineau I think you are right :)
-
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 about 10 years@flyingsheep: Agreed, I'd just use a regular
import sys, os.path as path
. -
Racing Tadpole about 10 yearsFYI, 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 straightimport components.core
works for me, importing from the notebook's parent directory as desired. -
andy about 9 yearsGreat things for nested usage of
dirname
function. Haven't seen that before. -
J Richard Snape almost 9 yearsThere is a nicely elaborated recent answer below with a link to the docs as suggested by the upvoted comment.
-
danny almost 9 yearswhat 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 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 over 8 yearsNote: 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 insidepkg
and you callpython -m tests.core_test
, it will not work. At least it didn't for me. -
Ville Miekk-oja over 8 yearsThis does not work if you run the script inside components dir for example
-
shad0w_wa1k3r over 8 yearsI coupled this with
cd
ing 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 about 8 yearsIs it better to use
insert
instead ofappend
? That is,sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
Jonathan Ray about 8 yearsWhen 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 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 beusr.share.someapp.somescript
? -
Alison S about 8 yearsThere is no sample code in the PEP-0366 linked documentation @BrenBarn. Where can I find sample code?
-
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 about 8 yearsBut 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 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 almost 8 yearsSeriously, can you explain whats going on in your answer?
-
Stefan Monov almost 8 yearsHow does
from os import sys
work?os
is a module outside thesys
module. -
Alex Dupuy almost 8 yearsUsing 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 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 theValueError: 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 over 7 yearsyou 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 over 7 yearsYour 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 over 7 yearsContrary to the answer for an FAQ in Python this answer gives no clue what is happening and from where to execute this command
-
mononoke over 6 yearsI 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 over 6 yearsMay 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 over 5 yearsfor running on jupyter notebook %run <filename/path> -m
-
user2589273 about 5 yearsI'm not sure how running it as a module helps @skytreader 's import problem from within another script...
-
Mohammad Mahjoub about 5 yearsThis did not work for me. Did you have to set the path in your configuration?
-
Philip about 5 yearsMaybe 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 almost 5 yearsdoing sys.path.append is not cool to do because generating a standalone installer with pyinstall... fails miserably. I switched to file system links
-
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 over 4 yearsI don't think having
if __name__ == "__main__"
in your file makes a difference to anything related to importing. -
James Hulse about 4 yearsIn the example
from .. import how
, how do you import a specific class / method from the 'how' file. when I do the equivalent offrom ..how import foo
then I get "attempted relative import beyond top-level package" -
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 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 almost 3 yearsWhat does the answer actually mean?
-
Shi B. almost 3 yearsThis is a seriously undervalued gem! I can't understand why there are not enough up-votes to make this answer near the top!
-
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 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 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 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.