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

View File

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

View File

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

View File

@@ -142,7 +142,8 @@ def _green_socket_modules():
def _green_thread_modules(): def _green_thread_modules():
from eventlet.green import Queue from eventlet.green import Queue
from eventlet.green import thread 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(): def _green_time_modules():
from eventlet.green import time 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 sys
import heapq import heapq
import collections import collections
import traceback
from Queue import Full, Empty 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: try:
modobj = __import__(name, globals(), locals(), ['test_main']) modobj = __import__(name, globals(), locals(), ['test_main'])
except ImportError: except ImportError:
@@ -18,44 +18,7 @@ def import_main(name):
except AttributeError: except AttributeError:
print "No test_main for %s, assuming it tests on import" % name 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 for m in all_modules.get_modules():
# remote hosts; any tests that try internet connections assimilate_patched(m)
# 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')

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)