[PATCH 3 of 6] socketserver: make it compatible with python 2

Jun Wu quark at fb.com
Sun May 8 20:06:22 EDT 2016


# HG changeset patch
# User Jun Wu <quark at fb.com>
# Date 1462502252 -3600
#      Fri May 06 03:37:32 2016 +0100
# Node ID 0e68b512f4d9dad9c064342b0deebd45238f0cdf
# Parent  d94e32fbb8c35c2b536a74780f54d563a48e19c5
socketserver: make it compatible with python 2

The unmodified socketserver.py from Python 3 has issues with Python 2, namely
"import selectors" and a "print" difference.

This patch adds shim code for Python 2.6, 2.7 to makes it just work.

diff --git a/mercurial/socketserver.py b/mercurial/socketserver.py
--- a/mercurial/socketserver.py
+++ b/mercurial/socketserver.py
@@ -140,7 +140,11 @@
     import dummy_threading as threading
 
 import time as timemod
-time = timemod.monotonic
+if hasattr(timemod, 'monotonic'):
+    time = timemod.monotonic
+else:
+    # Python 2 does not have monotonic
+    time = timemod.time
 
 __all__ = ["BaseServer", "TCPServer", "UDPServer", "ForkingUDPServer",
            "ForkingTCPServer", "ThreadingUDPServer", "ThreadingTCPServer",
@@ -161,8 +165,44 @@
 try:
     import selectors
 except ImportError:
-    # Python 2 does not have selectors
-    pass
+    # Python 2 does not have selectors. This is a minimal "selectors"
+    # module just satisfying the needs of the "socketserver" module.
+    import select
+    class selectors(object):
+        EVENT_READ = (1 << 0)
+
+        class SelectSelector(object):
+            def __init__(self):
+                self._fileobj = None
+
+            def register(self, fileobj, events, data=None):
+                assert events == selectors.EVENT_READ
+                assert data is None
+                self._fileobj = fileobj
+
+            def select(self, timeout=None):
+                if self._fileobj is None:
+                    return False
+                # copied from Python 2.7 SocketServer._eintr_retry
+                while True:
+                    try:
+                        r, w, e = select.select([self._fileobj], [], [],
+                                                timeout)
+                        # the return value is incompatible with Python 3
+                        # since we don't want to introduce heavy stuff like
+                        # SelectorKey.
+                        # it's good enough for all the use cases in this
+                        # socketserver module.
+                        return r
+                    except (OSError, select.error) as e:
+                        if e.args[0] != errno.EINTR:
+                            raise
+
+            def __enter__(self):
+                return self
+
+            def __exit__(self, *args):
+                pass
 
 # poll/select have the advantage of not requiring any extra file descriptor,
 # contrarily to epoll/kqueue (also, they require a single syscall).
@@ -388,8 +428,8 @@
 
         """
         print('-'*40)
-        print('Exception happened during processing of request from', end=' ')
-        print(client_address)
+        print('Exception happened during processing of request from %s'
+              % client_address)
         import traceback
         traceback.print_exc() # XXX But this goes to stderr!
         print('-'*40)
@@ -573,7 +613,10 @@
             except ChildProcessError:
                 # we don't have any children, we're done
                 self.active_children.clear()
-            except OSError:
+            except OSError as e:
+                # "ChildProcessError" for Python 2
+                if e.errno == errno.ECHILD:
+                    self.active_children.clear()
                 break
 
         # Now reap all defunct children.
@@ -586,8 +629,10 @@
             except ChildProcessError:
                 # someone else reaped it
                 self.active_children.discard(pid)
-            except OSError:
-                pass
+            except OSError as e:
+                # "ChildProcessError" for Python 2
+                if e.errno == errno.ECHILD:
+                    self.active_children.discard(pid)
 
     def handle_timeout(self):
         """Wait for zombies after self.timeout seconds of inactivity.


More information about the Mercurial-devel mailing list