Added monkeypatch stdlib tests, which test how well monkeypatching works. Unsurprisingly, some tweakage was also needed.

This commit is contained in:
Ryan Williams
2010-02-09 08:17:46 -08:00
parent 30c7f0f677
commit e1ee3cefbc
9 changed files with 98 additions and 58 deletions

View File

@@ -11,19 +11,21 @@ __patched__ = ['fdopen', 'read', 'write', 'wait', 'waitpid']
for var in dir(os_orig):
exec "%s = os_orig.%s" % (var, var)
__original_fdopen__ = os_orig.fdopen
def fdopen(*args, **kw):
"""fdopen(fd [, mode='r' [, bufsize]]) -> file_object
Return an open file object connected to a file descriptor."""
return greenio.GreenPipe(os_orig.fdopen(*args, **kw))
return greenio.GreenPipe(__original_fdopen__(*args, **kw))
__original_read__ = os_orig.read
def read(fd, n):
"""read(fd, buffersize) -> string
Read a file descriptor."""
while True:
try:
return os_orig.read(fd, n)
return __original_read__(fd, n)
except (OSError, IOError), e:
if e[0] != errno.EAGAIN:
raise
@@ -33,6 +35,7 @@ def read(fd, n):
raise
hubs.trampoline(fd, read=True)
__original_write__ = os_orig.write
def write(fd, st):
"""write(fd, string) -> byteswritten
@@ -40,7 +43,7 @@ def write(fd, st):
"""
while True:
try:
return os_orig.write(fd, st)
return __original_write__(fd, st)
except (OSError, IOError), e:
if e[0] != errno.EAGAIN:
raise
@@ -55,17 +58,18 @@ def wait():
Wait for completion of a child process."""
return waitpid(0,0)
__original_waitpid__ = os_orig.waitpid
def waitpid(pid, options):
"""waitpid(...)
waitpid(pid, options) -> (pid, status)
Wait for completion of a given child process."""
if options & os.WNOHANG != 0:
return os_orig.waitpid(pid, options)
return __original_waitpid__(pid, options)
else:
new_options = options | os.WNOHANG
while True:
rpid, status = os_orig.waitpid(pid, new_options)
rpid, status = __original_waitpid__(pid, new_options)
if status >= 0:
return rpid, status
greenthread.sleep(0.01)

View File

@@ -13,13 +13,16 @@ import warnings
__patched__ = ['fromfd', 'socketpair', 'gethostbyname', 'create_connection',
'ssl', 'socket']
__original_fromfd__ = __socket.fromfd
def fromfd(*args):
return socket(__socket.fromfd(*args))
return socket(__original_fromfd__(*args))
__original_socketpair__ = __socket.socketpair
def socketpair(*args):
one, two = __socket.socketpair(*args)
one, two = __original_socketpair__(*args)
return socket(one), socket(two)
__original_gethostbyname__ = __socket.gethostbyname
def gethostbyname(name):
can_use_tpool = os.environ.get("EVENTLET_TPOOL_GETHOSTBYNAME",
'').lower() == "yes"
@@ -28,7 +31,7 @@ def gethostbyname(name):
elif sys.platform.startswith('darwin') or not can_use_tpool:
# the thread primitives on Darwin have some bugs that make
# it undesirable to use tpool for hostname lookups
globals()['gethostbyname'] = __socket.gethostbyname
globals()['gethostbyname'] = __original_gethostbyname__
else:
globals()['gethostbyname'] = _gethostbyname_tpool
@@ -42,7 +45,7 @@ def _gethostbyname_twisted(name):
def _gethostbyname_tpool(name):
from eventlet import tpool
return tpool.execute(
__socket.gethostbyname, name)
__original_gethostbyname__, name)
# def getaddrinfo(*args, **kw):
# return tpool.execute(

View File

@@ -1,11 +1,11 @@
"""implements standard module 'thread' with greenlets"""
__thread = __import__('thread')
from eventlet.support import greenlets as greenlet
from eventlet.api import spawn
from eventlet import greenthread
from eventlet.semaphore import Semaphore as LockType
__patched__ = ['get_ident', 'start_new_thread', 'start_new', 'allocate_lock',
'allocate', 'exit', 'interrupt_main', 'stack_size', '_local']
'allocate', 'exit', 'interrupt_main', 'stack_size', '_local', 'LockType']
error = __thread.error
@@ -16,7 +16,7 @@ def get_ident(gr=None):
return id(gr)
def start_new_thread(function, args=(), kwargs={}):
g = spawn(function, *args, **kwargs)
g = greenthread.spawn(function, *args, **kwargs)
return get_ident(g)
start_new = start_new_thread
@@ -38,12 +38,13 @@ def interrupt_main():
else:
raise KeyboardInterrupt()
__original_stack_size__ = __thread.stack_size
if hasattr(__thread, 'stack_size'):
def stack_size(size=None):
if size is None:
return __thread.stack_size()
if size > __thread.stack_size():
return __thread.stack_size(size)
return __original_stack_size__()
if size > __original_stack_size__():
return __original_stack_size__(size)
else:
pass
# not going to decrease stack_size, because otherwise other greenlets in this thread will suffer

View File

@@ -2,6 +2,8 @@ from eventlet import patcher
from eventlet.green import thread
from eventlet.green import time
__patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident']
patcher.inject('threading',
globals(),
('thread', thread),

View File

@@ -142,7 +142,8 @@ def _green_socket_modules():
def _green_thread_modules():
from eventlet.green import Queue
from eventlet.green import thread
return [('Queue', Queue), ('thread', thread)]
from eventlet.green import threading
return [('Queue', Queue), ('thread', thread), ('threading', threading)]
def _green_time_modules():
from eventlet.green import time

View File

@@ -22,6 +22,7 @@ in :meth:`put <Queue.put>` or :meth:`get <Queue.get>` respectively.
import sys
import heapq
import collections
import traceback
from Queue import Full, Empty

View File

@@ -4,7 +4,7 @@ Many of these tests make connections to external servers, and all.py tries to sk
"""
def import_main(name):
def assimilate_patched(name):
try:
modobj = __import__(name, globals(), locals(), ['test_main'])
except ImportError:
@@ -18,44 +18,7 @@ def import_main(name):
except AttributeError:
print "No test_main for %s, assuming it tests on import" % name
import all_modules
# quick and dirty way of testing whether we can access
# remote hosts; any tests that try internet connections
# will fail if we cannot
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(0.5)
s.connect(('eventlet.net', 80))
s.close()
have_network_access = True
except socket.error, e:
print "Skipping network tests"
have_network_access = False
import_main('test_select')
import_main('test_SimpleHTTPServer')
import_main('test_asynchat')
import_main('test_asyncore')
import_main('test_ftplib')
import_main('test_httplib')
if have_network_access:
import_main('test_httpservers')
import_main('test_os')
import_main('test_queue')
if have_network_access:
import_main('test_socket')
import_main('test_socket_ssl')
#import_main('test_socketserver')
#import_main('test_subprocess')
if have_network_access:
import_main('test_ssl')
import_main('test_thread')
#import_main('test_threading')
import_main('test_threading_local')
if have_network_access:
import_main('test_timeout')
import_main('test_urllib')
if have_network_access:
import_main('test_urllib2')
import_main('test_urllib2_localnet')
for m in all_modules.get_modules():
assimilate_patched(m)

View File

@@ -0,0 +1,41 @@
def get_modules():
test_modules = [
'test_select',
'test_SimpleHTTPServer',
'test_asynchat',
'test_asyncore',
'test_ftplib',
'test_httplib',
'test_os',
'test_queue',
'test_socket_ssl',
# 'test_socketserver',
# 'test_subprocess',
'test_thread',
# 'test_threading',
'test_threading_local',
'test_urllib',
'test_urllib2_localnet']
network_modules = [
'test_httpservers',
'test_socket',
'test_ssl',
'test_timeout',
'test_urllib2']
# quick and dirty way of testing whether we can access
# remote hosts; any tests that try internet connections
# will fail if we cannot
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.settimeout(0.5)
s.connect(('eventlet.net', 80))
s.close()
test_modules = test_modules + network_modules
except socket.error, e:
print "Skipping network tests"
return test_modules

View File

@@ -0,0 +1,24 @@
import eventlet
eventlet.sleep(0)
from eventlet import patcher
patcher.monkey_patch()
def assimilate_real(name):
print "Assimilating", name
try:
modobj = __import__('test.' + name, globals(), locals(), ['test_main'])
except ImportError:
print "Not importing %s, it doesn't exist in this installation/version of Python" % name
return
else:
method_name = name + "_test_main"
try:
globals()[method_name] = modobj.test_main
modobj.test_main.__name__ = name + '.test_main'
except AttributeError:
print "No test_main for %s, assuming it tests on import" % name
import all_modules
for m in all_modules.get_modules():
assimilate_real(m)