/Lib/site-packages/gevent/builtins.py
https://gitlab.com/pierreEffiScience/TwitterClustering · Python · 125 lines · 72 code · 18 blank · 35 comment · 7 complexity · 2eaf47c1f23ea63cb0783414fba25ef3 MD5 · raw file
- # Copyright (c) 2015 gevent contributors. See LICENSE for details.
- """gevent friendly implementations of builtin functions."""
- from __future__ import absolute_import
- import imp # deprecated since 3.4; issues PendingDeprecationWarning in 3.5
- import sys
- import weakref
- from gevent.lock import RLock
- # Normally we'd have the "expected" case inside the try
- # (Python 3, because Python 3 is the way forward). But
- # under Python 2, the popular `future` library *also* provides
- # a `builtins` module---which lacks the __import__ attribute.
- # So we test for the old, deprecated version first
- try: # Py2
- import __builtin__ as builtins
- _allowed_module_name_types = (basestring,)
- __target__ = '__builtin__'
- except ImportError:
- import builtins
- _allowed_module_name_types = (str,)
- __target__ = 'builtins'
- _import = builtins.__import__
- # We need to protect imports both across threads and across greenlets.
- # And the order matters. Note that under 3.4, the global import lock
- # and imp module are deprecated. It seems that in all Py3 versions, a
- # module lock is used such that this fix is not necessary.
- # We emulate the per-module locking system under Python 2 in order to
- # avoid issues acquiring locks in multiple-level-deep imports
- # that attempt to use the gevent blocking API at runtime; using one lock
- # could lead to a LoopExit error as a greenlet attempts to block on it while
- # it's already held by the main greenlet (issue #798).
- # We base this approach on a simplification of what `importlib._boonstrap`
- # does; notably, we don't check for deadlocks
- _g_import_locks = {} # name -> wref of RLock
- __lock_imports = True
- def __module_lock(name):
- # Return the lock for the given module, creating it if necessary.
- # It will be removed when no longer needed.
- # Nothing in this function yields, so we're multi-greenlet safe
- # (But not multi-threading safe.)
- # XXX: What about on PyPy, where the GC is asynchronous (not ref-counting)?
- # (Does it stop-the-world first?)
- lock = None
- try:
- lock = _g_import_locks[name]()
- except KeyError:
- pass
- if lock is None:
- lock = RLock()
- def cb(_):
- # We've seen a KeyError on PyPy on RPi2
- _g_import_locks.pop(name, None)
- _g_import_locks[name] = weakref.ref(lock, cb)
- return lock
- def __import__(*args, **kwargs):
- """
- __import__(name, globals=None, locals=None, fromlist=(), level=0) -> object
- Normally python protects imports against concurrency by doing some locking
- at the C level (at least, it does that in CPython). This function just
- wraps the normal __import__ functionality in a recursive lock, ensuring that
- we're protected against greenlet import concurrency as well.
- """
- if len(args) > 0 and not issubclass(type(args[0]), _allowed_module_name_types):
- # if a builtin has been acquired as a bound instance method,
- # python knows not to pass 'self' when the method is called.
- # No such protection exists for monkey-patched builtins,
- # however, so this is necessary.
- args = args[1:]
- if not __lock_imports:
- return _import(*args, **kwargs)
- module_lock = __module_lock(args[0]) # Get a lock for the module name
- imp.acquire_lock()
- try:
- module_lock.acquire()
- try:
- result = _import(*args, **kwargs)
- finally:
- module_lock.release()
- finally:
- imp.release_lock()
- return result
- def _unlock_imports():
- """
- Internal function, called when gevent needs to perform imports
- lazily, but does not know the state of the system. It may be impossible
- to take the import lock because there are no other running greenlets, for
- example. This causes a monkey-patched __import__ to avoid taking any locks.
- until the corresponding call to lock_imports. This should only be done for limited
- amounts of time and when the set of imports is statically known to be "safe".
- """
- global __lock_imports
- # This could easily become a list that we push/pop from or an integer
- # we increment if we need to do this recursively, but we shouldn't get
- # that complex.
- __lock_imports = False
- def _lock_imports():
- global __lock_imports
- __lock_imports = True
- if sys.version_info[:2] >= (3, 3):
- __implements__ = []
- else:
- __implements__ = ['__import__']
- __all__ = __implements__