aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'portage_with_autodep/pym/portage/proxy/lazyimport.py')
-rw-r--r--portage_with_autodep/pym/portage/proxy/lazyimport.py212
1 files changed, 212 insertions, 0 deletions
diff --git a/portage_with_autodep/pym/portage/proxy/lazyimport.py b/portage_with_autodep/pym/portage/proxy/lazyimport.py
new file mode 100644
index 0000000..ad4a542
--- /dev/null
+++ b/portage_with_autodep/pym/portage/proxy/lazyimport.py
@@ -0,0 +1,212 @@
+# Copyright 2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+__all__ = ['lazyimport']
+
+import sys
+import types
+
+try:
+ import threading
+except ImportError:
+ import dummy_threading as threading
+
+from portage.proxy.objectproxy import ObjectProxy
+
+if sys.hexversion >= 0x3000000:
+ basestring = str
+
+_module_proxies = {}
+_module_proxies_lock = threading.RLock()
+
+def _preload_portage_submodules():
+ """
+ Load lazily referenced portage submodules into memory,
+ so imports won't fail during portage upgrade/downgrade.
+ Note that this recursively loads only the modules that
+ are lazily referenced by currently imported modules,
+ so some portage submodules may still remain unimported
+ after this function is called.
+ """
+ imported = set()
+ while True:
+ remaining = False
+ for name in list(_module_proxies):
+ if name.startswith('portage.'):
+ if name in imported:
+ continue
+ imported.add(name)
+ remaining = True
+ __import__(name)
+ _unregister_module_proxy(name)
+ if not remaining:
+ break
+
+def _register_module_proxy(name, proxy):
+ _module_proxies_lock.acquire()
+ try:
+ proxy_list = _module_proxies.get(name)
+ if proxy_list is None:
+ proxy_list = []
+ _module_proxies[name] = proxy_list
+ proxy_list.append(proxy)
+ finally:
+ _module_proxies_lock.release()
+
+def _unregister_module_proxy(name):
+ """
+ Destroy all proxies that reference the give module name. Also, check
+ for other proxies referenced by modules that have been imported and
+ destroy those proxies too. This way, destruction of a single proxy
+ can trigger destruction of all the rest. If a target module appears
+ to be partially imported (indicated when an AttributeError is caught),
+ this function will leave in place proxies that reference it.
+ """
+ _module_proxies_lock.acquire()
+ try:
+ if name in _module_proxies:
+ modules = sys.modules
+ for name, proxy_list in list(_module_proxies.items()):
+ if name not in modules:
+ continue
+ # First delete this name from the dict so that
+ # if this same thread reenters below, it won't
+ # enter this path again.
+ del _module_proxies[name]
+ try:
+ while proxy_list:
+ proxy = proxy_list.pop()
+ object.__getattribute__(proxy, '_get_target')()
+ except AttributeError:
+ # Apparently the target module is only partially
+ # imported, so proxies that reference it cannot
+ # be destroyed yet.
+ proxy_list.append(proxy)
+ _module_proxies[name] = proxy_list
+ finally:
+ _module_proxies_lock.release()
+
+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)
+ _register_module_proxy(name, self)
+
+ 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
+ _unregister_module_proxy(name)
+ return target
+
+class _LazyImportFrom(_LazyImport):
+
+ __slots__ = ('_attr_name',)
+
+ def __init__(self, scope, name, attr_name, alias):
+ object.__setattr__(self, '_attr_name', attr_name)
+ _LazyImport.__init__(self, scope, alias, name)
+
+ def _get_target(self):
+ try:
+ return object.__getattribute__(self, '_target')
+ except AttributeError:
+ pass
+ name = object.__getattribute__(self, '_name')
+ attr_name = object.__getattribute__(self, '_attr_name')
+ __import__(name)
+ # If called by _unregister_module_proxy() and the target module is
+ # partially imported, then the following getattr call may raise an
+ # AttributeError for _unregister_module_proxy() to handle.
+ target = getattr(sys.modules[name], attr_name)
+ object.__setattr__(self, '_target', target)
+ object.__getattribute__(self, '_scope')[
+ object.__getattribute__(self, '_alias')] = target
+ _unregister_module_proxy(name)
+ return target
+
+def lazyimport(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
+ """
+
+ modules = sys.modules
+
+ 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 range(len(components)):
+ alias = components[i]
+ if i < len(components) - 1:
+ parent_name = ".".join(components[:i+1])
+ __import__(parent_name)
+ mod = modules.get(parent_name)
+ if not isinstance(mod, types.ModuleType):
+ # raise an exception
+ __import__(name)
+ parent_scope[alias] = mod
+ parent_scope = mod.__dict__
+ continue
+
+ already_imported = modules.get(name)
+ if already_imported is not None:
+ parent_scope[alias] = already_imported
+ else:
+ parent_scope[alias] = \
+ _LazyImport(parent_scope, alias, name)
+
+ else:
+ name, fromlist = parts
+ already_imported = modules.get(name)
+ fromlist = fromlist.split(',')
+ for s in fromlist:
+ if not s:
+ # This happens if there's an extra comma in fromlist.
+ raise ValueError('Empty module attribute name')
+ alias = s.split('@', 1)
+ if len(alias) == 1:
+ alias = alias[0]
+ attr_name = alias
+ else:
+ attr_name, alias = alias
+ if already_imported is not None:
+ try:
+ scope[alias] = getattr(already_imported, attr_name)
+ except AttributeError:
+ # Apparently the target module is only partially
+ # imported, so create a proxy.
+ already_imported = None
+ scope[alias] = \
+ _LazyImportFrom(scope, name, attr_name, alias)
+ else:
+ scope[alias] = \
+ _LazyImportFrom(scope, name, attr_name, alias)