[3.6] bpo-32356: idempotent pause_/resume_reading (GH-4914) (GH-7629) · python/cpython@142e3c0 (original) (raw)
7 files changed
lines changed
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -124,11 +124,19 @@ ReadTransport | ||
124 | 124 | the protocol's :meth:`data_received` method until :meth:`resume_reading` |
125 | 125 | is called. |
126 | 126 | |
127 | + .. versionchanged:: 3.6.7 | |
128 | + The method is idempotent, i.e. it can be called when the | |
129 | + transport is already paused or closed. | |
130 | + | |
127 | 131 | .. method:: resume_reading() |
128 | 132 | |
129 | 133 | Resume the receiving end. The protocol's :meth:`data_received` method |
130 | 134 | will be called once again if some data is available for reading. |
131 | 135 | |
136 | + .. versionchanged:: 3.6.7 | |
137 | + The method is idempotent, i.e. it can be called when the | |
138 | + transport is already reading. | |
139 | + | |
132 | 140 | |
133 | 141 | WriteTransport |
134 | 142 | -------------- |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -160,20 +160,16 @@ def __init__(self, loop, sock, protocol, waiter=None, | ||
160 | 160 | self._loop.call_soon(self._loop_reading) |
161 | 161 | |
162 | 162 | def pause_reading(self): |
163 | -if self._closing: | |
164 | -raise RuntimeError('Cannot pause_reading() when closing') | |
165 | -if self._paused: | |
166 | -raise RuntimeError('Already paused') | |
163 | +if self._closing or self._paused: | |
164 | +return | |
167 | 165 | self._paused = True |
168 | 166 | if self._loop.get_debug(): |
169 | 167 | logger.debug("%r pauses reading", self) |
170 | 168 | |
171 | 169 | def resume_reading(self): |
172 | -if not self._paused: | |
173 | -raise RuntimeError('Not paused') | |
174 | -self._paused = False | |
175 | -if self._closing: | |
170 | +if self._closing or not self._paused: | |
176 | 171 | return |
172 | +self._paused = False | |
177 | 173 | if self._reschedule_on_resume: |
178 | 174 | self._loop.call_soon(self._loop_reading, self._read_fut) |
179 | 175 | self._reschedule_on_resume = False |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -703,18 +703,16 @@ def __init__(self, loop, sock, protocol, waiter=None, | ||
703 | 703 | waiter, None) |
704 | 704 | |
705 | 705 | def pause_reading(self): |
706 | -if self._closing: | |
707 | -raise RuntimeError('Cannot pause_reading() when closing') | |
708 | -if self._paused: | |
709 | -raise RuntimeError('Already paused') | |
706 | +if self._closing or self._paused: | |
707 | +return | |
710 | 708 | self._paused = True |
711 | 709 | self._loop._remove_reader(self._sock_fd) |
712 | 710 | if self._loop.get_debug(): |
713 | 711 | logger.debug("%r pauses reading", self) |
714 | 712 | |
715 | 713 | def resume_reading(self): |
716 | -if not self._paused: | |
717 | -raise RuntimeError('Not paused') | |
714 | +if self._closing or not self._paused: | |
715 | +return | |
718 | 716 | self._paused = False |
719 | 717 | self._add_reader(self._sock_fd, self._read_ready) |
720 | 718 | if self._loop.get_debug(): |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -335,12 +335,19 @@ def _remove_reader(self, fd): | ||
335 | 335 | return False |
336 | 336 | |
337 | 337 | def assert_reader(self, fd, callback, *args): |
338 | -assert fd in self.readers, 'fd {} is not registered'.format(fd) | |
338 | +if fd not in self.readers: | |
339 | +raise AssertionError(f'fd {fd} is not registered') | |
339 | 340 | handle = self.readers[fd] |
340 | -assert handle._callback == callback, '{!r} != {!r}'.format( | |
341 | -handle._callback, callback) | |
342 | -assert handle._args == args, '{!r} != {!r}'.format( | |
343 | -handle._args, args) | |
341 | +if handle._callback != callback: | |
342 | +raise AssertionError( | |
343 | +f'unexpected callback: {handle._callback} != {callback}') | |
344 | +if handle._args != args: | |
345 | +raise AssertionError( | |
346 | +f'unexpected callback args: {handle._args} != {args}') | |
347 | + | |
348 | +def assert_no_reader(self, fd): | |
349 | +if fd in self.readers: | |
350 | +raise AssertionError(f'fd {fd} is registered') | |
344 | 351 | |
345 | 352 | def _add_writer(self, fd, callback, *args): |
346 | 353 | self.writers[fd] = events.Handle(callback, args, self) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -334,18 +334,23 @@ def test_pause_resume_reading(self): | ||
334 | 334 | f = asyncio.Future(loop=self.loop) |
335 | 335 | f.set_result(msg) |
336 | 336 | futures.append(f) |
337 | + | |
337 | 338 | self.loop._proactor.recv.side_effect = futures |
338 | 339 | self.loop._run_once() |
339 | 340 | self.assertFalse(tr._paused) |
340 | 341 | self.loop._run_once() |
341 | 342 | self.protocol.data_received.assert_called_with(b'data1') |
342 | 343 | self.loop._run_once() |
343 | 344 | self.protocol.data_received.assert_called_with(b'data2') |
345 | + | |
346 | +tr.pause_reading() | |
344 | 347 | tr.pause_reading() |
345 | 348 | self.assertTrue(tr._paused) |
346 | 349 | for i in range(10): |
347 | 350 | self.loop._run_once() |
348 | 351 | self.protocol.data_received.assert_called_with(b'data2') |
352 | + | |
353 | +tr.resume_reading() | |
349 | 354 | tr.resume_reading() |
350 | 355 | self.assertFalse(tr._paused) |
351 | 356 | self.loop._run_once() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -81,6 +81,7 @@ def test_make_ssl_transport(self): | ||
81 | 81 | with test_utils.disable_logger(): |
82 | 82 | transport = self.loop._make_ssl_transport( |
83 | 83 | m, asyncio.Protocol(), m, waiter) |
84 | + | |
84 | 85 | # execute the handshake while the logger is disabled |
85 | 86 | # to ignore SSL handshake failure |
86 | 87 | test_utils.run_briefly(self.loop) |
@@ -884,14 +885,19 @@ def test_pause_resume_reading(self): | ||
884 | 885 | test_utils.run_briefly(self.loop) |
885 | 886 | self.assertFalse(tr._paused) |
886 | 887 | self.loop.assert_reader(7, tr._read_ready) |
888 | + | |
889 | +tr.pause_reading() | |
887 | 890 | tr.pause_reading() |
888 | 891 | self.assertTrue(tr._paused) |
889 | -self.assertFalse(7 in self.loop.readers) | |
892 | +self.loop.assert_no_reader(7) | |
893 | + | |
894 | +tr.resume_reading() | |
890 | 895 | tr.resume_reading() |
891 | 896 | self.assertFalse(tr._paused) |
892 | 897 | self.loop.assert_reader(7, tr._read_ready) |
893 | -with self.assertRaises(RuntimeError): | |
894 | -tr.resume_reading() | |
898 | + | |
899 | +tr.close() | |
900 | +self.loop.assert_no_reader(7) | |
895 | 901 | |
896 | 902 | def test_read_ready(self): |
897 | 903 | transport = self.socket_transport() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1 | +asyncio.transport.resume_reading() and pause_reading() are now idempotent. |