After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 664432 - Erroneous ImportError from __import__ used in package module
Erroneous ImportError from __import__ used in package module
Status: RESOLVED FIXED
Product: reinteract
Classification: Other
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: reinteract-maint
reinteract-maint
Depends on:
Blocks:
 
 
Reported: 2011-11-20 18:37 UTC by Alain Kalker
Modified: 2011-12-01 05:24 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Reinteract notebook for testing __import__ (630 bytes, application/x-gzip)
2011-11-21 21:16 UTC, Alain Kalker
  Details
Don't worry if we can't find fromlist items during __import__ (1.29 KB, patch)
2011-11-22 03:34 UTC, Robert Schroll
committed Details | Review
Notebook: catch when loading a parent module loads the child (1.29 KB, patch)
2011-12-01 04:06 UTC, Owen Taylor
committed Details | Review

Description Alain Kalker 2011-11-20 18:37:06 UTC
How to reproduce:

- Install eSpeak (we need the libespeak.so.1 shared library)
- In Reinteract, create a new notebook named 'speechserver'
- Obtain the latest Python package 'pyttsx' from Git:
  - In an empty directory, run
    $ git clone git://github.com/parente/pyttsx.git
- from within the repository, copy the pyttsx directory and its contents to the notebook
    $ cd pyttsx
    $ cp -r pyttsx <path to speechserver notebook>
- Create a worksheet named 'test_pyttsx' with the following contents:

--cut here--
import pyttsx

engine = pyttsx.init()
engine.say('Sally sells seashells by the seashore.')
engine.say('The quick brown fox jumped over the lazy dog.')
engine.runAndWait()
--cut here--

Recalculating the worksheet produces the following:

--cut here--
import pyttsx

engine = pyttsx.init()
  • File "/home/miki/Documenten/Reinteract/speechserver/pyttsx/__init__.py", line 39 in init
    eng = Engine(driverName, debug)
  • File "/home/miki/Documenten/Reinteract/speechserver/pyttsx/engine.py", line 45 in __init__
    self.proxy = driver.DriverProxy(weakref.proxy(self), driverName, debug)
  • File "/home/miki/Documenten/Reinteract/speechserver/pyttsx/driver.py", line 64 in __init__
    self._module = __import__(name, globals(), locals(), [driverName])
ImportError: no module named drivers.espeak.espeak
engine.say('Sally sells seashells by the seashore.')
engine.say('The quick brown fox jumped over the lazy dog.')
engine.runAndWait()
--cut here--

Running the worksheet directly with Python from a terminal:

$ python test_pyttsx.rws

works without problems.
Comment 1 Alain Kalker 2011-11-20 19:58:55 UTC
Note the duplicate "drivers.espeak.espeak" in the error message.

Also, when I do an 'import pyttsx.drivers' in a Reinteract worksheet, I get an AssertionError (without any additional info, so I don't know where it's coming from).
Comment 2 Alain Kalker 2011-11-20 20:05:16 UTC
Oops, make that:

When I enter 'import pyttsx.driver' in an empty worksheet and recalculate, I get an AssertionError, which I don't get when doing that in an interactive Python session.
Comment 3 Alain Kalker 2011-11-21 21:16:46 UTC
Created attachment 201872 [details]
Reinteract notebook for testing __import__

To run the test, open the notebook in Reinteract, then recalculate the worksheet named 'test_import.rws'.
Comment 4 Robert Schroll 2011-11-22 03:34:50 UTC
Created attachment 201894 [details] [review]
Don't worry if we can't find fromlist items during __import__

When __import__ is called directly, Python doesn't care if the items in
the fromlist exist or not -- it only cares that the fromlist is
non-empty.  For consistency, we shouldn't panic if we can't find the
objects in the fromlist.

This should solve the issues with the ImportErrors; the AssertionError 
seems to be something else.
Comment 5 Robert Schroll 2011-11-22 07:30:50 UTC
On the mailing list, Alain points out that the AssertionError is raised whenever you run 'import package.module' without running 'import package' first.  The problem in 'assert not prefixed in sys.modules' in __load_local_module in notebook.py.

My understanding is that this whole thing is caused by the 'import module' in package/__init__.py.  This causes package.module to be loaded whenever package is loaded.  When you import package.module, first package is loaded (thereby loading package.module).  Then package.module is loaded again.  This second time, __load_local_module notices that package.module has already been loaded and raises the AssertionError.  This can be avoided by removing import module from the __init__.py, but then the package doesn't work.

This assertion seems to be there to keep us from loading the same module twice.  In this case, commenting it out wouldn't hurt anything, but it's a good idea if there's some initialization code that should be run only once.  One solution would be to replace with assertion with a test that returns sys.modules[prefixed] if it exists.  But it would seem to me to be better to keep __load_local_module from being called the second time.  After all, if you import package before package.module, it never has this problem.  Unfortunately, I haven't been able to trace the code back far enough to see where the calls are ultimately coming from.

On this subject, there are several asserts scattered throughout notebook.py.  Perhaps they should be replace with more useful error reporting.
Comment 6 Owen Taylor 2011-12-01 03:58:56 UTC
Verified against the logic in CPython, pushed. (I think the test case code is
just buggy and non-sensicial, though?)

Attachment 201894 [details] pushed as 068b962 - Don't worry if we can't find fromlist items during __import__
Comment 7 Owen Taylor 2011-12-01 04:00:11 UTC
Reopening for the other issue - I think it's pretty simple - we just should check again if the module exists in self.__modules[] after we've loaded the parent.
Comment 8 Owen Taylor 2011-12-01 04:06:00 UTC
Created attachment 202497 [details] [review]
Notebook: catch when loading a parent module loads the child

When we retrieve the parent module for a module we want to load,
that might itself cause the child module to be loaded; check again
to catch when that happens and avoid an assertion error from loading
the child twice.
Comment 9 Owen Taylor 2011-12-01 05:23:57 UTC
(meant to leave my patch for testing/review, but accidentally pushed. Think it's fine.)

Attachment 202497 [details] pushed as 7f98efd - Notebook: catch when loading a parent module loads the child