Add a new portage.utils.lazy_import() function which behaves similar to the
authorZac Medico <zmedico@gentoo.org>
Fri, 20 Feb 2009 06:15:34 +0000 (06:15 -0000)
committerZac Medico <zmedico@gentoo.org>
Fri, 20 Feb 2009 06:15:34 +0000 (06:15 -0000)
snakeoil.demandload.demandload() function.

svn path=/main/trunk/; revision=12661

pym/portage/__init__.py
pym/portage/dbapi/bintree.py
pym/portage/util.py

index 15af77571f5384dfd0dc336f15925f8ce4b7ab07..621daa7bee1bbfe00aa3210d0c7de7f848a8bc46 100644 (file)
@@ -73,17 +73,30 @@ if platform.system() in ["FreeBSD"]:
 
 try:
        from portage.cache.cache_errors import CacheError
-       import portage.cvstree
-       import portage.xpak
-       import portage.getbinpkg
-       import portage.dep
-       from portage.dep import dep_getcpv, dep_getkey, get_operator, \
-               isjustname, isspecific, isvalidatom, \
-               match_from_list, match_to_list, best_match_to_list
-
-       # XXX: This needs to get cleaned up.
-       import portage.output
-       from portage.output import bold, colorize, green, red, yellow
+       import portage.util as util
+       util.lazy_import(globals(),
+               'portage.checksum',
+               'portage.checksum:perform_checksum,perform_md5,prelink_capable',
+               'portage.cvstree',
+               'portage.dep',
+               'portage.dep:best_match_to_list,dep_getcpv,dep_getkey,' + \
+                       'get_operator,isjustname,isspecific,isvalidatom,' + \
+                       'match_from_list,match_to_list',
+               'portage.eclass_cache',
+               'portage.getbinpkg',
+               'portage.locks',
+               'portage.locks:lockdir,lockfile,unlockdir,unlockfile',
+               'portage.output',
+               'portage.output:bold,colorize',
+               'portage.process',
+               'portage.process:atexit_register,run_exitfuncs',
+               'portage.update:dep_transform,fixdbentries,grab_updates,' + \
+                       'parse_updates,update_config_files,update_dbentries,' + \
+                       'update_dbentry',
+               'portage.versions:best,catpkgsplit,catsplit,endversion_keys,' + \
+                       'suffix_value@endversion,pkgcmp,pkgsplit,vercmp,ververify',
+               'portage.xpak',
+       )
 
        import portage.const
        from portage.const import VDB_PATH, PRIVATE_PATH, CACHE_PATH, DEPCACHE_PATH, \
@@ -99,31 +112,13 @@ try:
                                 portage_uid, portage_gid, userpriv_groups
        from portage.manifest import Manifest
 
-       import portage.util
        from portage.util import atomic_ofstream, apply_secpass_permissions, apply_recursive_permissions, \
                dump_traceback, getconfig, grabdict, grabdict_package, grabfile, grabfile_package, \
                map_dictlist_vals, new_protect_filename, normalize_path, \
                pickle_read, pickle_write, stack_dictlist, stack_dicts, stack_lists, \
                unique_array, varexpand, writedict, writemsg, writemsg_stdout, write_atomic
        import portage.exception
-       import portage.locks
-       import portage.process
-       from portage.process import atexit_register, run_exitfuncs
-       from portage.locks import unlockfile,unlockdir,lockfile,lockdir
-       import portage.checksum
-       from portage.checksum import perform_md5,perform_checksum,prelink_capable
-       import portage.eclass_cache
        from portage.localization import _
-       from portage.update import dep_transform, fixdbentries, grab_updates, \
-               parse_updates, update_config_files, update_dbentries, update_dbentry
-
-       # Need these functions directly in portage namespace to not break every external tool in existence
-       from portage.versions import best, catpkgsplit, catsplit, pkgcmp, \
-               pkgsplit, vercmp, ververify
-
-       # endversion and endversion_keys are for backward compatibility only.
-       from portage.versions import endversion_keys
-       from portage.versions import suffix_value as endversion
 
 except ImportError, e:
        sys.stderr.write("\n\n")
index 7f2c0cbf08e629e3612a356b7612a817d107495c..1d2c17ab8f3bc768fb4c917b257e8b006e594c25 100644 (file)
@@ -16,7 +16,7 @@ from portage.update import update_dbentries
 
 from portage import dep_expand, listdir, _check_distfile, _movefile
 
-import portage.xpak, portage.getbinpkg
+import portage
 
 import os, errno, stat
 import re
index da79d86fefabb13011d333aa224dc6ed62bb1684..54df381922d74dba825dd4557f245ef2904aec9f 100644 (file)
@@ -10,6 +10,7 @@ import shlex
 import stat
 import string
 import sys
+import types
 
 from portage.exception import PortageException, FileNotFound, \
        OperationNotPermitted, PermissionDenied, ReadOnlyFileSystem
@@ -341,6 +342,8 @@ class ObjectProxy(object):
        for implementing lazy initialization.
        """
 
+       __slots__ = ()
+
        def _get_target(self):
                raise NotImplementedError(self)
 
@@ -392,6 +395,104 @@ class ObjectProxy(object):
        def __nonzero__(self):
                return bool(object.__getattribute__(self, '_get_target')())
 
+class _LazyImport(ObjectProxy):
+
+       __slots__ = ('_scope', '_alias', '_name', '_target')
+
+       def __init__(self, scope, alias, name):
+               ObjectProxy.__init__(self)
+               object.__setattr__(self, '_scope', scope)
+               object.__setattr__(self, '_alias', alias)
+               object.__setattr__(self, '_name', name)
+
+       def _get_target(self):
+               try:
+                       return object.__getattribute__(self, '_target')
+               except AttributeError:
+                       pass
+               name = object.__getattribute__(self, '_name')
+               __import__(name)
+               target = sys.modules[name]
+               object.__setattr__(self, '_target', target)
+               object.__getattribute__(self, '_scope')[
+                       object.__getattribute__(self, '_alias')] = target
+               return target
+
+class _LazyImportFrom(_LazyImport):
+
+       __slots__ = ()
+
+       def _get_target(self):
+               try:
+                       return object.__getattribute__(self, '_target')
+               except AttributeError:
+                       pass
+               name = object.__getattribute__(self, '_name')
+               components = name.split('.')
+               parent_name = '.'.join(components[:-1])
+               __import__(parent_name)
+               target = getattr(sys.modules[parent_name], components[-1])
+               object.__setattr__(self, '_target', target)
+               object.__getattribute__(self, '_scope')[
+                       object.__getattribute__(self, '_alias')] = target
+               return target
+
+def lazy_import(scope, *args):
+       """
+       Create a proxy in the given scope in order to performa a lazy import.
+
+       Syntax         Result
+       foo            import foo
+       foo:bar,baz    from foo import bar, baz
+       foo:bar@baz    from foo import bar as baz
+
+       @param scope: the scope in which to place the import, typically globals()
+       @type myfilename: dict
+       @param args: module names to import
+       @type args: strings
+       """
+
+       for s in args:
+               parts = s.split(':', 1)
+               if len(parts) == 1:
+                       name = s
+
+                       if not name or not isinstance(name, basestring):
+                               raise ValueError(name)
+
+                       components = name.split('.')
+                       parent_scope = scope
+                       for i in xrange(len(components)):
+                               alias = components[i]
+                               mod = parent_scope.get(alias)
+                               if isinstance(mod, types.ModuleType):
+                                       parent_scope = mod.__dict__
+                                       continue
+                               if i < len(components) - 1:
+                                       parent_name = ".".join(components[:i+1])
+                                       __import__(parent_name)
+                                       mod = sys.modules.get(parent_name)
+                                       if not isinstance(mod, types.ModuleType):
+                                               # raise an exception
+                                               __import__(name)
+                                       parent_scope[alias] = mod
+                                       parent_scope = mod.__dict__
+                                       continue
+                               parent_scope[alias] = _LazyImport(parent_scope, alias, name)
+
+               else:
+                       name, fromlist = parts
+                       fromlist = fromlist.split(',')
+                       for s in fromlist:
+                               alias = s.split('@', 1)
+                               if len(alias) == 1:
+                                       alias = alias[0]
+                                       orig = alias
+                               else:
+                                       orig, alias = alias
+                               scope[alias] = _LazyImportFrom(scope, alias,
+                                       name + '.' + orig)
+
 class _tolerant_shlex(shlex.shlex):
        def sourcehook(self, newfile):
                try: