classification
Title: Identifier lookup in a multi-level package is flakey
Type: compile error Stage:
Components: Interpreter Core Versions: Python 3.4, Python 2.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: SegundoBob, martin.panter, r.david.murray
Priority: normal Keywords:

Created on 2015-08-27 22:59 by SegundoBob, last changed 2015-08-31 21:58 by SegundoBob.

Messages (5)
msg249269 - (view) Author: Bob Hossley (SegundoBob) Date: 2015-08-27 22:59
This seems like a bug to me, but it may be a recognized limitation even though I couldn't find any documentation suggesting that my tests should not work reliably.  I see no reason why my tests should not work reliably.

I have reliably reproduced the flakeyness under Windows XP with Python 2.6.4 and under Xubuntu 14.04 64-bit with Python 2.7.6 and Python 3.4.0.

Ubuntu 14.04 (trusty)  - XFCE desktop (Xubuntu) 64-bit
Gnome:  3.8.4
Kernel:  3.13.0-62-generic
GCC Version:  4.8 (x86_64-linux-gnu)
Xorg Version:  1.15.1 (12 February 2015  02:49:29PM)

Rebooting doesn't help.

I first encountered the flakeyness in a complicated script which I will describe in outline first.  The very, very simple interactive Python sessions that follow are probably of more interest and use to you.
---
Outline of my complicated script:

import email
    
    # The next line works around a flakeyness in Python    
    from email.mime.nonmultipart import MIMENonMultipart
    
    msg = email.mime.nonmultipart.MIMENonMultipart('text', 'plain', charset='utf-8')

Without the above work around I always get Error:

AttributeError: 'module' object has no attribute 'nonmultipart'

Note "import email" is global.  "from email.mime.nonmultipart import MIMENonMultipart" is local to the function containing the "msg = " line which is the line that fails whenever the workaround is absent.
---
XP Interpreter Session:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Admin>python
Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import email
>>> print email.mime.nonmultipart.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> print email.mime.nonmultipart.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> print email.mime.nonmultipart.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> print email.mime.nonmultipart.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> print email.mime.nonmultipart.__file__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> from email.mime import nonmultipart
>>> print email.mime.nonmultipart.__file__
C:\bin\Python26\lib\email\mime\nonmultipart.pyc
>>>

Xubuntu Python 2.7.6 Session

2015-08-25 14:02:46 /home/bob06
$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import email
>>> print(email.mime.nonmultipart.__file__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'nonmultipart'
>>> print(email.mime.nonmultipart.__file__)
/usr/lib/python2.7/email/mime/nonmultipart.pyc


Xubuntu Python 3.4.0 Session

2015-08-27 15:27:39 /home/bob06
$ python3
Python 3.4.0 (default, Jun 19 2015, 14:20:21) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import email
>>> print(email.mime.nonmultipart.__file__)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'mime'
>>> print(email.mime.nonmultipart.__file__)
/usr/lib/python3.4/email/mime/nonmultipart.py
msg249271 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2015-08-28 00:27
It should not be the case that email.mime.nonmultipart gets imported unless you import it explicitly.  I can't reproduce your case of trying to access its __file__ attribute and having it succeed the second time.  There must be something unusual about your setup or your linux distribution.
msg249272 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2015-08-28 03:11
It sounds like you are trying to do a plain “import email”, and then expect all the submodules under that package to work, including “email.mime.nonmultipart”. That is not how it works. I understand the submodules and subpackages are only initialized if you ask for them explicitly. Hence the “no attribute 'mime' ” error in 3.4.

In your case perhaps you should change or extend the import statement to do

import email.mime.nonmultipart

The reason why your “from . . . import” works is it also initializes the submodule that you want, and stores it in a chain of attributes of the top-level module as a side effect.

Quickly scanning through <https://docs.python.org/3/tutorial/modules.html#packages>, <https://docs.python.org/3/reference/import.html#packages>, <https://docs.python.org/3/reference/simple_stmts.html#import>, I didn’t see anything obvious pointing out that importing a top-level package doesn’t completely initialize the whole thing. But maybe there is something already there. You might have to read about how the __init__.py internals work to pick it up.
msg249431 - (view) Author: Bob Hossley (SegundoBob) Date: 2015-08-31 21:56
msg<249269>

Thank you David Murray.

I should have asked myself, what is reasonable behavior?  In the case of email.mime.nonmultipart an explicit import is clearly needed.

I was misled by my experience with the os library.  As a "package" it is very different from the email library.  Importing os also makes available all of what appear at the script syntax level to be all its "sub-packages."

2015-08-28 09:57:26 /home/bob06
$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> print(os.path.split)
<function split at 0x7fac18704320>

In the future I will try to remember that the effects of importing a "package" depend on how the "package" is packaged.

So far as I'm concerned this issue is closed.

I doubt that symptom "flakey Python behavior" is serious enough to interest Canonical.
msg249432 - (view) Author: Bob Hossley (SegundoBob) Date: 2015-08-31 21:58
msg249272

Thank you Martin Panter for the documentation URL's.  The import machinery is so complicated that I have given up trying to understand what is "correct" behavior.    Depending on the code in the relevant __init__.py and/or explicitly referenced Python modules each Python library can have vastly different import behavior.  I believe the simplest way to figure out what an import does and hence, what import statements I need is to run a Python interpreter in a terminal, execute an import statement, and then use the dir() function several times to see what the import statement did.

The import documentation is only slightly useful due to its great length and complexity.
History
Date User Action Args
2015-08-31 21:58:20SegundoBobsetmessages: + msg249432
2015-08-31 21:56:32SegundoBobsetmessages: + msg249431
2015-08-28 03:11:48martin.pantersetnosy: + martin.panter
messages: + msg249272
2015-08-28 00:28:00r.david.murraysetnosy: + r.david.murray
messages: + msg249271
2015-08-27 22:59:22SegundoBobcreate