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

Posted on

Solving problem is about exposing yourself to as many situations as possible like How to fix “Attempted relative import in non-package” even with __init__.py and practice these strategies over and over. With time, it becomes second nature and a natural way you approach any problems in general. Big or small, always start with a plan, use other strategies mentioned here till you are confident and ready to code the solution.
In this post, my aim is to share an overview the topic about How to fix “Attempted relative import in non-package” even with __init__.py, which can be followed any time. Take easy to follow this discuss.

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

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?

Answer #1:

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

python -m pkg.tests.core_test

Answer #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.

Answered By: BrenBarn

Answer #3:

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__))))
Answered By: ihm

Answer #4:

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
Answered By: Paolo Rovelli

Answer #5:

In core_test.py, do the following:

import sys
sys.path.append('../components')
from core import GameLoopEvents
Answered By: Allan Mwesigwa

Answer #6:

If your use case is for running tests, and it seams that it is, then you can do the following. Instead of running your test script as python core_test.py use a testing framework such as pytest. Then on the command line you can enter

$$ py.test

That will run the tests in your directory. This gets around the issue of __name__ being __main__ that was pointed out by @BrenBarn. Next, put an empty __init__.py file into your test directory, this will make the test directory part of your package. Then you will be able to do

from ..components.core import GameLoopEvents

However, if you run your test script as a main program then things will fail once again. So just use the test runner. Maybe this also works with other test runners such as nosetests but i haven’t checked it. Hope this helps.

Answered By: deepak

Answer #7:

My quick-fix is to add the directory to the path:

import sys
sys.path.insert(0, '../components/')
Answered By: v4gil

Answer #8:

Issue is with your testing method,

you tried python core_test.py

then you will get this error
ValueError: Attempted relative import in non-package

Reason: you are testing your packaging from non-package source.

so test your module from package source.

if this is your project structure,

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

cd pkg

python -m tests.core_test # dont use .py

or from outside pkg/

python -m pkg.tests.core_test

single . if you want to import from folder in same directory .
for each step back add one more.

hi/
  hello.py
how.py

in how.py

from .hi import hello

incase if you want to import how from hello.py

from .. import how

Leave a Reply

Your email address will not be published. Required fields are marked *