[Python-checkins] r85220 - in python/branches/py3k: Doc/library/asyncore.rst Doc/whatsnew/3.2.rst Lib/asyncore.py Lib/smtpd.py Lib/test/test_asyncore.py Lib/test/test_ftplib.py Lib/test/test_poplib.py Lib/test/test_smtplib.py Lib/test/test_ssl.py Misc/NEWS

giampaolo.rodola python-checkins at python.org
Mon Oct 4 23:08:36 CEST 2010


Author: giampaolo.rodola
Date: Mon Oct  4 23:08:36 2010
New Revision: 85220

Log:
Fix issue 6706: adds new handle_accepted() method to asyncore.dispatcher

Modified:
   python/branches/py3k/Doc/library/asyncore.rst
   python/branches/py3k/Doc/whatsnew/3.2.rst
   python/branches/py3k/Lib/asyncore.py
   python/branches/py3k/Lib/smtpd.py
   python/branches/py3k/Lib/test/test_asyncore.py
   python/branches/py3k/Lib/test/test_ftplib.py
   python/branches/py3k/Lib/test/test_poplib.py
   python/branches/py3k/Lib/test/test_smtplib.py
   python/branches/py3k/Lib/test/test_ssl.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/asyncore.rst
==============================================================================
--- python/branches/py3k/Doc/library/asyncore.rst	(original)
+++ python/branches/py3k/Doc/library/asyncore.rst	Mon Oct  4 23:08:36 2010
@@ -86,7 +86,7 @@
    | ``handle_close()``   | Implied by a read event with no data   |
    |                      | available                              |
    +----------------------+----------------------------------------+
-   | ``handle_accept()``  | Implied by a read event on a listening |
+   | ``handle_accepted()``| Implied by a read event on a listening |
    |                      | socket                                 |
    +----------------------+----------------------------------------+
 
@@ -144,8 +144,20 @@
 
       Called on listening channels (passive openers) when a connection can be
       established with a new remote endpoint that has issued a :meth:`connect`
-      call for the local endpoint.
+      call for the local endpoint. Deprecated in version 3.2; use
+      :meth:`handle_accepted` instead.
 
+   .. deprecated:: 3.2
+
+   .. method:: handle_accepted(sock, addr)
+
+      Called on listening channels (passive openers) when a connection has been
+      established with a new remote endpoint that has issued a :meth:`connect`
+      call for the local endpoint.  *conn* is a *new* socket object usable to
+      send and receive data on the connection, and *address* is the address
+      bound to the socket on the other end of the connection.
+
+   .. versionadded:: 3.2
 
    .. method:: readable()
 
@@ -210,10 +222,13 @@
    .. method:: accept()
 
       Accept a connection.  The socket must be bound to an address and listening
-      for connections.  The return value is a pair ``(conn, address)`` where
-      *conn* is a *new* socket object usable to send and receive data on the
-      connection, and *address* is the address bound to the socket on the other
-      end of the connection.
+      for connections.  The return value can be either ``None`` or a pair
+      ``(conn, address)`` where *conn* is a *new* socket object usable to send
+      and receive data on the connection, and *address* is the address bound to
+      the socket on the other end of the connection.
+      When ``None`` is returned it means the connection didn't take place, in
+      which case the server should just ignore this event and keep listening
+      for further incoming connections.
 
 
    .. method:: close()
@@ -223,6 +238,13 @@
       flushed).  Sockets are automatically closed when they are
       garbage-collected.
 
+
+.. class:: dispatcher_with_send()
+
+   A :class:`dispatcher` subclass which adds simple buffered output capability,
+   useful for simple clients. For more sophisticated usage use
+   :class:`asynchat.async_chat`.
+
 .. class:: file_dispatcher()
 
    A file_dispatcher takes a file descriptor or :term:`file object` along
@@ -239,7 +261,7 @@
    socket for use by the :class:`file_dispatcher` class.  Availability: UNIX.
 
 
-.. _asyncore-example:
+.. _asyncore-example-1:
 
 asyncore Example basic HTTP client
 ----------------------------------
@@ -249,7 +271,7 @@
 
    import asyncore, socket
 
-   class http_client(asyncore.dispatcher):
+   class HTTPClient(asyncore.dispatcher):
 
        def __init__(self, host, path):
            asyncore.dispatcher.__init__(self)
@@ -273,6 +295,40 @@
            sent = self.send(self.buffer)
            self.buffer = self.buffer[sent:]
 
-   c = http_client('www.python.org', '/')
 
-   asyncore.loop()
+    client = HTTPClient('www.python.org', '/')
+    asyncore.loop()
+
+.. _asyncore-example-2:
+
+asyncore Example basic echo server
+----------------------------------
+
+Here is abasic echo server that uses the :class:`dispatcher` class to accept
+connections and dispatches the incoming connections to a handler::
+
+    import asyncore
+    import socket
+
+    class EchoHandler(asyncore.dispatcher_with_send):
+
+        def handle_read(self):
+            data = self.recv(8192)
+            self.send(data)
+
+    class EchoServer(asyncore.dispatcher):
+
+        def __init__(self, host, port):
+            asyncore.dispatcher.__init__(self)
+            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+            self.set_reuse_addr()
+            self.bind((host, port))
+            self.listen(5)
+
+        def handle_accepted(self, sock, addr):
+            print('Incoming connection from %s' % repr(addr))
+            handler = EchoHandler(sock)
+
+    server = EchoServer('localhost', 8080)
+    asyncore.loop()
+

Modified: python/branches/py3k/Doc/whatsnew/3.2.rst
==============================================================================
--- python/branches/py3k/Doc/whatsnew/3.2.rst	(original)
+++ python/branches/py3k/Doc/whatsnew/3.2.rst	Mon Oct  4 23:08:36 2010
@@ -434,6 +434,14 @@
 
   (Contributed by Giampaolo Rodolà; :issue:`9794`.)
 
+* :class:`asyncore.dispatcher` now provides a
+  :meth:`~asyncore.dispatcher.handle_accepted()` method
+  returning a `(sock, addr)` pair which is called when a connection has actually
+  been established with a new remote endpoint. This is supposed to be used as a
+  replacement for old :meth:`~asyncore.dispatcher.handle_accept()` and avoids
+  the user  to call :meth:`~asyncore.dispatcher.accept()` directly.
+
+  (Contributed by Giampaolo Rodolà; :issue:`6706`.)
 
 Multi-threading
 ===============

Modified: python/branches/py3k/Lib/asyncore.py
==============================================================================
--- python/branches/py3k/Lib/asyncore.py	(original)
+++ python/branches/py3k/Lib/asyncore.py	Mon Oct  4 23:08:36 2010
@@ -352,12 +352,15 @@
         # XXX can return either an address pair or None
         try:
             conn, addr = self.socket.accept()
-            return conn, addr
+        except TypeError:
+            return None
         except socket.error as why:
-            if why.args[0] == EWOULDBLOCK:
-                pass
+            if why.args[0] in (EWOULDBLOCK, ECONNABORTED):
+                return None
             else:
                 raise
+        else:
+            return conn, addr
 
     def send(self, data):
         try:
@@ -506,7 +509,13 @@
         self.log_info('unhandled connect event', 'warning')
 
     def handle_accept(self):
-        self.log_info('unhandled accept event', 'warning')
+        pair = self.accept()
+        if pair is not None:
+            self.handle_accepted(*pair)
+
+    def handle_accepted(self, sock, addr):
+        sock.close()
+        self.log_info('unhandled accepted event', 'warning')
 
     def handle_close(self):
         self.log_info('unhandled close event', 'warning')

Modified: python/branches/py3k/Lib/smtpd.py
==============================================================================
--- python/branches/py3k/Lib/smtpd.py	(original)
+++ python/branches/py3k/Lib/smtpd.py	Mon Oct  4 23:08:36 2010
@@ -421,21 +421,7 @@
                 self.__class__.__name__, time.ctime(time.time()),
                 localaddr, remoteaddr), file=DEBUGSTREAM)
 
-    def handle_accept(self):
-        try:
-            conn, addr = self.accept()
-        except TypeError:
-            # sometimes accept() might return None
-            return
-        except socket.error as err:
-            # ECONNABORTED might be thrown
-            if err.args[0] != errno.ECONNABORTED:
-                raise
-            return
-        else:
-            # sometimes addr == None instead of (ip, port)
-            if addr == None:
-                return
+    def handle_accepted(self, conn, addr):
         print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM)
         channel = self.channel_class(self, conn, addr)
 

Modified: python/branches/py3k/Lib/test/test_asyncore.py
==============================================================================
--- python/branches/py3k/Lib/test/test_asyncore.py	(original)
+++ python/branches/py3k/Lib/test/test_asyncore.py	Mon Oct  4 23:08:36 2010
@@ -296,7 +296,6 @@
             d.handle_read()
             d.handle_write()
             d.handle_connect()
-            d.handle_accept()
         finally:
             sys.stdout = stdout
 
@@ -304,8 +303,7 @@
         expected = ['warning: unhandled incoming priority event',
                     'warning: unhandled read event',
                     'warning: unhandled write event',
-                    'warning: unhandled connect event',
-                    'warning: unhandled accept event']
+                    'warning: unhandled connect event']
         self.assertEqual(lines, expected)
 
     def test_issue_8594(self):
@@ -451,6 +449,9 @@
     def handle_accept(self):
         raise Exception("handle_accept not supposed to be called")
 
+    def handle_accepted(self):
+        raise Exception("handle_accepted not supposed to be called")
+
     def handle_connect(self):
         raise Exception("handle_connect not supposed to be called")
 
@@ -481,8 +482,7 @@
     def address(self):
         return self.socket.getsockname()[:2]
 
-    def handle_accept(self):
-        sock, addr = self.accept()
+    def handle_accepted(self, sock, addr):
         self.handler(sock)
 
     def handle_error(self):
@@ -546,6 +546,29 @@
         client = BaseClient(server.address)
         self.loop_waiting_for_flag(server)
 
+    def test_handle_accepted(self):
+        # make sure handle_accepted() is called when a client connects
+
+        class TestListener(BaseTestHandler):
+
+            def __init__(self):
+                BaseTestHandler.__init__(self)
+                self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.bind((HOST, 0))
+                self.listen(5)
+                self.address = self.socket.getsockname()[:2]
+
+            def handle_accept(self):
+                asyncore.dispatcher.handle_accept(self)
+
+            def handle_accepted(self, sock, addr):
+                self.flag = True
+
+        server = TestListener()
+        client = BaseClient(server.address)
+        self.loop_waiting_for_flag(server)
+
+
     def test_handle_read(self):
         # make sure handle_read is called on data received
 

Modified: python/branches/py3k/Lib/test/test_ftplib.py
==============================================================================
--- python/branches/py3k/Lib/test/test_ftplib.py	(original)
+++ python/branches/py3k/Lib/test/test_ftplib.py	Mon Oct  4 23:08:36 2010
@@ -244,8 +244,7 @@
         self.active = False
         self.join()
 
-    def handle_accept(self):
-        conn, addr = self.accept()
+    def handle_accepted(self, conn, addr):
         self.handler_instance = self.handler(conn)
 
     def handle_connect(self):

Modified: python/branches/py3k/Lib/test/test_poplib.py
==============================================================================
--- python/branches/py3k/Lib/test/test_poplib.py	(original)
+++ python/branches/py3k/Lib/test/test_poplib.py	Mon Oct  4 23:08:36 2010
@@ -144,8 +144,7 @@
         self.active = False
         self.join()
 
-    def handle_accept(self):
-        conn, addr = self.accept()
+    def handle_accepted(self, conn, addr):
         self.handler_instance = self.handler(conn)
 
     def handle_connect(self):

Modified: python/branches/py3k/Lib/test/test_smtplib.py
==============================================================================
--- python/branches/py3k/Lib/test/test_smtplib.py	(original)
+++ python/branches/py3k/Lib/test/test_smtplib.py	Mon Oct  4 23:08:36 2010
@@ -379,8 +379,7 @@
         self._extra_features = []
         smtpd.SMTPServer.__init__(self, *args, **kw)
 
-    def handle_accept(self):
-        conn, addr = self.accept()
+    def handle_accepted(self, conn, addr):
         self._SMTPchannel = SimSMTPChannel(self._extra_features,
                                            self, conn, addr)
 

Modified: python/branches/py3k/Lib/test/test_ssl.py
==============================================================================
--- python/branches/py3k/Lib/test/test_ssl.py	(original)
+++ python/branches/py3k/Lib/test/test_ssl.py	Mon Oct  4 23:08:36 2010
@@ -838,8 +838,7 @@
                 asyncore.dispatcher.__init__(self, sock)
                 self.listen(5)
 
-            def handle_accept(self):
-                sock_obj, addr = self.accept()
+            def handle_accepted(self, sock_obj, addr):
                 if support.verbose:
                     sys.stdout.write(" server:  new connection from %s:%s\n" %addr)
                 self.ConnectionHandler(sock_obj, self.certfile)

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Mon Oct  4 23:08:36 2010
@@ -88,6 +88,12 @@
 Library
 -------
 
+- Issue 6706: asyncore.dispatcher now provides a handle_accepted() method 
+  returning a (sock, addr) pair which is called when a connection has been
+  established with a new remote endpoint. This is supposed to be used as a 
+  replacement for old handle_accept() and avoids the user to call accept()
+  directly.
+
 - Issue #9065: tarfile no longer uses "root" as the default for the uname and
   gname field.
 


More information about the Python-checkins mailing list