GNOME Bugzilla – Bug 664432
Erroneous ImportError from __import__ used in package module
Last modified: 2011-12-01 05:24:00 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()
+ Trace 229081
eng = Engine(driverName, debug)
self.proxy = driver.DriverProxy(weakref.proxy(self), driverName, debug)
self._module = __import__(name, globals(), locals(), [driverName])
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.
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).
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.
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'.
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.
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.
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__
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.
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.
(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