[code.view]

[top] / python / PyMOTW / sys / sys_shelve_importer.py

     #!/usr/bin/env python
     # encoding: utf-8
     #
     # Copyright (c) 2009 Doug Hellmann All rights reserved.
     #
     """
     """
     #end_pymotw_header
     
     import contextlib
     import imp
     import os
     import shelve
     import sys
     
     
     @contextlib.contextmanager
     def shelve_context(filename, flag='r'):
         """Context manager to make shelves work with 'with' statement."""
         db = shelve.open(filename, flag)
         try:
             yield db
         finally:
             db.close()
     
         
     def _mk_init_name(fullname):
         """Return the name of the __init__ module for a given package name."""
         if fullname.endswith('.__init__'):
             return fullname
         return fullname + '.__init__'
     
     
     def _get_key_name(fullname, db):
         """Look in an open shelf for fullname or fullname.__init__, return the name found."""
         if fullname in db:
             return fullname
         init_name = _mk_init_name(fullname)
         if init_name in db:
             return init_name
         return None
         
     
     class ShelveFinder(object):
         """Find modules collected in a shelve archive."""
         
         def __init__(self, path_entry):
             if not os.path.isfile(path_entry):
                 raise ImportError
             try:
                 # Test the path_entry to see if it is a valid shelf
                 with shelve_context(path_entry):
                     pass
             except Exception, e:
                 raise ImportError(str(e))
             else:
                 print 'new shelf added to import path:', path_entry
                 self.path_entry = path_entry
             return
             
         def __str__(self):
             return '<%s for "%s">' % (self.__class__.__name__, self.path_entry)
             
         def find_module(self, fullname, path=None):
             path = path or self.path_entry
             print 'looking for "%s" in %s ...' % (fullname, path),
             with shelve_context(path) as db:
                 key_name = _get_key_name(fullname, db)
                 if key_name:
                     print 'found it as %s' % key_name
                     return ShelveLoader(path)
             print 'not found'
             return None
     
     
     class ShelveLoader(object):
         """Load source for modules from shelve databases."""
         
         def __init__(self, path_entry):
             self.path_entry = path_entry
             return
             
         def _get_filename(self, fullname):
             # Make up a fake filename that starts with the path entry
             # so pkgutil.get_data() works correctly.
             return os.path.join(self.path_entry, fullname)
             
         def get_source(self, fullname):
             print 'loading source for "%s" from shelf' % fullname
             try:
                 with shelve_context(self.path_entry) as db:
                     key_name = _get_key_name(fullname, db)
                     if key_name:
                         return db[key_name]
                     raise ImportError('could not find source for %s' % fullname)
             except Exception, e:
                 print 'could not load source:', e
                 raise ImportError(str(e))
                 
         def get_code(self, fullname):
             source = self.get_source(fullname)
             print 'compiling code for "%s"' % fullname
             return compile(source, self._get_filename(fullname), 'exec', dont_inherit=True)
         
         def get_data(self, path):
             print 'looking for data in %s for "%s"' % (self.path_entry, path)
             if not path.startswith(self.path_entry):
                 raise IOError
             path = path[len(self.path_entry)+1:]
             key_name = 'data:' + path
             try:
                 with shelve_context(self.path_entry) as db:
                     return db[key_name]
             except Exception, e:
                 # Convert all errors to IOError
                 raise IOError
             
         def is_package(self, fullname):
             init_name = _mk_init_name(fullname)
             with shelve_context(self.path_entry) as db:
                 return init_name in db
     
         def load_module(self, fullname):
             source = self.get_source(fullname)
     
             if fullname in sys.modules:
                 print 'reusing existing module from previous import of "%s"' % fullname
                 mod = sys.modules[fullname]
             else:
                 print 'creating a new module object for "%s"' % fullname
                 mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
     
             # Set a few properties required by PEP 302
             mod.__file__ = self._get_filename(fullname)
             mod.__name__ = fullname
             mod.__path__ = self.path_entry
             mod.__loader__ = self
             mod.__package__ = '.'.join(fullname.split('.')[:-1])
             
             if self.is_package(fullname):
                 print 'adding path for package'
                 # Set __path__ for packages
                 # so we can find the sub-modules.
                 mod.__path__ = [ self.path_entry ]
             else:
                 print 'imported as regular module'
             
             print 'execing source...'
             exec source in mod.__dict__
             print 'done'
             return mod
             
     

[top] / python / PyMOTW / sys / sys_shelve_importer.py

contact | logmethods.com