Commit 011f719f authored by Denis Bilenko's avatar Denis Bilenko

monkey: remove broken get_unpatched; add get_original() with new implementation

parent 03cfd4b1
...@@ -11,6 +11,7 @@ import heapq ...@@ -11,6 +11,7 @@ import heapq
from time import time as _time, sleep as _sleep from time import time as _time, sleep as _sleep
from gevent import monkey from gevent import monkey
from gevent.hub import PY3
__all__ = ['Condition', __all__ = ['Condition',
...@@ -24,7 +25,8 @@ __all__ = ['Condition', ...@@ -24,7 +25,8 @@ __all__ = ['Condition',
'stack_size'] 'stack_size']
start_new_thread, Lock, get_ident, local, stack_size = monkey.get_unpatched('thread', [ thread_name = '_thread' if PY3 else 'thread'
start_new_thread, Lock, get_ident, local, stack_size = monkey.get_original(thread_name, [
'start_new_thread', 'allocate_lock', 'get_ident', '_local', 'stack_size']) 'start_new_thread', 'allocate_lock', 'get_ident', '_local', 'stack_size'])
......
...@@ -67,70 +67,77 @@ __all__ = ['patch_all', ...@@ -67,70 +67,77 @@ __all__ = ['patch_all',
'patch_thread'] 'patch_thread']
def get_unpatched(name, items): # maps module name -> attribute name -> original item
# QQQ would prefer to avoid importing gevent.xxx module just to get __target__ # e.g. "time" -> "sleep" -> built-in function sleep
# XXX does not work for 'time', 'sleep' saved = {}
source = getattr(__import__('gevent.' + name), name)
target = getattr(source, '__target__', name)
dest = __import__(target) def get_original(name, items):
original = getattr(dest, 'monkey_original', dest) d = saved.get(name, {})
if isinstance(items, basestring): values = []
return getattr(original, items) module = None
else: for item in items:
results = [] if item in d:
for item in items: values.append(d[item])
results.append(getattr(original, item)) else:
return results if module is None:
module = __import__(name)
values.append(getattr(module, item))
return values
def patch_item(module, attr, newitem):
NONE = object()
olditem = getattr(module, attr, NONE)
if olditem is not NONE:
saved.setdefault(module.__name__, {}).setdefault(attr, olditem)
setattr(module, attr, newitem)
class original(object):
pass def remove_item(module, attr):
NONE = object()
olditem = getattr(module, attr, NONE)
if olditem is NONE:
return
saved.setdefault(module.__name__, {}).setdefault(attr, olditem)
delattr(module, attr)
def patch_module(name, items=None): def patch_module(name, items=None):
source = getattr(__import__('gevent.' + name), name) gevent_module = getattr(__import__('gevent.' + name), name)
target = getattr(source, '__target__', name) module_name = getattr(gevent_module, '__target__', name)
dest = __import__(target) module = __import__(module_name)
monkey_original = dest.monkey_original = original()
count = 0
if items is None: if items is None:
items = getattr(source, '__implements__', None) items = getattr(gevent_module, '__implements__', None)
if items is None: if items is None:
raise AttributeError('%r does not have __implements__' % source) raise AttributeError('%r does not have __implements__' % gevent_module)
for attr in items: for attr in items:
olditem = getattr(dest, attr, None) patch_item(module, attr, getattr(gevent_module, attr))
newitem = getattr(source, attr)
if olditem is not newitem:
setattr(monkey_original, attr, olditem)
setattr(dest, attr, newitem)
count += 1
return count
def patch_os(): def patch_os():
"""Replace :func:`os.fork` with :func:`gevent.fork`.""" """Replace :func:`os.fork` with :func:`gevent.fork`. Does nothing if fork is not available."""
try: try:
from gevent.hub import fork from gevent.hub import fork
except ImportError: except ImportError:
return return
import os import os
os.fork = fork patch_item(os, 'fork', fork)
def patch_time(): def patch_time():
"""Replace :func:`time.sleep` with :func:`gevent.sleep`.""" """Replace :func:`time.sleep` with :func:`gevent.sleep`."""
from gevent.hub import sleep from gevent.hub import sleep
_time = __import__('time') import time
_time.sleep = sleep patch_item(time, 'sleep', sleep)
def patch_thread(threading=True, _threading_local=True): def patch_thread(threading=True, _threading_local=True):
"""Replace the standard :mod:`thread` module to make it greenlet-based. """Replace the standard :mod:`thread` module to make it greenlet-based.
If *threading* is true (the default), also patch ``threading.local``. If *threading* is true (the default), also patch ``threading``.
If *_threading_local* is true (the default), also patch ``_threading_local.local``. If *_threading_local* is true (the default), also patch ``_threading_local.local``.
""" """
if not patch_module('thread'): patch_module('thread')
return
from gevent.local import local from gevent.local import local
if threading: if threading:
from gevent import thread as green_thread from gevent import thread as green_thread
...@@ -168,7 +175,7 @@ def patch_socket(dns=True, aggressive=True): ...@@ -168,7 +175,7 @@ def patch_socket(dns=True, aggressive=True):
patch_module('socket', items=items) patch_module('socket', items=items)
if aggressive: if aggressive:
if 'ssl' not in socket.__implements__: if 'ssl' not in socket.__implements__:
socket.__dict__.pop('ssl', None) remove_item(socket, 'ssl')
def patch_dns(): def patch_dns():
...@@ -180,7 +187,7 @@ def patch_ssl(): ...@@ -180,7 +187,7 @@ def patch_ssl():
patch_module('ssl') patch_module('ssl')
def patch_select(aggressive=False): def patch_select(aggressive=True):
"""Replace :func:`select.select` with :func:`gevent.select.select`. """Replace :func:`select.select` with :func:`gevent.select.select`.
If aggressive is true (the default), also remove other blocking functions the :mod:`select`. If aggressive is true (the default), also remove other blocking functions the :mod:`select`.
...@@ -191,10 +198,10 @@ def patch_select(aggressive=False): ...@@ -191,10 +198,10 @@ def patch_select(aggressive=False):
# since these are blocking we're removing them here. This makes some other # since these are blocking we're removing them here. This makes some other
# modules (e.g. asyncore) non-blocking, as they use select that we provide # modules (e.g. asyncore) non-blocking, as they use select that we provide
# when none of these are available. # when none of these are available.
select.__dict__.pop('poll', None) remove_item(select, 'poll')
select.__dict__.pop('epoll', None) remove_item(select, 'epoll')
select.__dict__.pop('kqueue', None) remove_item(select, 'kqueue')
select.__dict__.pop('kevent', None) remove_item(select, 'kevent')
def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True, httplib=False, aggressive=True): def patch_all(socket=True, dns=True, time=True, select=True, thread=True, os=True, ssl=True, httplib=False, aggressive=True):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment