Skip to content

Commit 78532ba

Browse files
committed
Merged revisions 70873,70904,70934,71490 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. ........
1 parent 12f6a99 commit 78532ba

3 files changed

Lines changed: 49 additions & 66 deletions

File tree

Doc/library/asyncore.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ any that have been added to the map during asynchronous service) is closed.
8181
+----------------------+----------------------------------------+
8282
| Event | Description |
8383
+======================+========================================+
84-
| ``handle_connect()`` | Implied by the first write event |
84+
| ``handle_connect()`` | Implied by the first read or write |
85+
| | event |
8586
+----------------------+----------------------------------------+
8687
| ``handle_close()`` | Implied by a read event with no data |
8788
| | available |

Lib/asyncore.py

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -68,41 +68,43 @@ def _strerror(err):
6868
class ExitNow(Exception):
6969
pass
7070

71+
_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit)
72+
7173
def read(obj):
7274
try:
7375
obj.handle_read_event()
74-
except (ExitNow, KeyboardInterrupt, SystemExit):
76+
except _reraised_exceptions:
7577
raise
7678
except:
7779
obj.handle_error()
7880

7981
def write(obj):
8082
try:
8183
obj.handle_write_event()
82-
except (ExitNow, KeyboardInterrupt, SystemExit):
84+
except _reraised_exceptions:
8385
raise
8486
except:
8587
obj.handle_error()
8688

8789
def _exception(obj):
8890
try:
8991
obj.handle_expt_event()
90-
except (ExitNow, KeyboardInterrupt, SystemExit):
92+
except _reraised_exceptions:
9193
raise
9294
except:
9395
obj.handle_error()
9496

9597
def readwrite(obj, flags):
9698
try:
97-
if flags & (select.POLLIN | select.POLLPRI):
99+
if flags & select.POLLIN:
98100
obj.handle_read_event()
99101
if flags & select.POLLOUT:
100102
obj.handle_write_event()
101-
if flags & (select.POLLERR | select.POLLNVAL):
102-
obj.handle_expt_event()
103-
if flags & select.POLLHUP:
103+
if flags & (select.POLLHUP | select.POLLERR | select.POLLNVAL):
104104
obj.handle_close()
105-
except (ExitNow, KeyboardInterrupt, SystemExit):
105+
if flags & select.POLLPRI:
106+
obj.handle_expt_event()
107+
except _reraised_exceptions:
106108
raise
107109
except:
108110
obj.handle_error()
@@ -210,6 +212,7 @@ class dispatcher:
210212
accepting = False
211213
closing = False
212214
addr = None
215+
ignore_log_types = frozenset(['warning'])
213216

214217
def __init__(self, sock=None, map=None):
215218
if map is None:
@@ -397,7 +400,7 @@ def log(self, message):
397400
sys.stderr.write('log: %s\n' % str(message))
398401

399402
def log_info(self, message, type='info'):
400-
if __debug__ or type != 'info':
403+
if type not in self.ignore_log_types:
401404
print('%s: %s' % (type, message))
402405

403406
def handle_read_event(self):
@@ -431,22 +434,17 @@ def handle_write_event(self):
431434
self.handle_write()
432435

433436
def handle_expt_event(self):
434-
# if the handle_expt is the same default worthless method,
435-
# we'll not even bother calling it, we'll instead generate
436-
# a useful error
437-
x = True
438-
try:
439-
y1 = self.handle_expt.__func__
440-
y2 = dispatcher.handle_expt
441-
x = y1 is y2
442-
except AttributeError:
443-
pass
444-
445-
if x:
446-
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
447-
msg = _strerror(err)
448-
449-
raise socket.error(err, msg)
437+
# handle_expt_event() is called if there might be an error on the
438+
# socket, or if there is OOB data
439+
# check for the error condition first
440+
err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
441+
if err != 0:
442+
# we can get here when select.select() says that there is an
443+
# exceptional condition on the socket
444+
# since there is an error, we'll go ahead and close the socket
445+
# like we would in a subclassed handle_read() that received no
446+
# data
447+
self.handle_close()
450448
else:
451449
self.handle_expt()
452450

@@ -471,7 +469,7 @@ def handle_error(self):
471469
self.handle_close()
472470

473471
def handle_expt(self):
474-
self.log_info('unhandled exception', 'warning')
472+
self.log_info('unhandled incoming priority event', 'warning')
475473

476474
def handle_read(self):
477475
self.log_info('unhandled read event', 'warning')
@@ -552,7 +550,7 @@ def close_all(map=None, ignore_all=False):
552550
pass
553551
elif not ignore_all:
554552
raise
555-
except (ExitNow, KeyboardInterrupt, SystemExit):
553+
except _reraised_exceptions:
556554
raise
557555
except:
558556
if not ignore_all:

Lib/test/test_asyncore.py

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,24 @@ def test_readwriteexc(self):
116116
def test_readwrite(self):
117117
# Check that correct methods are called by readwrite()
118118

119+
attributes = ('read', 'expt', 'write', 'closed', 'error_handled')
120+
121+
expected = (
122+
(select.POLLIN, 'read'),
123+
(select.POLLPRI, 'expt'),
124+
(select.POLLOUT, 'write'),
125+
(select.POLLERR, 'closed'),
126+
(select.POLLHUP, 'closed'),
127+
(select.POLLNVAL, 'closed'),
128+
)
129+
119130
class testobj:
120131
def __init__(self):
121132
self.read = False
122133
self.write = False
123134
self.closed = False
124135
self.expt = False
136+
self.error_handled = False
125137

126138
def handle_read_event(self):
127139
self.read = True
@@ -138,54 +150,25 @@ def handle_expt_event(self):
138150
def handle_error(self):
139151
self.error_handled = True
140152

141-
for flag in (select.POLLIN, select.POLLPRI):
153+
for flag, expectedattr in expected:
142154
tobj = testobj()
143-
self.assertEqual(tobj.read, False)
155+
self.assertEqual(getattr(tobj, expectedattr), False)
144156
asyncore.readwrite(tobj, flag)
145-
self.assertEqual(tobj.read, True)
146157

147-
# check that ExitNow exceptions in the object handler method
148-
# bubbles all the way up through asyncore readwrite call
149-
tr1 = exitingdummy()
150-
self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
151-
152-
# check that an exception other than ExitNow in the object handler
153-
# method causes the handle_error method to get called
154-
tr2 = crashingdummy()
155-
asyncore.readwrite(tr2, flag)
156-
self.assertEqual(tr2.error_handled, True)
157-
158-
tobj = testobj()
159-
self.assertEqual(tobj.write, False)
160-
asyncore.readwrite(tobj, select.POLLOUT)
161-
self.assertEqual(tobj.write, True)
162-
163-
# check that ExitNow exceptions in the object handler method
164-
# bubbles all the way up through asyncore readwrite call
165-
tr1 = exitingdummy()
166-
self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1,
167-
select.POLLOUT)
168-
169-
# check that an exception other than ExitNow in the object handler
170-
# method causes the handle_error method to get called
171-
tr2 = crashingdummy()
172-
asyncore.readwrite(tr2, select.POLLOUT)
173-
self.assertEqual(tr2.error_handled, True)
174-
175-
for flag in (select.POLLERR, select.POLLHUP, select.POLLNVAL):
176-
tobj = testobj()
177-
self.assertEqual((tobj.expt, tobj.closed)[flag == select.POLLHUP], False)
178-
asyncore.readwrite(tobj, flag)
179-
self.assertEqual((tobj.expt, tobj.closed)[flag == select.POLLHUP], True)
158+
# Only the attribute modified by the routine we expect to be
159+
# called should be True.
160+
for attr in attributes:
161+
self.assertEqual(getattr(tobj, attr), attr==expectedattr)
180162

181163
# check that ExitNow exceptions in the object handler method
182-
# bubbles all the way up through asyncore readwrite calls
164+
# bubbles all the way up through asyncore readwrite call
183165
tr1 = exitingdummy()
184166
self.assertRaises(asyncore.ExitNow, asyncore.readwrite, tr1, flag)
185167

186168
# check that an exception other than ExitNow in the object handler
187169
# method causes the handle_error method to get called
188170
tr2 = crashingdummy()
171+
self.assertEqual(tr2.error_handled, False)
189172
asyncore.readwrite(tr2, flag)
190173
self.assertEqual(tr2.error_handled, True)
191174

@@ -299,6 +282,7 @@ def test_log_info(self):
299282

300283
def test_unhandled(self):
301284
d = asyncore.dispatcher()
285+
d.ignore_log_types = ()
302286

303287
# capture output of dispatcher.log_info() (to stdout via print)
304288
fp = StringIO()
@@ -314,7 +298,7 @@ def test_unhandled(self):
314298
sys.stdout = stdout
315299

316300
lines = fp.getvalue().splitlines()
317-
expected = ['warning: unhandled exception',
301+
expected = ['warning: unhandled incoming priority event',
318302
'warning: unhandled read event',
319303
'warning: unhandled write event',
320304
'warning: unhandled connect event',

0 commit comments

Comments
 (0)