[Python-modules-commits] r20893 - in packages/python-eventlet/trunk/debian (8 files)

stefanor at users.alioth.debian.org stefanor at users.alioth.debian.org
Wed Mar 21 15:32:34 UTC 2012


    Date: Wednesday, March 21, 2012 @ 15:32:33
  Author: stefanor
Revision: 20893

* Apply upstream threading related memory leak patch (Closes: #661781)
* Bump Standards-Version to 3.9.3, no changes needed.
* Update machine-readable copyright format to 1.0.

Added:
  packages/python-eventlet/trunk/debian/patches/retry-on-timeout
    (from rev 20366, packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch)
  packages/python-eventlet/trunk/debian/patches/threading-leak
Modified:
  packages/python-eventlet/trunk/debian/changelog
  packages/python-eventlet/trunk/debian/control
  packages/python-eventlet/trunk/debian/copyright
  packages/python-eventlet/trunk/debian/patches/series
Deleted:
  packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch
  packages/python-eventlet/trunk/debian/source/local-options

Modified: packages/python-eventlet/trunk/debian/changelog
===================================================================
--- packages/python-eventlet/trunk/debian/changelog	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/changelog	2012-03-21 15:32:33 UTC (rev 20893)
@@ -1,4 +1,4 @@
-python-eventlet (0.9.16-2) UNRELEASED; urgency=low
+python-eventlet (0.9.16-2) unstable; urgency=low
 
   [ Soren Hansen ]
   * Add myself to Uploaders.
@@ -10,8 +10,11 @@
     - Don't manually symlink jquery.js to libjs-jquery.
   * Don't compress Sphinx _sources.
   * Include examples.
+  * Apply upstream threading related memory leak patch (Closes: #661781)
+  * Bump Standards-Version to 3.9.3, no changes needed.
+  * Update machine-readable copyright format to 1.0.
 
- -- Soren Hansen <soren at ubuntu.com>  Wed, 08 Jun 2011 17:57:40 +0200
+ -- Stefano Rivera <stefanor at debian.org>  Wed, 21 Mar 2012 17:31:35 +0200
 
 python-eventlet (0.9.16-1) unstable; urgency=low
 

Modified: packages/python-eventlet/trunk/debian/control
===================================================================
--- packages/python-eventlet/trunk/debian/control	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/control	2012-03-21 15:32:33 UTC (rev 20893)
@@ -18,7 +18,7 @@
  python-sphinx (>= 1.0.7+dfsg),
  python-zmq
 X-Python-Version: >= 2.5
-Standards-Version: 3.9.2
+Standards-Version: 3.9.3
 Homepage: http://eventlet.net
 Vcs-Svn: svn://svn.debian.org/python-modules/packages/python-eventlet/trunk/
 Vcs-Browser: http://svn.debian.org/viewsvn/python-modules/packages/python-eventlet/trunk/

Modified: packages/python-eventlet/trunk/debian/copyright
===================================================================
--- packages/python-eventlet/trunk/debian/copyright	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/copyright	2012-03-21 15:32:33 UTC (rev 20893)
@@ -1,4 +1,4 @@
-Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=174
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: Eventlet
 Upstream-Contact: Ryan Williams <breath at alum.mit.edu>
 Source: http://eventlet.net
@@ -104,7 +104,7 @@
 Copyright:
  2010,      Monty Taylor <mordred at inaugust.com>
  2010-2011, Soren Hansen <soren at ubuntu.com>
- 2011,      Stefano Rivera <stefanor at debian.org>
+ 2011-2012, Stefano Rivera <stefanor at debian.org>
 License: generic-bsd
 
 License: generic-bsd

Copied: packages/python-eventlet/trunk/debian/patches/retry-on-timeout (from rev 20366, packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch)
===================================================================
--- packages/python-eventlet/trunk/debian/patches/retry-on-timeout	                        (rev 0)
+++ packages/python-eventlet/trunk/debian/patches/retry-on-timeout	2012-03-21 15:32:33 UTC (rev 20893)
@@ -0,0 +1,192 @@
+Description: If an operation times out, try one last time.
+ This addresses a problem where a timeout fires even though the
+ connection was actually correctly established.
+Origin: Chris Behrens, https://bitbucket-assetroot.s3.amazonaws.com/which_linden/eventlet/20110601/87/eventlet-socket-timeout.diff
+Bug: https://bitbucket.org/which_linden/eventlet/issue/87/socket-connects-are-incorrectly-reported
+Bug-Ubuntu: https://launchpad.net/bugs/771512
+Reviewed-By: Soren Hansen <soren at ubuntu.com>
+Last-Update: 2011-06-01
+
+--- a/eventlet/greenio.py
++++ b/eventlet/greenio.py
+@@ -174,8 +174,16 @@
+                     return
+                 if time.time() >= end:
+                     raise socket.timeout("timed out")
+-                trampoline(fd, write=True, timeout=end-time.time(),
+-                        timeout_exc=socket.timeout("timed out"))
++                try:
++                    trampoline(fd, write=True, timeout=end-time.time(),
++                            timeout_exc=socket.timeout("timed out"))
++                except socket.timeout, e:
++                    try:
++                        if socket_connect(fd, address):
++                            return
++                        raise e
++                    except:
++                        raise e
+                 socket_checkerr(fd)
+ 
+     def connect_ex(self, address):
+@@ -197,8 +205,16 @@
+                         return 0
+                     if time.time() >= end:
+                         raise socket.timeout(errno.EAGAIN)
+-                    trampoline(fd, write=True, timeout=end-time.time(),
+-                            timeout_exc=socket.timeout(errno.EAGAIN))
++                    try:
++                        trampoline(fd, write=True, timeout=end-time.time(),
++                                timeout_exc=socket.timeout(errno.EAGAIN))
++                    except socket.timeout, e:
++                        try:
++                            if socket_connect(fd, address):
++                                return
++                            raise e
++                        except:
++                            raise e
+                     socket_checkerr(fd)
+                 except socket.error, ex:
+                     return get_errno(ex)
+@@ -218,42 +234,43 @@
+             "makefile instead", DeprecationWarning, stacklevel=2)
+         return self.makefile(*args, **kw)
+ 
+-    def recv(self, buflen, flags=0):
+-        fd = self.fd
++    def _read_io(self, fd, f, *args, **kwargs):
+         if self.act_non_blocking:
+-            return fd.recv(buflen, flags)
++            return f(*args, **kwargs)
+         while True:
+             try:
+-                return fd.recv(buflen, flags)
++                return f(*args, **kwargs)
+             except socket.error, e:
+                 if get_errno(e) in SOCKET_BLOCKING:
+                     pass
+-                elif get_errno(e) in SOCKET_CLOSED:
++                # XXX -- Why does recv() do this?
++                elif f == fd.recv and get_errno(e) in SOCKET_CLOSED:
+                     return ''
+                 else:
+                     raise
+-            trampoline(fd, 
+-                read=True, 
+-                timeout=self.gettimeout(), 
+-                timeout_exc=socket.timeout("timed out"))
++            try:
++                trampoline(fd, 
++                        read=True, 
++                        timeout=self.gettimeout(), 
++                        timeout_exc=socket.timeout("timed out"))
++            except socket.timeout, e:
++                # Try one last time to see if the timeout is 'real'
++                try:
++                    return f(*args, **kwargs)
++                except:
++                    raise e
++
++    def recv(self, buflen, flags=0):
++        return self._read_io(self.fd, self.fd.recv, buflen, flags)
+ 
+     def recvfrom(self, *args):
+-        if not self.act_non_blocking:
+-            trampoline(self.fd, read=True, timeout=self.gettimeout(),
+-                    timeout_exc=socket.timeout("timed out"))
+-        return self.fd.recvfrom(*args)
++        return self._read_io(self.fd, self.fd.recvfrom, *args)
+ 
+     def recvfrom_into(self, *args):
+-        if not self.act_non_blocking:
+-            trampoline(self.fd, read=True, timeout=self.gettimeout(),
+-                    timeout_exc=socket.timeout("timed out"))
+-        return self.fd.recvfrom_into(*args)
++        return self._read_io(self.fd, self.fd.recvfrom_into, *args)
+ 
+     def recv_into(self, *args):
+-        if not self.act_non_blocking:
+-            trampoline(self.fd, read=True, timeout=self.gettimeout(),
+-                    timeout_exc=socket.timeout("timed out"))
+-        return self.fd.recv_into(*args)
++        return self._read_io(self.fd, self.fd.recv_into, *args)
+ 
+     def send(self, data, flags=0):
+         fd = self.fd
+@@ -264,7 +281,7 @@
+         total_sent = 0
+         len_data = len(data)
+ 
+-        while 1:
++        while True:
+             try:
+                 total_sent += fd.send(data[total_sent:], flags)
+             except socket.error, e:
+@@ -274,8 +291,15 @@
+             if total_sent == len_data:
+                 break
+ 
+-            trampoline(self.fd, write=True, timeout=self.gettimeout(),
+-                    timeout_exc=socket.timeout("timed out"))
++            try:
++                trampoline(fd, write=True, timeout=self.gettimeout(),
++                        timeout_exc=socket.timeout("timed out"))
++            except socket.timeout, e:
++                # Try one last time to see if the timeout is 'real'
++                try:
++                    total_sent += fd.send(data[total_sent:], flags)
++                except:
++                    raise e
+ 
+         return total_sent
+ 
+@@ -286,8 +310,26 @@
+             tail += self.send(data[tail:], flags)
+ 
+     def sendto(self, *args):
+-        trampoline(self.fd, write=True)
+-        return self.fd.sendto(*args)
++        fd = self.fd
++        if self.act_non_blocking:
++            return fd.sendto(*args)
++        while True:
++            try:
++                return fd.sendto(*args)
++            except socket.error, e:
++                if get_errno(e) in SOCKET_BLOCKING:
++                    pass
++                else:
++                    raise
++            try:
++                trampoline(fd, write=True, timeout=self.gettimeout(),
++                        timeout_exc=socket.timeout("timed out"))
++            except socket.timeout, e:
++                # Try one last time to see if the timeout is 'real'
++                try:
++                    return fd.sendto(*args)
++                except:
++                    raise e
+ 
+     def setblocking(self, flag):
+         if flag:
+--- a/tests/greenio_test.py
++++ b/tests/greenio_test.py
+@@ -133,7 +133,8 @@
+             self.assertEqual(e.args[0], 'timed out')
+ 
+     def test_recvfrom_into_timeout(self):
+-        buf = buffer(array.array('B'))
++        buf = array.array('B')
++        buf.fromstring('\0')
+ 
+         gs = greenio.GreenSocket(
+             socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
+@@ -148,7 +149,8 @@
+             self.assertEqual(e.args[0], 'timed out')
+ 
+     def test_recv_into_timeout(self):
+-        buf = buffer(array.array('B'))
++        buf = array.array('B')
++        buf.fromstring('\0')
+ 
+         listener = greenio.GreenSocket(socket.socket())
+         listener.bind(('', 0))

Deleted: packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch
===================================================================
--- packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/patches/retry-on-timeout.patch	2012-03-21 15:32:33 UTC (rev 20893)
@@ -1,192 +0,0 @@
-Description: If an operation times out, try one last time.
- This addresses a problem where a timeout fires even though the
- connection was actually correctly established.
-Origin: Chris Behrens, https://bitbucket-assetroot.s3.amazonaws.com/which_linden/eventlet/20110601/87/eventlet-socket-timeout.diff
-Bug: https://bitbucket.org/which_linden/eventlet/issue/87/socket-connects-are-incorrectly-reported
-Bug-Ubuntu: https://launchpad.net/bugs/771512
-Reviewed-By: Soren Hansen <soren at ubuntu.com>
-Last-Update: 2011-06-01
-
---- a/eventlet/greenio.py
-+++ b/eventlet/greenio.py
-@@ -174,8 +174,16 @@
-                     return
-                 if time.time() >= end:
-                     raise socket.timeout("timed out")
--                trampoline(fd, write=True, timeout=end-time.time(),
--                        timeout_exc=socket.timeout("timed out"))
-+                try:
-+                    trampoline(fd, write=True, timeout=end-time.time(),
-+                            timeout_exc=socket.timeout("timed out"))
-+                except socket.timeout, e:
-+                    try:
-+                        if socket_connect(fd, address):
-+                            return
-+                        raise e
-+                    except:
-+                        raise e
-                 socket_checkerr(fd)
- 
-     def connect_ex(self, address):
-@@ -197,8 +205,16 @@
-                         return 0
-                     if time.time() >= end:
-                         raise socket.timeout(errno.EAGAIN)
--                    trampoline(fd, write=True, timeout=end-time.time(),
--                            timeout_exc=socket.timeout(errno.EAGAIN))
-+                    try:
-+                        trampoline(fd, write=True, timeout=end-time.time(),
-+                                timeout_exc=socket.timeout(errno.EAGAIN))
-+                    except socket.timeout, e:
-+                        try:
-+                            if socket_connect(fd, address):
-+                                return
-+                            raise e
-+                        except:
-+                            raise e
-                     socket_checkerr(fd)
-                 except socket.error, ex:
-                     return get_errno(ex)
-@@ -218,42 +234,43 @@
-             "makefile instead", DeprecationWarning, stacklevel=2)
-         return self.makefile(*args, **kw)
- 
--    def recv(self, buflen, flags=0):
--        fd = self.fd
-+    def _read_io(self, fd, f, *args, **kwargs):
-         if self.act_non_blocking:
--            return fd.recv(buflen, flags)
-+            return f(*args, **kwargs)
-         while True:
-             try:
--                return fd.recv(buflen, flags)
-+                return f(*args, **kwargs)
-             except socket.error, e:
-                 if get_errno(e) in SOCKET_BLOCKING:
-                     pass
--                elif get_errno(e) in SOCKET_CLOSED:
-+                # XXX -- Why does recv() do this?
-+                elif f == fd.recv and get_errno(e) in SOCKET_CLOSED:
-                     return ''
-                 else:
-                     raise
--            trampoline(fd, 
--                read=True, 
--                timeout=self.gettimeout(), 
--                timeout_exc=socket.timeout("timed out"))
-+            try:
-+                trampoline(fd, 
-+                        read=True, 
-+                        timeout=self.gettimeout(), 
-+                        timeout_exc=socket.timeout("timed out"))
-+            except socket.timeout, e:
-+                # Try one last time to see if the timeout is 'real'
-+                try:
-+                    return f(*args, **kwargs)
-+                except:
-+                    raise e
-+
-+    def recv(self, buflen, flags=0):
-+        return self._read_io(self.fd, self.fd.recv, buflen, flags)
- 
-     def recvfrom(self, *args):
--        if not self.act_non_blocking:
--            trampoline(self.fd, read=True, timeout=self.gettimeout(),
--                    timeout_exc=socket.timeout("timed out"))
--        return self.fd.recvfrom(*args)
-+        return self._read_io(self.fd, self.fd.recvfrom, *args)
- 
-     def recvfrom_into(self, *args):
--        if not self.act_non_blocking:
--            trampoline(self.fd, read=True, timeout=self.gettimeout(),
--                    timeout_exc=socket.timeout("timed out"))
--        return self.fd.recvfrom_into(*args)
-+        return self._read_io(self.fd, self.fd.recvfrom_into, *args)
- 
-     def recv_into(self, *args):
--        if not self.act_non_blocking:
--            trampoline(self.fd, read=True, timeout=self.gettimeout(),
--                    timeout_exc=socket.timeout("timed out"))
--        return self.fd.recv_into(*args)
-+        return self._read_io(self.fd, self.fd.recv_into, *args)
- 
-     def send(self, data, flags=0):
-         fd = self.fd
-@@ -264,7 +281,7 @@
-         total_sent = 0
-         len_data = len(data)
- 
--        while 1:
-+        while True:
-             try:
-                 total_sent += fd.send(data[total_sent:], flags)
-             except socket.error, e:
-@@ -274,8 +291,15 @@
-             if total_sent == len_data:
-                 break
- 
--            trampoline(self.fd, write=True, timeout=self.gettimeout(),
--                    timeout_exc=socket.timeout("timed out"))
-+            try:
-+                trampoline(fd, write=True, timeout=self.gettimeout(),
-+                        timeout_exc=socket.timeout("timed out"))
-+            except socket.timeout, e:
-+                # Try one last time to see if the timeout is 'real'
-+                try:
-+                    total_sent += fd.send(data[total_sent:], flags)
-+                except:
-+                    raise e
- 
-         return total_sent
- 
-@@ -286,8 +310,26 @@
-             tail += self.send(data[tail:], flags)
- 
-     def sendto(self, *args):
--        trampoline(self.fd, write=True)
--        return self.fd.sendto(*args)
-+        fd = self.fd
-+        if self.act_non_blocking:
-+            return fd.sendto(*args)
-+        while True:
-+            try:
-+                return fd.sendto(*args)
-+            except socket.error, e:
-+                if get_errno(e) in SOCKET_BLOCKING:
-+                    pass
-+                else:
-+                    raise
-+            try:
-+                trampoline(fd, write=True, timeout=self.gettimeout(),
-+                        timeout_exc=socket.timeout("timed out"))
-+            except socket.timeout, e:
-+                # Try one last time to see if the timeout is 'real'
-+                try:
-+                    return fd.sendto(*args)
-+                except:
-+                    raise e
- 
-     def setblocking(self, flag):
-         if flag:
---- a/tests/greenio_test.py
-+++ b/tests/greenio_test.py
-@@ -133,7 +133,8 @@
-             self.assertEqual(e.args[0], 'timed out')
- 
-     def test_recvfrom_into_timeout(self):
--        buf = buffer(array.array('B'))
-+        buf = array.array('B')
-+        buf.fromstring('\0')
- 
-         gs = greenio.GreenSocket(
-             socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
-@@ -148,7 +149,8 @@
-             self.assertEqual(e.args[0], 'timed out')
- 
-     def test_recv_into_timeout(self):
--        buf = buffer(array.array('B'))
-+        buf = array.array('B')
-+        buf.fromstring('\0')
- 
-         listener = greenio.GreenSocket(socket.socket())
-         listener.bind(('', 0))

Modified: packages/python-eventlet/trunk/debian/patches/series
===================================================================
--- packages/python-eventlet/trunk/debian/patches/series	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/patches/series	2012-03-21 15:32:33 UTC (rev 20893)
@@ -1 +1,2 @@
-retry-on-timeout.patch
+retry-on-timeout
+threading-leak

Added: packages/python-eventlet/trunk/debian/patches/threading-leak
===================================================================
--- packages/python-eventlet/trunk/debian/patches/threading-leak	                        (rev 0)
+++ packages/python-eventlet/trunk/debian/patches/threading-leak	2012-03-21 15:32:33 UTC (rev 20893)
@@ -0,0 +1,371 @@
+Description: Monkey patch threading.current_thread() as well
+ Patching thread.get_ident() but not threading.current_thread() can
+ result in _DummyThread objects being created. These objects will
+ never be garbage collected and will leak memory. In a long running
+ process (like a daemon), this can result in a pretty significant
+ memory leak if it uses green threads regularly.
+Author: User Johannes Erdfelt <johannes at erdfelt.com>
+Bug-Debian: http://bugs.debian.org/661781
+Bug-Eventlet: https://bitbucket.org/which_linden/eventlet/issue/115
+Origin: https://bitbucket.org/which_linden/eventlet/changeset/2a02c700f51a
+        https://bitbucket.org/which_linden/eventlet/changeset/6603e234fc56
+        https://bitbucket.org/which_linden/eventlet/changeset/55b6de9bd947
+        https://bitbucket.org/which_linden/eventlet/changeset/f3fd4562f347
+Applied-Upstream: https://bitbucket.org/which_linden/eventlet/pull-request/10/monkey-patch-threadingcurrent_thread-as
+
+--- a/eventlet/green/threading.py
++++ b/eventlet/green/threading.py
+@@ -1,9 +1,16 @@
++"""Implements the standard threading module, using greenthreads."""
+ from eventlet import patcher
+ from eventlet.green import thread
+ from eventlet.green import time
++from eventlet.support import greenlets as greenlet
+ 
+ __patched__ = ['_start_new_thread', '_allocate_lock', '_get_ident', '_sleep',
+-               'local', 'stack_size', 'Lock']
++               'local', 'stack_size', 'Lock', 'currentThread',
++               'current_thread', '_after_fork', '_shutdown']
++
++__orig_threading = patcher.original('threading')
++__threadlocal = __orig_threading.local()
++
+ 
+ patcher.inject('threading',
+     globals(),
+@@ -11,3 +18,103 @@
+     ('time', time))
+ 
+ del patcher
++
++
++_count = 1
++class _GreenThread(object):
++    """Wrapper for GreenThread objects to provide Thread-like attributes
++    and methods"""
++    def __init__(self, g):
++        global _count
++        self._g = g
++        self._name = 'GreenThread-%d' % _count
++        _count += 1
++
++    def __repr__(self):
++        return '<_GreenThread(%s, %r)>' % (self._name, self._g)
++
++    def join(self, timeout=None):
++        return self._g.wait()
++
++    @property
++    def name(self):
++        return self._name
++
++    @name.setter
++    def name(self, name):
++        self._name = str(name)
++
++    def getName(self):
++        return self.name
++    get_name = getName
++
++    def setName(self, name):
++        self.name = name
++    set_name = setName
++
++    @property
++    def ident(self):
++        return id(self._g)
++
++    def isAlive(self):
++        return True
++    is_alive = isAlive
++
++    @property
++    def daemon(self):
++        return True
++
++    def isDaemon(self):
++        return self.daemon
++    is_daemon = isDaemon
++
++
++__threading = None
++
++def _fixup_thread(t):
++    # Some third-party packages (lockfile) will try to patch the
++    # threading.Thread class with a get_name attribute if it doesn't
++    # exist. Since we might return Thread objects from the original
++    # threading package that won't get patched, let's make sure each
++    # individual object gets patched too our patched threading.Thread
++    # class has been patched. This is why monkey patching can be bad...
++    global __threading
++    if not __threading:
++        __threading = __import__('threading')
++
++    if (hasattr(__threading.Thread, 'get_name') and
++        not hasattr(t, 'get_name')):
++        t.get_name = t.getName
++    return t
++
++
++def current_thread():
++    g = greenlet.getcurrent()
++    if not g:
++        # Not currently in a greenthread, fall back to standard function
++        return _fixup_thread(__orig_threading.current_thread())
++
++    try:
++        active = __threadlocal.active
++    except AttributeError:
++        active = __threadlocal.active = {}
++    
++    try:
++        t = active[id(g)]
++    except KeyError:
++        # Add green thread to active if we can clean it up on exit
++        def cleanup(g):
++            del active[id(g)]
++        try:
++            g.link(cleanup)
++        except AttributeError:
++            # Not a GreenThread type, so there's no way to hook into
++            # the green thread exiting. Fall back to the standard
++            # function then.
++            t = _fixup_thread(__orig_threading.current_thread())
++        else:
++            t = active[id(g)] = _GreenThread(g)
++
++    return t
++
++currentThread = current_thread
+--- a/eventlet/patcher.py
++++ b/eventlet/patcher.py
+@@ -223,7 +223,6 @@
+         on.setdefault(modname, default_on)
+         
+     modules_to_patch = []
+-    patched_thread = False
+     if on['os'] and not already_patched.get('os'):
+         modules_to_patch += _green_os_modules()
+         already_patched['os'] = True
+@@ -234,7 +233,6 @@
+         modules_to_patch += _green_socket_modules()
+         already_patched['socket'] = True
+     if on['thread'] and not already_patched.get('thread'):
+-        patched_thread = True
+         modules_to_patch += _green_thread_modules()
+         already_patched['thread'] = True
+     if on['time'] and not already_patched.get('time'):
+@@ -266,27 +264,9 @@
+                 patched_attr = getattr(mod, attr_name, None)
+                 if patched_attr is not None:
+                     setattr(orig_mod, attr_name, patched_attr)
+-
+-        # hacks ahead; this is necessary to prevent a KeyError on program exit
+-        if patched_thread:
+-            _patch_main_thread(sys.modules['threading'])
+     finally:
+         imp.release_lock()
+ 
+-def _patch_main_thread(mod):
+-    """This is some gnarly patching specific to the threading module;
+-    threading will always be initialized prior to monkeypatching, and
+-    its _active dict will have the wrong key (it uses the real thread
+-    id but once it's patched it will use the greenlet ids); so what we
+-    do is rekey the _active dict so that the main thread's entry uses
+-    the greenthread key.  Other threads' keys are ignored."""
+-    thread = original('thread')
+-    curthread = mod._active.pop(thread.get_ident(), None)
+-    if curthread:
+-        import eventlet.green.thread
+-        mod._active[eventlet.green.thread.get_ident()] = curthread
+-
+-
+ def is_monkey_patched(module):
+     """Returns True if the given module is monkeypatched currently, False if
+     not.  *module* can be either the module itself or its name.
+--- a/tests/patcher_test.py
++++ b/tests/patcher_test.py
+@@ -293,5 +293,183 @@
+         self.assertEqual(output, "done\n", output)
+ 
+ 
++class Threading(ProcessBase):
++    def test_orig_thread(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++from eventlet import patcher
++import threading
++_threading = patcher.original('threading')
++def test():
++    print repr(threading.current_thread())
++t = _threading.Thread(target=test)
++t.start()
++t.join()
++print len(threading._active)
++print len(_threading._active)
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 4, "\n".join(lines))
++        self.assert_(lines[0].startswith('<Thread'), lines[0])
++        self.assertEqual(lines[1], "1", lines[1])
++        self.assertEqual(lines[2], "1", lines[2])
++
++    def test_threading(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++import threading
++def test():
++    print repr(threading.current_thread())
++t = threading.Thread(target=test)
++t.start()
++t.join()
++print len(threading._active)
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assert_(lines[0].startswith('<_MainThread'), lines[0])
++        self.assertEqual(lines[1], "1", lines[1])
++
++    def test_tpool(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++from eventlet import tpool
++import threading
++def test():
++    print repr(threading.current_thread())
++tpool.execute(test)
++print len(threading._active)
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assert_(lines[0].startswith('<Thread'), lines[0])
++        self.assertEqual(lines[1], "1", lines[1])
++
++    def test_greenlet(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++from eventlet import event
++import threading
++evt = event.Event()
++def test():
++    print repr(threading.current_thread())
++    evt.send()
++eventlet.spawn_n(test)
++evt.wait()
++print len(threading._active)
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assert_(lines[0].startswith('<_MainThread'), lines[0])
++        self.assertEqual(lines[1], "1", lines[1])
++
++    def test_greenthread(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++import threading
++def test():
++    print repr(threading.current_thread())
++t = eventlet.spawn(test)
++t.wait()
++print len(threading._active)
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assert_(lines[0].startswith('<_GreenThread'), lines[0])
++        self.assertEqual(lines[1], "1", lines[1])
++
++    def test_keyerror(self):
++        new_mod = """import eventlet
++eventlet.monkey_patch()
++"""
++        self.write_to_tempfile("newmod", new_mod)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 1, "\n".join(lines))
++
++
++class GreenThreadWrapper(ProcessBase):
++    prologue = """import eventlet
++eventlet.monkey_patch()
++import threading
++def test():
++    t = threading.current_thread()
++"""
++    epilogue = """
++t = eventlet.spawn(test)
++t.wait()
++"""
++
++    def test_join(self):
++        self.write_to_tempfile("newmod", self.prologue + """
++    def test2():
++        global t2
++        t2 = threading.current_thread()
++    eventlet.spawn(test2)
++""" + self.epilogue + """
++print repr(t2)
++t2.join()
++""")
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 2, "\n".join(lines))
++        self.assert_(lines[0].startswith('<_GreenThread'), lines[0])
++
++    def test_name(self):
++        self.write_to_tempfile("newmod", self.prologue + """
++    print t.name
++    print t.getName()
++    print t.get_name()
++    t.name = 'foo'
++    print t.name
++    print t.getName()
++    print t.get_name()
++    t.setName('bar')
++    print t.name
++    print t.getName()
++    print t.get_name()
++""" + self.epilogue)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 10, "\n".join(lines))
++        for i in xrange(0, 3):
++            self.assertEqual(lines[i], "GreenThread-1", lines[i])
++        for i in xrange(3, 6):
++            self.assertEqual(lines[i], "foo", lines[i])
++        for i in xrange(6, 9):
++            self.assertEqual(lines[i], "bar", lines[i])
++
++    def test_ident(self):
++        self.write_to_tempfile("newmod", self.prologue + """
++    print id(t._g)
++    print t.ident
++""" + self.epilogue)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assertEqual(lines[0], lines[1])
++
++    def test_is_alive(self):
++        self.write_to_tempfile("newmod", self.prologue + """
++    print t.is_alive()
++    print t.isAlive()
++""" + self.epilogue)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assertEqual(lines[0], "True", lines[0])
++        self.assertEqual(lines[1], "True", lines[1])
++
++    def test_is_daemon(self):
++        self.write_to_tempfile("newmod", self.prologue + """
++    print t.is_daemon()
++    print t.isDaemon()
++""" + self.epilogue)
++        output, lines = self.launch_subprocess('newmod')
++        self.assertEqual(len(lines), 3, "\n".join(lines))
++        self.assertEqual(lines[0], "True", lines[0])
++        self.assertEqual(lines[1], "True", lines[1])
++
++
+ if __name__ == '__main__':
+     main()

Deleted: packages/python-eventlet/trunk/debian/source/local-options
===================================================================
--- packages/python-eventlet/trunk/debian/source/local-options	2012-03-21 02:53:29 UTC (rev 20892)
+++ packages/python-eventlet/trunk/debian/source/local-options	2012-03-21 15:32:33 UTC (rev 20893)
@@ -1 +0,0 @@
-abort-on-upstream-changes




More information about the Python-modules-commits mailing list