[Python-Dev] Broken import?

Guido van Rossum guido at python.org
Tue Mar 31 01:17:53 CEST 2009


[Adding python-dev. I'm quoting the entire original message.]

> On Thu, Mar 19, 2009 at 6:40 PM, Fredrik Lundh <fredriklundh at google.com> wrote:
>> PS. Is it just me, or is import broken in 3.0?  Consider this:
>>
>> $ more package\a.py
>> print("in a")
>>
>> import b
>>
>> def a():
>>    print("here")
>>
>> def main():
>>    b.b()
>>
>> $ more package\b.py
>> print("in b")
>>
>> import a
>>
>> def b():
>>    a.a()
>>
>> Under 2.X, this prints "in a" "in b" and "here", as expected.  Under
>> 3.0, using the "from . import" form for relative imports, it bombs out
>> with a:
>>
>> in a
>> in b
>> Traceback (most recent call last):
>>  File "main.py", line 1, in <module>
>>    from package import a
>>  File "package/a.py", line 3, in <module>
>>    from . import b
>>  File "package\b.py", line 3, in <module>
>>    from . import a
>> ImportError: cannot import name a
>>
>> Sure, it's a recursive import, but there's no recursive dependency
>> here - nobody will access the module contents until the main program
>> calls the library.  What am I missing?

On Mon, Mar 30, 2009 at 5:44 PM, Guido van Rossum <guido at python.org> wrote:
> I reproduced this, but it seems to have more to do with "from . import
> ..." than with the Python version. If I add the "from ." before each
> of the imports, "python -c 'import p.a' " fails with roughly the above
> traceback for any version of Python that supports this syntax, while
> without that it passes for any 2.x.
>
> If I use the "from ." syntax in a.py but not in b.py, "import p.a"
> passes but "import p.b" fails.
>
> I'll see if anyone present at the sprints has a clue.

Made some progress. Anything using "from <whatever> import b" (where
<whatever> is either '.' or 'p') will fail when b's import is not
completed. OTOH using "import p.b" works. I reduced it to:

p/a.py == "from p import b"
p/b.py == "import a"
python -c "import p.b"

The reason seems to be that until the outermost import (in this case
p.b) is completed, while sys.modules has the (incomplete) modules 'p',
'p.a' and 'p.b', the attributes p.a and p.b aren't added until after
their import is completed. Which it isn't during recursive import.
Apparently 'from <anything> import <something>' looks for the
<something> attribute in the <parent> object. This is because
"from...import" can also be used to import objects other than modules
(e.g. "from M import C"). I'm guessing that setting the attribute is
delayed until the import is totally complete, because upon a failed
import we remove the half-imported module object from sys.modules, but
apparently we didn 't want to be in the business of removing the
attribute from the parent package, so that's only set after the import
is deemed successful.

At least, this is my hypothesis, thinking about it -- I might look at
the code later. :-)

The most portable solution is to avoid "from...import" and instead
write something like

import p.b as b

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list