Commits

Anonymous committed 65f00e2 Merge

merge with main repositroy.

Comments (0)

Files changed (7)

 * Ralf Schmitt, for wsgi/webob incompatibility bug report and suggested fix
 * Benoit Chesneau, bug report on green.os and patch to fix it
 * Slant, better iterator implementation in tpool
-* Ambroff, nice pygtk hub
+* Ambroff, nice pygtk hub example
+* Michael Carter, and Marcin Bachry, nice repro of a bug and good diagnosis leading to the fix
 The other way of greening an application is simply to monkeypatch the standard
 library.  This has the disadvantage of appearing quite magical, but the advantage of avoiding the late-binding problem.
 
-.. function:: eventlet.patcher.monkey_patch(all=True, os=False, select=False, socket=False, thread=False, time=False)
+.. function:: eventlet.patcher.monkey_patch(os=None, select=None, socket=None, thread=None, time=None)
 
-    By default, this function monkeypatches the key system modules by replacing their key elements with green equivalents.  The keyword arguments afford some control over which modules are patched, in case that's important.  If *all* is True, then all modules are patched regardless of the other arguments. If it's False, then the rest of the keyword arguments control patching of specific subsections of the standard library.  Most patch the single module of the same name (e.g. time=True means that the time module is patched [time.sleep is patched by eventlet.sleep]).  The exceptions to this rule are *socket*, which also patches the :mod:`ssl` module if present; and *thread*, which patches :mod:`thread`, :mod:`threading`, and :mod:`Queue`.
+    This function monkeypatches the key system modules by replacing their key elements with green equivalents.  If no arguments are specified, everything is patched::
+    
+        import eventlet
+        eventlet.monkey_patch()
+
+    The keyword arguments afford some control over which modules are patched, in case that's important.  Most patch the single module of the same name (e.g. time=True means that the time module is patched [time.sleep is patched by eventlet.sleep]).  The exceptions to this rule are *socket*, which also patches the :mod:`ssl` module if present; and *thread*, which patches :mod:`thread`, :mod:`threading`, and :mod:`Queue`.
     
     Here's an example of using monkey_patch to patch only a few modules::
     
         import eventlet
-        eventlet.monkey_patch(all=False, socket=True, select=True)
-    
-    It is important to call :func:`~eventlet.patcher.monkey_patch` as early in the lifetime of the application as possible.  Try to do it as one of the first lines in the main module.  The reason for this is that sometimes there is a class that inherits from a class that needs to be greened -- e.g. a class that inherits from socket.socket -- and inheritance is done at import time, so therefore the monkeypatching should happen before the derived class is defined.      It's safe to call monkey_patch multiple times.
+        eventlet.monkey_patch(socket=True, select=True)
+         
+    It is important to call :func:`~eventlet.patcher.monkey_patch` as early in the lifetime of the application as possible.  Try to do it as one of the first lines in the main module.  The reason for this is that sometimes there is a class that inherits from a class that needs to be greened -- e.g. a class that inherits from socket.socket -- and inheritance is done at import time, so therefore the monkeypatching should happen before the derived class is defined.      It's safe to call monkey_patch multiple times.

eventlet/green/threading.py

 from eventlet.green import time
 
 __patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident', '_sleep',
-               'local', 'stack_size']
+               'local', 'stack_size', 'Lock']
 
 patcher.inject('threading',
     globals(),

eventlet/patcher.py

     return _originals.get(modname)
 
 already_patched = {}
-def monkey_patch(all=True, os=False, select=False,
-                           socket=False, thread=False, time=False):
+def monkey_patch(**on):
     """Globally patches certain system modules to be greenthread-friendly.
 
     The keyword arguments afford some control over which modules are patched.
-    If *all* is True, then all modules are patched regardless of the other
-    arguments. If it's False, then the rest of the keyword arguments control
-    patching of specific subsections of the standard library.
-    Most patch the single module of the same name (os, time,
-    select).  The exceptions are socket, which also patches the ssl module if
-    present; and thread, which patches thread, threading, and Queue.
+    If no keyword arguments are supplied, all possible modules are patched.
+    If keywords are set to True, only the specified modules are patched.  E.g.,
+    ``monkey_patch(socket=True, select=True)`` patches only the select and 
+    socket modules.  Most arguments patch the single module of the same name 
+    (os, time, select).  The exceptions are socket, which also patches the ssl 
+    module if present; and thread, which patches thread, threading, and Queue.
 
     It's safe to call monkey_patch multiple times.
     """
+    accepted_args = set(('os', 'select', 'socket', 'thread', 'time'))
+    default_on = on.pop("all",None)
+    for k in on.iterkeys():
+        if k not in accepted_args:
+            raise TypeError("monkey_patch() got an unexpected "\
+                                "keyword argument %r" % k)
+    if default_on is None:
+        default_on = not (True in on.values())
+    for modname in accepted_args:
+        on.setdefault(modname, default_on)
+        
     modules_to_patch = []
-    if all or os and not already_patched.get('os'):
+    if on['os'] and not already_patched.get('os'):
         modules_to_patch += _green_os_modules()
         already_patched['os'] = True
-    if all or select and not already_patched.get('select'):
+    if on['select'] and not already_patched.get('select'):
         modules_to_patch += _green_select_modules()
         already_patched['select'] = True
-    if all or socket and not already_patched.get('socket'):
+    if on['socket'] and not already_patched.get('socket'):
         modules_to_patch += _green_socket_modules()
         already_patched['socket'] = True
-    if all or thread and not already_patched.get('thread'):
+    if on['thread'] and not already_patched.get('thread'):
         # hacks ahead
         threading = original('threading')
         import eventlet.green.threading as greenthreading
         greenthreading._patch_main_thread(threading)
         modules_to_patch += _green_thread_modules()
         already_patched['thread'] = True
-    if all or time and not already_patched.get('time'):
+    if on['time'] and not already_patched.get('time'):
         modules_to_patch += _green_time_modules()
         already_patched['time'] = True
 
     for name, mod in modules_to_patch:
         orig_mod = sys.modules.get(name)
         for attr_name in mod.__patched__:
-            #orig_attr = getattr(orig_mod, attr_name, None)
-            # @@tavis: line above wasn't used, not sure what author intended
             patched_attr = getattr(mod, attr_name, None)
             if patched_attr is not None:
                 setattr(orig_mod, attr_name, patched_attr)

tests/__init__.py

         self.timer = eventlet.Timeout(self.TEST_TIMEOUT, 
                                       TestIsTakingTooLong(self.TEST_TIMEOUT))
 
+    def reset_timeout(self, new_timeout):
+        """Changes the timeout duration; only has effect during one test case"""
+        import eventlet
+        self.timer.cancel()
+        self.timer = eventlet.Timeout(new_timeout, 
+                                      TestIsTakingTooLong(new_timeout))
+
     def tearDown(self):
         self.timer.cancel()
         try:

tests/patcher_test.py

         p = subprocess.Popen([sys.executable, 
                               os.path.join(self.tempdir, filename)],
                 stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=new_env)
-        return p
+        output, _ = p.communicate()
+        lines = output.split("\n")
+        return output, lines
 
+
+class ImportPatched(Patcher):
     def test_patch_a_module(self):
         self.write_to_tempfile("base", base_module_contents)
         self.write_to_tempfile("patching", patching_module_contents)
         self.write_to_tempfile("importing", import_module_contents)
-        p = self.launch_subprocess('importing.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assert_(lines[0].startswith('patcher'), repr(output[0]))
-        self.assert_(lines[1].startswith('base'), repr(output[0]))
-        self.assert_(lines[2].startswith('importing'), repr(output[0]))
-        self.assert_('eventlet.green.socket' in lines[1], repr(output[0]))
-        self.assert_('eventlet.green.urllib' in lines[1], repr(output[0]))
-        self.assert_('eventlet.green.socket' in lines[2], repr(output[0]))
-        self.assert_('eventlet.green.urllib' in lines[2], repr(output[0]))
-        self.assert_('eventlet.green.httplib' not in lines[2], repr(output[0]))
+        output, lines = self.launch_subprocess('importing.py')
+        self.assert_(lines[0].startswith('patcher'), repr(output))
+        self.assert_(lines[1].startswith('base'), repr(output))
+        self.assert_(lines[2].startswith('importing'), repr(output))
+        self.assert_('eventlet.green.socket' in lines[1], repr(output))
+        self.assert_('eventlet.green.urllib' in lines[1], repr(output))
+        self.assert_('eventlet.green.socket' in lines[2], repr(output))
+        self.assert_('eventlet.green.urllib' in lines[2], repr(output))
+        self.assert_('eventlet.green.httplib' not in lines[2], repr(output))
         
     def test_import_patched_defaults(self):
         self.write_to_tempfile("base", base_module_contents)
 print "newmod", base, base.socket, base.urllib.socket.socket
 """
         self.write_to_tempfile("newmod", new_mod)
-        p = self.launch_subprocess('newmod.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assert_(lines[0].startswith('base'), repr(output[0]))
-        self.assert_(lines[1].startswith('newmod'), repr(output[0]))
-        self.assert_('eventlet.green.socket' in lines[1], repr(output[0]))
-        self.assert_('GreenSocket' in lines[1], repr(output[0]))
-        
-    def test_monkey_patch(self):
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assert_(lines[0].startswith('base'), repr(output))
+        self.assert_(lines[1].startswith('newmod'), repr(output))
+        self.assert_('eventlet.green.socket' in lines[1], repr(output))
+        self.assert_('GreenSocket' in lines[1], repr(output))
+
+
+class MonkeyPatch(Patcher):        
+    def test_patched_modules(self):
         new_mod = """
 from eventlet import patcher
 patcher.monkey_patch()
 print "newmod", socket.socket, urllib.socket.socket
 """
         self.write_to_tempfile("newmod", new_mod)
-        p = self.launch_subprocess('newmod.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assert_(lines[0].startswith('newmod'), repr(output[0]))
-        self.assertEqual(lines[0].count('GreenSocket'), 2, repr(output[0]))
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assert_(lines[0].startswith('newmod'), repr(output))
+        self.assertEqual(lines[0].count('GreenSocket'), 2, repr(output))
         
     def test_early_patching(self):
         new_mod = """
 print "newmod"
 """
         self.write_to_tempfile("newmod", new_mod)
-        p = self.launch_subprocess('newmod.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assertEqual(len(lines), 2, repr(output[0]))
-        self.assert_(lines[0].startswith('newmod'), repr(output[0]))
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assertEqual(len(lines), 2, repr(output))
+        self.assert_(lines[0].startswith('newmod'), repr(output))
 
     def test_late_patching(self):
         new_mod = """
 print "newmod"
 """
         self.write_to_tempfile("newmod", new_mod)
-        p = self.launch_subprocess('newmod.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assertEqual(len(lines), 2, repr(output[0]))
-        self.assert_(lines[0].startswith('newmod'), repr(output[0]))
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assertEqual(len(lines), 2, repr(output))
+        self.assert_(lines[0].startswith('newmod'), repr(output))
         
     def test_tpool(self):
         new_mod = """
 print "newmod", tpool.execute(len, "hi2")
 """
         self.write_to_tempfile("newmod", new_mod)
-        p = self.launch_subprocess('newmod.py')
-        output = p.communicate()
-        lines = output[0].split("\n")
-        self.assertEqual(len(lines), 3, repr(output[0]))
-        self.assert_(lines[0].startswith('newmod'), repr(output[0]))
-        self.assert_('2' in lines[0], repr(output[0]))
-        self.assert_('3' in lines[1], repr(output[0]))
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assertEqual(len(lines), 3, repr(output))
+        self.assert_(lines[0].startswith('newmod'), repr(output))
+        self.assert_('2' in lines[0], repr(output))
+        self.assert_('3' in lines[1], repr(output))
         
+
+    def test_typeerror(self):
+        new_mod = """
+from eventlet import patcher
+patcher.monkey_patch(finagle=True)
+"""
+        self.write_to_tempfile("newmod", new_mod)
+        output, lines = self.launch_subprocess('newmod.py')
+        self.assert_(lines[-2].startswith('TypeError'), repr(output))
+        self.assert_('finagle' in lines[-2], repr(output))
+        
+
+    def assert_boolean_logic(self, call, expected):
+        new_mod = """
+from eventlet import patcher
+%s
+print "already_patched", ",".join(sorted(patcher.already_patched.keys()))
+""" % call
+        self.write_to_tempfile("newmod", new_mod)
+        output, lines = self.launch_subprocess('newmod.py')
+        ap = 'already_patched'
+        self.assert_(lines[0].startswith(ap), repr(output))
+        patched_modules = lines[0][len(ap):].strip() 
+        self.assertEqual(patched_modules, expected,
+                         "Logic:%s\nExpected: %s != %s" %(call, expected,
+                                                          patched_modules))
+
+    def test_boolean(self):
+        self.assert_boolean_logic("patcher.monkey_patch()",
+                                         'os,select,socket,thread,time')
+
+    def test_boolean_all(self):
+        self.assert_boolean_logic("patcher.monkey_patch(all=True)",
+                                         'os,select,socket,thread,time')
+
+    def test_boolean_all_single(self):
+        self.assert_boolean_logic("patcher.monkey_patch(all=True, socket=True)",
+                                         'os,select,socket,thread,time')
+
+    def test_boolean_all_negative(self):
+        self.assert_boolean_logic("patcher.monkey_patch(all=False, "\
+                                      "socket=False, select=True)",
+                                         'select')
+
+    def test_boolean_single(self):
+        self.assert_boolean_logic("patcher.monkey_patch(socket=True)",
+                                         'socket')
+
+    def test_boolean_double(self):
+        self.assert_boolean_logic("patcher.monkey_patch(socket=True,"\
+                                      " select=True)",
+                                         'select,socket')
+
+    def test_boolean_negative(self):
+        self.assert_boolean_logic("patcher.monkey_patch(socket=False)",
+                                         'os,select,thread,time')
+
+    def test_boolean_negative2(self):
+        self.assert_boolean_logic("patcher.monkey_patch(socket=False,"\
+                                      "time=False)",
+                                         'os,select,thread')
+
+    def test_conflicting_specifications(self):
+        self.assert_boolean_logic("patcher.monkey_patch(socket=False, "\
+                                      "select=True)",
+                                         'select')

tests/tpool_test.py

         
     @skip_with_pyevent
     def test_wrap_iterator2(self):
+        self.reset_timeout(5)  # might take a while due to imprecise sleeping
         def foo():
             import time
-            for x in xrange(10):
+            for x in xrange(2):
                 yield x
-                time.sleep(0.01)
+                time.sleep(0.001)
                 
         counter = [0]
         def tick():
-            for i in xrange(100):
+            for i in xrange(20000):
                 counter[0]+=1
-                eventlet.sleep(0.001)
+                eventlet.sleep()
                 
         gt = eventlet.spawn(tick)
         previtem = 0
             self.assert_(item >= previtem)
         # make sure the tick happened at least a few times so that we know
         # that our iterations in foo() were actually tpooled
-        self.assert_(counter[0] > 10)
+        self.assert_(counter[0] > 10, counter[0])
         gt.wait()