[Import-sig] imputil.py patch

Gordon McMillan gmcm@hypernet.com
Tue, 17 Jul 2001 12:09:24 -0400


While playing with _xmlplus, I found an incompatibility in 
imputil.py.

Background: 
xml/__init__.py (in the standard lib) does an import of 
_xmlplus, and if the package is found and the version number 
of the package is acceptable, it updates sys.modules so that 
"xml" now points to _xmlplus/__init__.py. Subsequent imports 
from the xml package now come from _xmlplus.

The Problem:
Under the standard import mechanism, these modules show 
up in sys.modules under the "xml" name. Their __name__ 
also starts with "xml". The only evidence of the _xmlplus 
package is that _xmlplus/__init__.py shows up in 
sys.modules.

Under imputil, they show up in sys.modules (and have 
__name__s) under "_xmlplus", with the only evidence of 
package "xml" in sys.modules being the top. Normally, this is 
OK (because when used, modules are fetched from their 
parent's namespace, so "xml.sax.saxlib" is resolved correctly, 
even though it's in sys.modules as "_xmplus.sax.saxlib"). 
However, there are quite a few places in _xmplus where code 
looks in sys.modules for the "xml" name (expecting, of 
course, to find _xmlplus modules).

While I don't really approve of _xmlplus's shennanigans, 
(explicit is better than implicit), they're not doing anything 
illegal, so imputil should probably be fixed.

The attached patch does that, with no untoward side-effects 
that I can discover (well, it broke my ZlibArchive, but that was 
easy to fix). I post it here because this stuff is very subtle and 
could use more eyes. It also might break Thomas's py2exe.

The "from" file is the current imputil acquired from viewcvs.


- Gordon



-------------- Enclosure number 1 ----------------
*** p:/tmp/imputil.py   Tue Jul 17 11:32:32 2001
--- imputil.py  Tue Jul 17 11:37:52 2001
***************
*** 291,297 ****
              exec code in module.__dict__

          # fetch from sys.modules instead of returning module directly.
!         return sys.modules[fqname]

      def _load_tail(self, m, parts):
          """Import the rest of the modules, down from the top-level module.
--- 291,301 ----
              exec code in module.__dict__

          # fetch from sys.modules instead of returning module directly.
!         # also make module's __name__ agree with fqname, in case
!         # the "exec code in module.__dict__" played games on us.
!         module = sys.modules[fqname]
!         module.__name__ = fqname
!         return module

      def _load_tail(self, m, parts):
          """Import the rest of the modules, down from the top-level module.