summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/asyncore.rst3
-rw-r--r--Lib/asyncore.py52
-rw-r--r--Lib/test/test_asyncore.py60
3 files changed, 49 insertions, 66 deletions
diff --git a/Doc/library/asyncore.rst b/Doc/library/asyncore.rst
index 40dc812..267c58b 100644
--- a/Doc/library/asyncore.rst
+++ b/Doc/library/asyncore.rst
@@ -81,7 +81,8 @@ any that have been added to the map during asynchronous service) is closed.
+----------------------+----------------------------------------+
| Event | Description |
+======================+========================================+
- | ``handle_connect()`` | Implied by the first write event |
+ | ``handle_connect()`` | Implied by the first read or write |
+ | | event |
+----------------------+----------------------------------------+
| ``handle_close()`` | Implied by a read event with no data |
| | available |
diff --git a/Lib/asyncore.py b/Lib/asyncore.py
index 236fd9e..e4f9bf9 100644
--- a/Lib/asyncore.py
+++ b/Lib/asyncore.py
@@ -68,10 +68,12 @@ def _strerror(err):
class ExitNow(Exception):
pass
+_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
+
def read(obj):
try:
obj.handle_read_event()
- except (ExitNow, KeyboardInterrupt, SystemExit):
+ except _reraised_exceptions:
raise
except:
obj.handle_error()
@@ -79,7 +81,7 @@ def read(obj):
def write(obj):
try:
obj.handle_write_event()
- except (ExitNow, KeyboardInterrupt, SystemExit):
+ except _reraised_exceptions:
raise
except:
obj.handle_error()
@@ -87,22 +89,22 @@ def write(obj):
def _exception(obj):
try:
obj.handle_expt_event()
- except (ExitNow, KeyboardInterrupt, SystemExit):
+ except _reraised_exceptions:
raise
except:
obj.handle_error()
def readwrite(obj, flags):
try:
- if flags & (select.POLLIN | select.POLLPRI):
+ if flags & select.POLLIN:
obj.handle_read_event()
if flags & select.POLLOUT:
obj.handle_write_event()
- if flags & (select.POLLERR | select.POLLNVAL):
- obj.handle_expt_event()
- if flags & select.POLLHUP:
+ if flags & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
obj.handle_close()
- except (ExitNow, KeyboardInterrupt, SystemExit):
+ if flags & select.POLLPRI:
+ obj.handle_expt_event()
+ except _reraised_exceptions:
raise
except:
obj.handle_error()
@@ -210,6 +212,7 @@ class dispatcher:
accepting = False
closing = False
addr = None
+ ignore_log_types = frozenset(['warning'])
def __init__(self, sock=None, map=None):
if map is None:
@@ -397,7 +400,7 @@ class dispatcher:
sys.stderr.write('log: %s\n' % str(message))
def log_info(self, message, type='info'):
- if __debug__ or type != 'info':
+ if type not in self.ignore_log_types:
print('%s: %s' % (type, message))
def handle_read_event(self):
@@ -431,22 +434,17 @@ class dispatcher:
self.handle_write()
def handle_expt_event(self):
- # if the handle_expt is the same default worthless method,
- # we'll not even bother calling it, we'll instead generate
- # a useful error
- x = True
- try:
- y1 = self.handle_expt.__func__
- y2 = dispatcher.handle_expt
- x = y1 is y2
- except AttributeError:
- pass
-
- if x:
- err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
- msg = _strerror(err)
-
- raise socket.error(err, msg)
+ # handle_expt_event() is called if there might be an error on the
+ # socket, or if there is OOB data
+ # check for the error condition first
+ err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
+ if err != 0:
+ # we can get here when select.select() says that there is an
+ # exceptional condition on the socket
+ # since there is an error, we'll go ahead and close the socket
+ # like we would in a subclassed handle_read() that received no
+ # data
+ self.handle_close()
else:
self.handle_expt()
@@ -471,7 +469,7 @@ class dispatcher:
self.handle_close()
def handle_expt(self):
- self.log_info('unhandled exception', 'warning')
+ self.log_info('unhandled incoming priority event', 'warning')
def handle_read(self):
self.log_info('unhandled read event', 'warning')
@@ -552,7 +550,7 @@ def close_all(map=None, ignore_all=False):
pass
elif not ignore_all:
raise
- except (ExitNow, KeyboardInterrupt, SystemExit):
+ except _reraised_exceptions:
raise
except:
if not ignore_all:
diff --git a/Lib/test/test_asyncore.py b/Lib/test/test_asyncore.py
index 940b45e..6837602 100644
--- a/Lib/test/test_asyncore.py
+++ b/Lib/test/test_asyncore.py
@@ -116,12 +116,24 @@ class HelperFunctionTests(unittest.TestCase):
def test_readwrite(self):
# Check that correct methods are called by readwrite()
+ attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
+
+ expected = (
+ (select.POLLIN, 'read'),
+ (select.POLLPRI, 'expt'),
+ (select.POLLOUT, 'write'),
+ (select.POLLERR, 'closed'),
+ (select.POLLHUP, 'closed'),
+ (select.POLLNVAL, 'closed'),
+ )
+
class testobj:
def __init__(self):
self.read = False
self.write = False
self.closed = False
self.expt = False
+ self.error_handled = False
def handle_read_event(self):
self.read = True
@@ -138,54 +150,25 @@ class HelperFunctionTests(unittest.TestCase):
def handle_error(self):
self.error_handled = True
- for flag in (select.POLLIN, select.POLLPRI):
+ for flag, expectedattr in expected:
tobj = testobj()
- self.assertEqual(tobj.read, False)
+ self.assertEqual(getattr(tobj, expectedattr), False)
asyncore.readwrite(tobj, flag)
- self.assertEqual(tobj.read, True)
- # check that ExitNow exceptions in the object handler method
- # bubbles all the way up through asyncore readwrite call
- tr1 = exitingdummy()
- self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
-
- # check that an exception other than ExitNow in the object handler
- # method causes the handle_error method to get called
- tr2 = crashingdummy()
- asyncore.readwrite(tr2, flag)
- self.assertEqual(tr2.error_handled, True)
-
- tobj = testobj()
- self.assertEqual(tobj.write, False)
- asyncore.readwrite(tobj, select.POLLOUT)
- self.assertEqual(tobj.write, True)
-
- # check that ExitNow exceptions in the object handler method
- # bubbles all the way up through asyncore readwrite call
- tr1 = exitingdummy()
- self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1,
- select.POLLOUT)
-
- # check that an exception other than ExitNow in the object handler
- # method causes the handle_error method to get called
- tr2 = crashingdummy()
- asyncore.readwrite(tr2, select.POLLOUT)
- self.assertEqual(tr2.error_handled, True)
-
- for flag in (select.POLLERR, select.POLLHUP, select.POLLNVAL):
- tobj = testobj()
- self.assertEqual((tobj.expt, tobj.closed)[flag == select.POLLHUP], False)
- asyncore.readwrite(tobj, flag)
- self.assertEqual((tobj.expt, tobj.closed)[flag == select.POLLHUP], True)
+ # Only the attribute modified by the routine we expect to be
+ # called should be True.
+ for attr in attributes:
+ self.assertEqual(getattr(tobj, attr), attr==expectedattr)
# check that ExitNow exceptions in the object handler method
- # bubbles all the way up through asyncore readwrite calls
+ # bubbles all the way up through asyncore readwrite call
tr1 = exitingdummy()
self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
# check that an exception other than ExitNow in the object handler
# method causes the handle_error method to get called
tr2 = crashingdummy()
+ self.assertEqual(tr2.error_handled, False)
asyncore.readwrite(tr2, flag)
self.assertEqual(tr2.error_handled, True)
@@ -299,6 +282,7 @@ class DispatcherTests(unittest.TestCase):
def test_unhandled(self):
d = asyncore.dispatcher()
+ d.ignore_log_types = ()
# capture output of dispatcher.log_info() (to stdout via print)
fp = StringIO()
@@ -314,7 +298,7 @@ class DispatcherTests(unittest.TestCase):
sys.stdout = stdout
lines = fp.getvalue().splitlines()
- expected = ['warning: unhandled exception',
+ expected = ['warning: unhandled incoming priority event',
'warning: unhandled read event',
'warning: unhandled write event',
'warning: unhandled connect event',