Hey, get this! [was: import from database]

Steve Holden steve at holdenweb.com
Wed Feb 2 09:38:03 EST 2005


Steve Holden wrote:

> Peter Otten wrote:
> 
>> Steve Holden wrote:
>>
>>
>>> This is even stranger: it makes it if I import the module a second time:
>>
>>
>>
>> [second import seems to succeed]
>>
>> Maybe you are experiencing some version confusion? What you describe 
>> looks
>> much like the normal Python 2.3 behaviour (with no import hook involved)
>> whereas you seem to operate on the 2.4 library.
>> A partially initialized module object is left behind in sys.modules 
>> and seen
>> by further import attempts.
>>
> I agree that this is 2.3-like behavior, but Python cannot lie ...
> 
> sholden at dellboy ~/Projects/Python/dbimp
> $ python
> Python 2.4 (#1, Dec  4 2004, 20:10:33)
> [GCC 3.3.3 (cygwin special)] on cygwin
> Type "help", "copyright", "credits" or "license" for more information.
>  >>>
> 
Just to make things simpler, and (;-) to appeal to a wider audience, 
here is a program that doesn't use database at all (it loads the entire 
standard library into a dict) and still shows the error.

What *I* would like to know is: who is allowing the import of bsddb.os, 
thereby somehow causing the code of the os library module to be run a 
second time.

#
# Establish standard library in dict
#
import os
import glob
import sys
import marshal
import new

def importpy(dct, path, modname, package):
     c = compile(file(path).read(), path, "exec")
     dct[modname] = (marshal.dumps(c), package, path)
     if package:
         print "Package", modname, path
     else:
         print "Module", modname, path

def importall(dct, path, modlist):
     os.chdir(path)
     for f in glob.glob("*"):
         if os.path.isdir(f):
             fn = os.path.join(path, f, "__init__.py")
             if os.path.exists(fn):
                 ml = modlist + [f]
                 importpy(dct, fn, ".".join(ml), 1)
                 importall(dct, os.path.join(path, f), ml)
         elif f.endswith('.py') and '.' not in f[:-3] and f != 
"__init__.py":
             importpy(dct, os.path.join(path, f), 
".".join(modlist+[f[:-3]]), 0)

class dbimporter(object):

     def __init__(self, item, *args, **kw):
         ##print "dbimporter: item:", item, "args:", args, "keywords:", kw
         if item != "*db*":
             raise ImportError
         print "Accepted", item

     def find_module(self, fullname, path=None):
         print "find_module:", fullname, "from", path
         if fullname not in impdict:
             #print "Bailed on", fullname
             return None
         else:
             print "found", fullname, "in db"
             return self

     def load_module(self, modname):
         print "load_module:", modname
         if modname in sys.modules:
             return sys.modules[modname]
         try:
             row = impdict[modname]
         except KeyError:
             #print modname, "not found in db"
             raise ImportError, "DB module %s not found in modules"
         code, package, path = row
         code = marshal.loads(code)
         module = new.module(modname)
         sys.modules[modname] = module
         module.__name__ = modname
         module.__file__ = path # "db:%s" % modname
         module.__loader__ = dbimporter
         if package:
             module.__path__ = sys.path
         exec code in module.__dict__
         print modname, "loaded:", repr(module), "pkg:", package
         return module

def install():
     sys.path_hooks.append(dbimporter)
     sys.path_importer_cache.clear() # probably not necessary
     sys.path.insert(0, "*db*") # probably not needed with a metea-path 
hook?

if __name__ == "__main__":
     impdict = {}
     for path in sys.argv[1:]:
         importall(impdict, path, [])
     install()
     import bsddb

Running this against a copy of the Python 2.4 standard library in C:\Lib 
gives me

[...]
Module _strptime C:\Lib\_strptime.py
Module _threading_local C:\Lib\_threading_local.py
Module __future__ C:\Lib\__future__.py
Accepted *db*
find_module: bsddb from None
found bsddb in db
load_module: bsddb
find_module: bsddb._bsddb from None
find_module: bsddb.sys from None
find_module: bsddb.os from None
find_module: bsddb.nt from None
find_module: bsddb.ntpath from None
find_module: bsddb.stat from None
Traceback (most recent call last):
   File "C:\Steve\Projects\Python\dbimp\dictload.py", line 79, in ?
     import bsddb
   File "C:\Steve\Projects\Python\dbimp\dictload.py", line 65, in 
load_module
     exec code in module.__dict__
   File "C:\Lib\bsddb\__init__.py", line 62, in ?
     import sys, os
   File "C:\Python24\lib\os.py", line 133, in ?
     from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, 
altsep,
ImportError: No module named path

The 2.3 bsddb library doesn't cause the same problems (and even loads 
into 2.4 quite nicely). Lots of modules *will* import, and most packages 
don't seem to cause problems. Anyone give me a pointer here?

regards
  Steve
-- 
Meet the Python developers and your c.l.py favorites March 23-25
Come to PyCon DC 2005          http://www.python.org/pycon/2005/
Steve Holden                           http://www.holdenweb.com/



More information about the Python-list mailing list