/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

  1. # Copyright (c) 2015 gevent contributors. See LICENSE for details.
  2. """gevent friendly implementations of builtin functions."""
  3. from __future__ import absolute_import
  4. import imp # deprecated since 3.4; issues PendingDeprecationWarning in 3.5
  5. import sys
  6. import weakref
  7. from gevent.lock import RLock
  8. # Normally we'd have the "expected" case inside the try
  9. # (Python 3, because Python 3 is the way forward). But
  10. # under Python 2, the popular `future` library *also* provides
  11. # a `builtins` module---which lacks the __import__ attribute.
  12. # So we test for the old, deprecated version first
  13. try: # Py2
  14. import __builtin__ as builtins
  15. _allowed_module_name_types = (basestring,)
  16. __target__ = '__builtin__'
  17. except ImportError:
  18. import builtins
  19. _allowed_module_name_types = (str,)
  20. __target__ = 'builtins'
  21. _import = builtins.__import__
  22. # We need to protect imports both across threads and across greenlets.
  23. # And the order matters. Note that under 3.4, the global import lock
  24. # and imp module are deprecated. It seems that in all Py3 versions, a
  25. # module lock is used such that this fix is not necessary.
  26. # We emulate the per-module locking system under Python 2 in order to
  27. # avoid issues acquiring locks in multiple-level-deep imports
  28. # that attempt to use the gevent blocking API at runtime; using one lock
  29. # could lead to a LoopExit error as a greenlet attempts to block on it while
  30. # it's already held by the main greenlet (issue #798).
  31. # We base this approach on a simplification of what `importlib._boonstrap`
  32. # does; notably, we don't check for deadlocks
  33. _g_import_locks = {} # name -> wref of RLock
  34. __lock_imports = True
  35. def __module_lock(name):
  36. # Return the lock for the given module, creating it if necessary.
  37. # It will be removed when no longer needed.
  38. # Nothing in this function yields, so we're multi-greenlet safe
  39. # (But not multi-threading safe.)
  40. # XXX: What about on PyPy, where the GC is asynchronous (not ref-counting)?
  41. # (Does it stop-the-world first?)
  42. lock = None
  43. try:
  44. lock = _g_import_locks[name]()
  45. except KeyError:
  46. pass
  47. if lock is None:
  48. lock = RLock()
  49. def cb(_):
  50. # We've seen a KeyError on PyPy on RPi2
  51. _g_import_locks.pop(name, None)
  52. _g_import_locks[name] = weakref.ref(lock, cb)
  53. return lock
  54. def __import__(*args, **kwargs):
  55. """
  56. __import__(name, globals=None, locals=None, fromlist=(), level=0) -> object
  57. Normally python protects imports against concurrency by doing some locking
  58. at the C level (at least, it does that in CPython). This function just
  59. wraps the normal __import__ functionality in a recursive lock, ensuring that
  60. we're protected against greenlet import concurrency as well.
  61. """
  62. if len(args) > 0 and not issubclass(type(args[0]), _allowed_module_name_types):
  63. # if a builtin has been acquired as a bound instance method,
  64. # python knows not to pass 'self' when the method is called.
  65. # No such protection exists for monkey-patched builtins,
  66. # however, so this is necessary.
  67. args = args[1:]
  68. if not __lock_imports:
  69. return _import(*args, **kwargs)
  70. module_lock = __module_lock(args[0]) # Get a lock for the module name
  71. imp.acquire_lock()
  72. try:
  73. module_lock.acquire()
  74. try:
  75. result = _import(*args, **kwargs)
  76. finally:
  77. module_lock.release()
  78. finally:
  79. imp.release_lock()
  80. return result
  81. def _unlock_imports():
  82. """
  83. Internal function, called when gevent needs to perform imports
  84. lazily, but does not know the state of the system. It may be impossible
  85. to take the import lock because there are no other running greenlets, for
  86. example. This causes a monkey-patched __import__ to avoid taking any locks.
  87. until the corresponding call to lock_imports. This should only be done for limited
  88. amounts of time and when the set of imports is statically known to be "safe".
  89. """
  90. global __lock_imports
  91. # This could easily become a list that we push/pop from or an integer
  92. # we increment if we need to do this recursively, but we shouldn't get
  93. # that complex.
  94. __lock_imports = False
  95. def _lock_imports():
  96. global __lock_imports
  97. __lock_imports = True
  98. if sys.version_info[:2] >= (3, 3):
  99. __implements__ = []
  100. else:
  101. __implements__ = ['__import__']
  102. __all__ = __implements__