From 155f9c0e4530a02863e3c1c45712eb0e23ab2ea6 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Tue, 5 Jan 2010 18:58:53 -0800 Subject: [PATCH 01/10] Set tpool to be quiet by default, improved exception raising. --- eventlet/tpool.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/eventlet/tpool.py b/eventlet/tpool.py index 02bc8b2..77f5525 100644 --- a/eventlet/tpool.py +++ b/eventlet/tpool.py @@ -15,12 +15,13 @@ import os import threading +import sys from Queue import Empty, Queue from eventlet import api, coros, greenio -QUIET=False +QUIET=True _rfile = _wfile = None @@ -69,9 +70,7 @@ def tworker(): except SYS_EXCS: raise except Exception,exn: - import sys - (a,b,tb) = sys.exc_info() - rv = (exn,a,b,tb) + rv = sys.exc_info() _rspq.put((e,rv)) meth = args = kwargs = e = rv = None _signal_t2e() @@ -79,13 +78,13 @@ def tworker(): def erecv(e): rv = e.wait() - if isinstance(rv,tuple) and len(rv) == 4 and isinstance(rv[0],Exception): + if isinstance(rv,tuple) and len(rv) == 3 and isinstance(rv[1],Exception): import traceback - (e,a,b,tb) = rv + (c,e,tb) = rv if not QUIET: - traceback.print_exception(Exception,e,tb) + traceback.print_exception(c,e,tb) traceback.print_stack() - raise e + raise c,e,tb return rv From b8a83ab9a0e9bde010ad34da776bf1e7599fe569 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Wed, 6 Jan 2010 19:13:50 -0800 Subject: [PATCH 02/10] Fixed intermittent patcher_test failures -- it turns out that you don't want to use tempfile.mkstemp files as dummy modules, because their names sometimes contain dashes and are unimportable. --- tests/patcher_test.py | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/tests/patcher_test.py b/tests/patcher_test.py index 401e11e..aef13e0 100644 --- a/tests/patcher_test.py +++ b/tests/patcher_test.py @@ -1,7 +1,8 @@ import os -import tempfile +import shutil import subprocess import sys +import tempfile from tests import LimitedTestCase @@ -16,49 +17,42 @@ from eventlet.green import socket from eventlet.green import urllib from eventlet import patcher print 'patcher', socket, urllib -patcher.inject('%s', globals(), ('socket', socket), ('urllib', urllib)) +patcher.inject('base', globals(), ('socket', socket), ('urllib', urllib)) del patcher """ import_module_contents = """ -import %(mod)s -import httplib -print "importing", %(mod)s, httplib, %(mod)s.socket, %(mod)s.urllib +import patching +import socket +print "importing", patching, socket, patching.socket, patching.urllib """ class Patcher(LimitedTestCase): TEST_TIMEOUT=3 # starting processes is time-consuming def setUp(self): self._saved_syspath = sys.path - self.tempfiles = [] + self.tempdir = tempfile.mkdtemp('_patcher_test') def tearDown(self): sys.path = self._saved_syspath - for tf in self.tempfiles: - os.remove(tf) + shutil.rmtree(self.tempdir) - def write_to_tempfile(self, contents): - fn, filename = tempfile.mkstemp('_patcher_test.py') - fd = os.fdopen(fn, 'w') + def write_to_tempfile(self, name, contents): + filename = os.path.join(self.tempdir, name + '.py') + fd = open(filename, "w") fd.write(contents) fd.close() - self.tempfiles.append(filename) - return os.path.dirname(filename), os.path.basename(filename) def test_patch_a_module(self): - base = self.write_to_tempfile(base_module_contents) - base_modname = os.path.splitext(base[1])[0] - patching = self.write_to_tempfile(patching_module_contents % base_modname) - patching_modname = os.path.splitext(patching[1])[0] - importing = self.write_to_tempfile( - import_module_contents % dict(mod=patching_modname)) + self.write_to_tempfile("base", base_module_contents) + self.write_to_tempfile("patching", patching_module_contents) + self.write_to_tempfile("importing", import_module_contents) - python_path = os.pathsep.join(sys.path) - python_path += os.pathsep.join((base[0], patching[0], importing[0])) + python_path = os.pathsep.join(sys.path + [self.tempdir]) new_env = os.environ.copy() new_env['PYTHONPATH'] = python_path p = subprocess.Popen([sys.executable, - os.path.join(importing[0], importing[1])], + os.path.join(self.tempdir, "importing.py")], stdout=subprocess.PIPE, env=new_env) output = p.communicate() lines = output[0].split("\n") From 70da219fac11d8ddbe42b1a999395976f22a0b60 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Thu, 7 Jan 2010 18:19:46 -0800 Subject: [PATCH 03/10] Bumped up saranwrap test timeout again because it's so fucking fast. --- tests/saranwrap_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/saranwrap_test.py b/tests/saranwrap_test.py index ce84a45..517e9b3 100644 --- a/tests/saranwrap_test.py +++ b/tests/saranwrap_test.py @@ -32,7 +32,7 @@ class CoroutineCallingClass(object): class TestSaranwrap(LimitedTestCase): - TEST_TIMEOUT=3 + TEST_TIMEOUT=8 def assert_server_exists(self, prox): self.assert_(saranwrap.status(prox)) prox.foo = 0 From a868b1c857e43d538e3d613919df67f49b846eb8 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 10:06:20 -0800 Subject: [PATCH 04/10] Improved error reporting when we are on Windows and try to do something that Windows doesn't support. Patch from Nat. --- eventlet/greenio.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/eventlet/greenio.py b/eventlet/greenio.py index 0d6d1be..636039e 100644 --- a/eventlet/greenio.py +++ b/eventlet/greenio.py @@ -143,8 +143,22 @@ def set_nonblocking(fd): try: setblocking = fd.setblocking except AttributeError: - # This version of Python predates socket.setblocking() - import fcntl + # fd has no setblocking() method. It could be that this version of + # Python predates socket.setblocking(). In that case, we can still set + # the flag "by hand" on the underlying OS fileno using the fcntl + # module. + try: + import fcntl + except ImportError: + # Whoops, Windows has no fcntl module. This might not be a socket + # at all, but rather a file-like object with no setblocking() + # method. In particular, on Windows, pipes don't support + # non-blocking I/O and therefore don't have that method. Which + # means fcntl wouldn't help even if we could load it. + raise NotImplementedError("set_nonblocking() on a file object " + "with no setblocking() method " + "(Windows pipes don't support non-blocking I/O)") + # We managed to import fcntl. fileno = fd.fileno() flags = fcntl.fcntl(fileno, fcntl.F_GETFL) fcntl.fcntl(fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK) From 06157e647a2b7a7c67b08f34b60343d00b355e39 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 12:24:27 -0800 Subject: [PATCH 05/10] Fixed intermittent test failure in saranwrap, changed imports to comply with pyrage requirements. --- eventlet/saranwrap.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eventlet/saranwrap.py b/eventlet/saranwrap.py index 457f193..f522617 100644 --- a/eventlet/saranwrap.py +++ b/eventlet/saranwrap.py @@ -1,4 +1,4 @@ -from cPickle import dumps, loads +import cPickle as Pickle import os import struct import sys @@ -106,8 +106,8 @@ def _read_response(id, attribute, input, cp): try: str = _read_lp_hunk(input) _prnt(`str`) - response = loads(str) - except (AttributeError, DeadProcess), e: + response = Pickle.loads(str) + except (AttributeError, DeadProcess, Pickle.UnpicklingError), e: raise UnrecoverableError(e) _prnt("response: %s" % response) if response[0] == 'value': @@ -130,7 +130,7 @@ def _write_lp_hunk(stream, hunk): def _write_request(param, output): _prnt("request: %s" % param) - str = dumps(param) + str = Pickle.dumps(param) _write_lp_hunk(output, str) def _is_local(attribute): @@ -495,7 +495,7 @@ class Server(object): _log("Exiting normally") sys.exit(0) - request = loads(str_) + request = Pickle.loads(str_) _log("request: %s (%s)" % (request, self._objects)) req = request id = None @@ -558,7 +558,7 @@ class Server(object): def respond(self, body): _log("responding with: %s" % body) #_log("objects: %s" % self._objects) - s = dumps(body) + s = Pickle.dumps(body) _log(`s`) str_ = _write_lp_hunk(self._out, s) From d33bb039e22f13e009eecc0557be7d1c4789c951 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 12:39:10 -0800 Subject: [PATCH 06/10] Added silent timer support to pyevent hub, upgraded api_test to use actual unit test primitives rather than inventing its own. --- eventlet/hubs/pyevent.py | 3 ++- tests/api_test.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/eventlet/hubs/pyevent.py b/eventlet/hubs/pyevent.py index 6b8fbd2..3dab7d1 100644 --- a/eventlet/hubs/pyevent.py +++ b/eventlet/hubs/pyevent.py @@ -96,7 +96,8 @@ class Hub(BaseHub): self.schedule_call_global(0, api.getcurrent().parent.throw, *self.signal_exc_info) self.signal_exc_info = None else: - traceback.print_exc() + if not self.silent_timer_exceptions: + traceback.print_exc() def abort(self): self.schedule_call_global(0, self.greenlet.throw, api.GreenletExit) diff --git a/tests/api_test.py b/tests/api_test.py index 3e29cfe..343293d 100644 --- a/tests/api_test.py +++ b/tests/api_test.py @@ -210,12 +210,12 @@ class TestApi(TestCase): state.append('finished') g = api.spawn(test) api.sleep(DELAY/2) - assert state == ['start'], state + self.assertEquals(state, ['start']) api.kill(g) # will not get there, unless switching is explicitly scheduled by kill - assert state == ['start', 'except'], state + self.assertEquals(state,['start', 'except']) api.sleep(DELAY) - assert state == ['start', 'except', 'finished'], state + self.assertEquals(state, ['start', 'except', 'finished']) def test_nested_with_timeout(self): def func(): From c6e1910d0ad02119c96c676808a5da16a970dae9 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 15:36:17 -0800 Subject: [PATCH 07/10] Added continuous build links to index, tinkered with stdlib tests some more. --- doc/real_index.html | 4 +++- tests/stdlib/all.py | 8 ++++---- tests/stdlib/test_urllib2.py | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/real_index.html b/doc/real_index.html index f3b0bd7..0769d2e 100644 --- a/doc/real_index.html +++ b/doc/real_index.html @@ -99,7 +99,9 @@ easy_install eventlet

Links

diff --git a/tests/stdlib/all.py b/tests/stdlib/all.py index b6d3ccc..dea77b1 100644 --- a/tests/stdlib/all.py +++ b/tests/stdlib/all.py @@ -1,6 +1,6 @@ -""" Convenience module for running standard library tests with nose. The standard tests are not especially homogeneous, but they mostly expose a test_main method that does the work of selecting which tests to run based on what is supported by the platform. On its own, Nose would run all possible tests and many would fail; therefore we collect all of the test_main methods here in one module and Nose can run it. Hopefully in the future the standard tests get rewritten to be more self-contained. +""" Convenience module for running standard library tests with nose. The standard tests are not especially homogeneous, but they mostly expose a test_main method that does the work of selecting which tests to run based on what is supported by the platform. On its own, Nose would run all possible tests and many would fail; therefore we collect all of the test_main methods here in one module and Nose can run it. Hopefully in the future the standard tests get rewritten to be more nosey. -Many of these tests make connections to external servers, causing failures when run while disconnected from the internet. +Many of these tests make connections to external servers, and all.py tries to skip these tests rather than failing them, so you can get some work done on a plane. """ @@ -21,7 +21,7 @@ def import_main(g, name): # quick and dirty way of testing whether we can access # remote hosts; any tests that try internet connections -# will fail if we cannot +# will fail if we cannot import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: @@ -48,7 +48,7 @@ import_main(globals(), 'test_socketserver') if have_network_access: import_main(globals(), 'test_ssl') import_main(globals(), 'test_thread') -import_main(globals(), 'test_threading') +#import_main(globals(), 'test_threading') import_main(globals(), 'test_threading_local') if have_network_access: import_main(globals(), 'test_timeout') diff --git a/tests/stdlib/test_urllib2.py b/tests/stdlib/test_urllib2.py index 40735f4..1345ddb 100644 --- a/tests/stdlib/test_urllib2.py +++ b/tests/stdlib/test_urllib2.py @@ -8,6 +8,7 @@ patcher.inject('test.test_urllib2', ('urllib2', urllib2)) HandlerTests.test_file = patcher.patch_function(HandlerTests.test_file, ('socket', socket)) +OpenerDirectorTests.test_badly_named_methods = patcher.patch_function(OpenerDirectorTests.test_badly_named_methods, ('urllib2', urllib2)) if __name__ == "__main__": test_main() From 0f5a00a2ad3064f8476f3aac112bcd99cfc06dd2 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 18:15:38 -0800 Subject: [PATCH 08/10] Fixed all.py to be simpler and 2.4-compatible. --- tests/stdlib/all.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/stdlib/all.py b/tests/stdlib/all.py index dea77b1..28ec746 100644 --- a/tests/stdlib/all.py +++ b/tests/stdlib/all.py @@ -4,16 +4,16 @@ Many of these tests make connections to external servers, and all.py tries to sk """ -def import_main(g, name): +def import_main(name): try: - modobj = __import__(name, g, fromlist=['test_main']) + modobj = __import__(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: - g[method_name] = modobj.test_main + 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 @@ -33,26 +33,26 @@ except socket.error, e: print "Skipping network tests" have_network_access = False -import_main(globals(), 'test_select') -import_main(globals(), 'test_SimpleHTTPServer') -import_main(globals(), 'test_asynchat') -import_main(globals(), 'test_asyncore') -import_main(globals(), 'test_ftplib') -import_main(globals(), 'test_httplib') +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(globals(), 'test_httpservers') + import_main('test_httpservers') if have_network_access: - import_main(globals(), 'test_socket') -import_main(globals(), 'test_socket_ssl') -import_main(globals(), 'test_socketserver') + import_main('test_socket') +import_main('test_socket_ssl') +import_main('test_socketserver') if have_network_access: - import_main(globals(), 'test_ssl') -import_main(globals(), 'test_thread') -#import_main(globals(), 'test_threading') -import_main(globals(), 'test_threading_local') + import_main('test_ssl') +import_main('test_thread') +#import_main('test_threading') +import_main('test_threading_local') if have_network_access: - import_main(globals(), 'test_timeout') -import_main(globals(), 'test_urllib') + import_main('test_timeout') +import_main('test_urllib') if have_network_access: - import_main(globals(), 'test_urllib2') -import_main(globals(), 'test_urllib2_localnet') \ No newline at end of file + import_main('test_urllib2') +import_main('test_urllib2_localnet') \ No newline at end of file From bb9af896a3e2d6b315d5b61413b2dd9a3ca00433 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 18:28:19 -0800 Subject: [PATCH 09/10] Changed wrap_socket_with_coroutine_socket to not use tpool to wrap DNS by default. --- eventlet/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eventlet/util.py b/eventlet/util.py index ab6b5a2..069307b 100644 --- a/eventlet/util.py +++ b/eventlet/util.py @@ -69,7 +69,7 @@ except ImportError: return connection socket_already_wrapped = False -def wrap_socket_with_coroutine_socket(use_thread_pool=True): +def wrap_socket_with_coroutine_socket(use_thread_pool=False): global socket_already_wrapped if socket_already_wrapped: return From 9ec729c02367f79dfe5a5570801fd725f71d37f5 Mon Sep 17 00:00:00 2001 From: Ryan Williams Date: Fri, 8 Jan 2010 18:30:35 -0800 Subject: [PATCH 10/10] Fixed 2.4 stdlib test failure. --- tests/stdlib/test_urllib2.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/stdlib/test_urllib2.py b/tests/stdlib/test_urllib2.py index 1345ddb..14e6483 100644 --- a/tests/stdlib/test_urllib2.py +++ b/tests/stdlib/test_urllib2.py @@ -8,7 +8,10 @@ patcher.inject('test.test_urllib2', ('urllib2', urllib2)) HandlerTests.test_file = patcher.patch_function(HandlerTests.test_file, ('socket', socket)) -OpenerDirectorTests.test_badly_named_methods = patcher.patch_function(OpenerDirectorTests.test_badly_named_methods, ('urllib2', urllib2)) +try: + OpenerDirectorTests.test_badly_named_methods = patcher.patch_function(OpenerDirectorTests.test_badly_named_methods, ('urllib2', urllib2)) +except AttributeError: + pass # 2.4 doesn't have this test method if __name__ == "__main__": test_main()