mirror of https://github.com/python/cpython
Merged revisions 70873,70904,70934,71490,71553,71579 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r70873 | josiah.carlson | 2009-03-31 15:32:34 -0400 (Tue, 31 Mar 2009) | 2 lines This resolves issue 1161031. Tests pass. ........ r70904 | josiah.carlson | 2009-03-31 17:49:36 -0400 (Tue, 31 Mar 2009) | 3 lines Made handle_expt_event() be called last, so that we don't accidentally read after closing the socket. ........ r70934 | josiah.carlson | 2009-03-31 21:28:11 -0400 (Tue, 31 Mar 2009) | 2 lines Fix for failing asyncore tests. ........ r71490 | r.david.murray | 2009-04-11 13:52:56 -0400 (Sat, 11 Apr 2009) | 4 lines Make test_asyncore tests match code changes introduced by the fix to Issue1161031, refactoring the test to simplify it in the process. ........ r71553 | r.david.murray | 2009-04-12 21:06:46 -0400 (Sun, 12 Apr 2009) | 3 lines Adjust test_asyncore to account for intentional asyncore behavior change introduced by r70934 that was causing a test failure when run under -O. ........ r71579 | r.david.murray | 2009-04-13 12:56:32 -0400 (Mon, 13 Apr 2009) | 2 lines Add missing NEWS item for issue1161031 fix. ........
This commit is contained in:
parent
0ec635138f
commit
7cd8f2bea3
|
@ -81,7 +81,8 @@ any that have been added to the map during asynchronous service) is closed.
|
||||||
+----------------------+----------------------------------------+
|
+----------------------+----------------------------------------+
|
||||||
| Event | Description |
|
| 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 |
|
| ``handle_close()`` | Implied by a read event with no data |
|
||||||
| | available |
|
| | available |
|
||||||
|
|
|
@ -69,10 +69,12 @@ def _strerror(err):
|
||||||
class ExitNow(Exception):
|
class ExitNow(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
|
||||||
|
|
||||||
def read(obj):
|
def read(obj):
|
||||||
try:
|
try:
|
||||||
obj.handle_read_event()
|
obj.handle_read_event()
|
||||||
except (ExitNow, KeyboardInterrupt, SystemExit):
|
except _reraised_exceptions:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
@ -80,7 +82,7 @@ def read(obj):
|
||||||
def write(obj):
|
def write(obj):
|
||||||
try:
|
try:
|
||||||
obj.handle_write_event()
|
obj.handle_write_event()
|
||||||
except (ExitNow, KeyboardInterrupt, SystemExit):
|
except _reraised_exceptions:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
@ -88,22 +90,22 @@ def write(obj):
|
||||||
def _exception(obj):
|
def _exception(obj):
|
||||||
try:
|
try:
|
||||||
obj.handle_expt_event()
|
obj.handle_expt_event()
|
||||||
except (ExitNow, KeyboardInterrupt, SystemExit):
|
except _reraised_exceptions:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
|
||||||
def readwrite(obj, flags):
|
def readwrite(obj, flags):
|
||||||
try:
|
try:
|
||||||
if flags & (select.POLLIN | select.POLLPRI):
|
if flags & select.POLLIN:
|
||||||
obj.handle_read_event()
|
obj.handle_read_event()
|
||||||
if flags & select.POLLOUT:
|
if flags & select.POLLOUT:
|
||||||
obj.handle_write_event()
|
obj.handle_write_event()
|
||||||
if flags & (select.POLLERR | select.POLLNVAL):
|
if flags & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
|
||||||
obj.handle_expt_event()
|
|
||||||
if flags & select.POLLHUP:
|
|
||||||
obj.handle_close()
|
obj.handle_close()
|
||||||
except (ExitNow, KeyboardInterrupt, SystemExit):
|
if flags & select.POLLPRI:
|
||||||
|
obj.handle_expt_event()
|
||||||
|
except _reraised_exceptions:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
obj.handle_error()
|
obj.handle_error()
|
||||||
|
@ -211,6 +213,7 @@ class dispatcher:
|
||||||
accepting = False
|
accepting = False
|
||||||
closing = False
|
closing = False
|
||||||
addr = None
|
addr = None
|
||||||
|
ignore_log_types = frozenset(['warning'])
|
||||||
|
|
||||||
def __init__(self, sock=None, map=None):
|
def __init__(self, sock=None, map=None):
|
||||||
if map is None:
|
if map is None:
|
||||||
|
@ -398,7 +401,7 @@ class dispatcher:
|
||||||
sys.stderr.write('log: %s\n' % str(message))
|
sys.stderr.write('log: %s\n' % str(message))
|
||||||
|
|
||||||
def log_info(self, message, type='info'):
|
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)
|
print '%s: %s' % (type, message)
|
||||||
|
|
||||||
def handle_read_event(self):
|
def handle_read_event(self):
|
||||||
|
@ -432,22 +435,17 @@ class dispatcher:
|
||||||
self.handle_write()
|
self.handle_write()
|
||||||
|
|
||||||
def handle_expt_event(self):
|
def handle_expt_event(self):
|
||||||
# if the handle_expt is the same default worthless method,
|
# handle_expt_event() is called if there might be an error on the
|
||||||
# we'll not even bother calling it, we'll instead generate
|
# socket, or if there is OOB data
|
||||||
# a useful error
|
# check for the error condition first
|
||||||
x = True
|
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
||||||
try:
|
if err != 0:
|
||||||
y1 = self.__class__.handle_expt.im_func
|
# we can get here when select.select() says that there is an
|
||||||
y2 = dispatcher.handle_expt.im_func
|
# exceptional condition on the socket
|
||||||
x = y1 is y2
|
# since there is an error, we'll go ahead and close the socket
|
||||||
except AttributeError:
|
# like we would in a subclassed handle_read() that received no
|
||||||
pass
|
# data
|
||||||
|
self.handle_close()
|
||||||
if x:
|
|
||||||
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
|
|
||||||
msg = _strerror(err)
|
|
||||||
|
|
||||||
raise socket.error(err, msg)
|
|
||||||
else:
|
else:
|
||||||
self.handle_expt()
|
self.handle_expt()
|
||||||
|
|
||||||
|
@ -472,7 +470,7 @@ class dispatcher:
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
|
||||||
def handle_expt(self):
|
def handle_expt(self):
|
||||||
self.log_info('unhandled exception', 'warning')
|
self.log_info('unhandled incoming priority event', 'warning')
|
||||||
|
|
||||||
def handle_read(self):
|
def handle_read(self):
|
||||||
self.log_info('unhandled read event', 'warning')
|
self.log_info('unhandled read event', 'warning')
|
||||||
|
@ -553,7 +551,7 @@ def close_all(map=None, ignore_all=False):
|
||||||
pass
|
pass
|
||||||
elif not ignore_all:
|
elif not ignore_all:
|
||||||
raise
|
raise
|
||||||
except (ExitNow, KeyboardInterrupt, SystemExit):
|
except _reraised_exceptions:
|
||||||
raise
|
raise
|
||||||
except:
|
except:
|
||||||
if not ignore_all:
|
if not ignore_all:
|
||||||
|
|
|
@ -115,12 +115,24 @@ class HelperFunctionTests(unittest.TestCase):
|
||||||
def test_readwrite(self):
|
def test_readwrite(self):
|
||||||
# Check that correct methods are called by readwrite()
|
# 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:
|
class testobj:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.read = False
|
self.read = False
|
||||||
self.write = False
|
self.write = False
|
||||||
self.closed = False
|
self.closed = False
|
||||||
self.expt = False
|
self.expt = False
|
||||||
|
self.error_handled = False
|
||||||
|
|
||||||
def handle_read_event(self):
|
def handle_read_event(self):
|
||||||
self.read = True
|
self.read = True
|
||||||
|
@ -137,11 +149,15 @@ class HelperFunctionTests(unittest.TestCase):
|
||||||
def handle_error(self):
|
def handle_error(self):
|
||||||
self.error_handled = True
|
self.error_handled = True
|
||||||
|
|
||||||
for flag in (select.POLLIN, select.POLLPRI):
|
for flag, expectedattr in expected:
|
||||||
tobj = testobj()
|
tobj = testobj()
|
||||||
self.assertEqual(tobj.read, False)
|
self.assertEqual(getattr(tobj, expectedattr), False)
|
||||||
asyncore.readwrite(tobj, flag)
|
asyncore.readwrite(tobj, flag)
|
||||||
self.assertEqual(tobj.read, 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
|
# check that ExitNow exceptions in the object handler method
|
||||||
# bubbles all the way up through asyncore readwrite call
|
# bubbles all the way up through asyncore readwrite call
|
||||||
|
@ -151,40 +167,7 @@ class HelperFunctionTests(unittest.TestCase):
|
||||||
# check that an exception other than ExitNow in the object handler
|
# check that an exception other than ExitNow in the object handler
|
||||||
# method causes the handle_error method to get called
|
# method causes the handle_error method to get called
|
||||||
tr2 = crashingdummy()
|
tr2 = crashingdummy()
|
||||||
asyncore.readwrite(tr2, flag)
|
self.assertEqual(tr2.error_handled, False)
|
||||||
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)
|
|
||||||
|
|
||||||
# check that ExitNow exceptions in the object handler method
|
|
||||||
# bubbles all the way up through asyncore readwrite calls
|
|
||||||
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)
|
asyncore.readwrite(tr2, flag)
|
||||||
self.assertEqual(tr2.error_handled, True)
|
self.assertEqual(tr2.error_handled, True)
|
||||||
|
|
||||||
|
@ -289,15 +272,13 @@ class DispatcherTests(unittest.TestCase):
|
||||||
sys.stdout = stdout
|
sys.stdout = stdout
|
||||||
|
|
||||||
lines = fp.getvalue().splitlines()
|
lines = fp.getvalue().splitlines()
|
||||||
if __debug__:
|
expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
|
||||||
expected = ['EGGS: %s' % l1, 'info: %s' % l2, 'SPAM: %s' % l3]
|
|
||||||
else:
|
|
||||||
expected = ['EGGS: %s' % l1, 'SPAM: %s' % l3]
|
|
||||||
|
|
||||||
self.assertEquals(lines, expected)
|
self.assertEquals(lines, expected)
|
||||||
|
|
||||||
def test_unhandled(self):
|
def test_unhandled(self):
|
||||||
d = asyncore.dispatcher()
|
d = asyncore.dispatcher()
|
||||||
|
d.ignore_log_types = ()
|
||||||
|
|
||||||
# capture output of dispatcher.log_info() (to stdout via print)
|
# capture output of dispatcher.log_info() (to stdout via print)
|
||||||
fp = StringIO()
|
fp = StringIO()
|
||||||
|
@ -313,7 +294,7 @@ class DispatcherTests(unittest.TestCase):
|
||||||
sys.stdout = stdout
|
sys.stdout = stdout
|
||||||
|
|
||||||
lines = fp.getvalue().splitlines()
|
lines = fp.getvalue().splitlines()
|
||||||
expected = ['warning: unhandled exception',
|
expected = ['warning: unhandled incoming priority event',
|
||||||
'warning: unhandled read event',
|
'warning: unhandled read event',
|
||||||
'warning: unhandled write event',
|
'warning: unhandled write event',
|
||||||
'warning: unhandled connect event',
|
'warning: unhandled connect event',
|
||||||
|
|
|
@ -14,6 +14,15 @@ Core and Builtins
|
||||||
|
|
||||||
- Issue #5759: float() didn't call __float__ on str subclasses.
|
- Issue #5759: float() didn't call __float__ on str subclasses.
|
||||||
|
|
||||||
|
Library
|
||||||
|
-------
|
||||||
|
|
||||||
|
- Issue #1161031: fix readwrite select flag handling: POLLPRI now
|
||||||
|
results in a handle_expt_event call, not handle_read_event, and POLLERR
|
||||||
|
and POLLNVAL now call handle_close, not handle_expt_event. Also,
|
||||||
|
dispatcher now has an 'ignore_log_types' attribute for suppressing
|
||||||
|
log messages, which is set to 'warning' by default.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 2.6.2 rc 1
|
What's New in Python 2.6.2 rc 1
|
||||||
===============================
|
===============================
|
||||||
|
|
Loading…
Reference in New Issue