Relative import from script with same name as package

O

OKB (not okblacke)

I'm using Python 2.6.5. I have a directory structure like this:

thetest/
__init__.py
thetest.py
theother.py

__init__.py is an empty file. theother.py contains a function foo().
The package is accessible from sys.path, so that if I open the
interpreter and do "import thetest" or "from thetest import thetest" or
"import thetest.thetest", it works fine.

Inside thetest.py I have code like this:

###
from __future__ import absolute_import

if __name__ == "__main__" and __package__ is None:
import thetest
__package__ = "thetest"

from .theother import foo
###

Note that I need the "import thetest" line to avoid a "parent
module not loaded" error, as described here:
http://stackoverflow.com/questions/2943847/nightmare-with-relative-
imports-how-does-pep-366-work

If I run foo.py directly, I receive a traceback like this:

Traceback (most recent call last):
File "C:\...\thetest\thetest.py", line 4, in <module>
import thetest
File "C:\...\thetest\thetest.py", line 11, in <module>
from .theother import foo
ValueError: Attempted relative import in non-package

It appears that Python is reading "import thetest" as importing
thetest.py (the same file that is currently being run). When it tries
to run that file a second time, the relative import fails.

But why? That __future__ import is supposed to make absolute
imports the default, so why is "import thetest" importing thetest.py
instead of the package called thetest? The absolute import should make
it look in sys.path first and not try to import from the script
directory, right?

If I change the outer directory name and change the code in
thetest.py to match, it works fine. But I shouldn't have to do this.
How can I get relative imports to work correctly when running a script
whose filename is the same as that of the directory (and thus the
package) in which it resides?

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
O

OKB (not okblacke)

OKB said:
But why? That __future__ import is supposed to make
absolute
imports the default, so why is "import thetest" importing
thetest.py instead of the package called thetest? The absolute
import should make it look in sys.path first and not try to import
from the script directory, right?

If I change the outer directory name and change the code
in
thetest.py to match, it works fine. But I shouldn't have to do
this. How can I get relative imports to work correctly when
running a script whose filename is the same as that of the
directory (and thus the package) in which it resides?

After a bit more googling I discovered the answer here:
http://stackoverflow.com/questions/1959188/absolute-import-failing-in-
subpackage-that-shadows-a-stdlib-package-name

The deal is that sys.path by default has the empty string as the
first element, which tells Python to look first in the directory of the
script being executed. This is unfortunate, but can worked around this
way:

import sys
sys.path = sys.path[1:] + ['']

(That is, move the current directory to the end of the search path
instead of the beginning.)

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 
C

Chris Angelico

sys.path = sys.path[1:] + ['']

(That is, move the current directory to the end of the search path
instead of the beginning.)

Or, equivalently:

sys.path.append(sys.path.pop(0))

ChrisA
 
O

OKB (not okblacke)

=?UTF-8?B?T2t0YXkgxZ5hZmFr?= said:
No, there is no such thing happening. Read the error message more
carefully: the error happens when your code reaches the line "from
.theother import foo", and it fails because you are trying to
execute an "explicit" relative import statement (with leading dot
notation) as introduced by PEP 328. What you see is perfectly
expected behaviour as explained in detail in the PEP because the
python interpreter can only make sense of that statement if that
code is *imported* for use by code that resides *outside* the
package. That error message is what you see when you try to *run* a
package member module which uses explicit relative imports. Let me
try to explain a bit further:

Yes, such a thing was happening. (I described the fix in an
answer to my own post.) You should read PEP 366 to understand what I
was talking about, and what the __package__ variable does.

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,829
Messages
2,569,737
Members
45,521
Latest member
maryb

Latest Threads

Top