Skip to content

Commit 0035be3

Browse files
committed
Misc asyncio improvements from upstream (merge 3.5->3.6)
2 parents 61cd726 + e3c65a7 commit 0035be3

File tree

8 files changed

+164
-42
lines changed

8 files changed

+164
-42
lines changed

Lib/asyncio/base_events.py

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,24 +115,16 @@ def _ipaddr_info(host, port, family, type, proto):
115115

116116
if port is None:
117117
port = 0
118-
elif isinstance(port, bytes):
119-
if port == b'':
120-
port = 0
121-
else:
122-
try:
123-
port = int(port)
124-
except ValueError:
125-
# Might be a service name like b"http".
126-
port = socket.getservbyname(port.decode('ascii'))
127-
elif isinstance(port, str):
128-
if port == '':
129-
port = 0
130-
else:
131-
try:
132-
port = int(port)
133-
except ValueError:
134-
# Might be a service name like "http".
135-
port = socket.getservbyname(port)
118+
elif isinstance(port, bytes) and port == b'':
119+
port = 0
120+
elif isinstance(port, str) and port == '':
121+
port = 0
122+
else:
123+
# If port's a service name like "http", don't skip getaddrinfo.
124+
try:
125+
port = int(port)
126+
except (TypeError, ValueError):
127+
return None
136128

137129
if family == socket.AF_UNSPEC:
138130
afs = [socket.AF_INET, socket.AF_INET6]

Lib/asyncio/base_subprocess.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import warnings
44

55
from . import compat
6-
from . import futures
76
from . import protocols
87
from . import transports
98
from .coroutines import coroutine

Lib/asyncio/coroutines.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ def send(self, *value):
120120
def send(self, value):
121121
return self.gen.send(value)
122122

123-
def throw(self, exc):
124-
return self.gen.throw(exc)
123+
def throw(self, type, value=None, traceback=None):
124+
return self.gen.throw(type, value, traceback)
125125

126126
def close(self):
127127
return self.gen.close()

Lib/asyncio/queues.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
from . import compat
99
from . import events
10-
from . import futures
1110
from . import locks
1211
from .coroutines import coroutine
1312

Lib/asyncio/tasks.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
594594
"""Return a future aggregating results from the given coroutines
595595
or futures.
596596
597+
Coroutines will be wrapped in a future and scheduled in the event
598+
loop. They will not necessarily be scheduled in the same order as
599+
passed in.
600+
597601
All futures must share the same event loop. If all the tasks are
598602
done successfully, the returned future's result is the list of
599603
results (in the order of the original sequence, not necessarily

Lib/test/test_asyncio/test_base_events.py

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -142,26 +142,6 @@ def test_port_parameter_types(self):
142142
(INET, STREAM, TCP, '', ('1.2.3.4', 1)),
143143
base_events._ipaddr_info('1.2.3.4', b'1', INET, STREAM, TCP))
144144

145-
def test_getaddrinfo_servname(self):
146-
INET = socket.AF_INET
147-
STREAM = socket.SOCK_STREAM
148-
TCP = socket.IPPROTO_TCP
149-
150-
self.assertEqual(
151-
(INET, STREAM, TCP, '', ('1.2.3.4', 80)),
152-
base_events._ipaddr_info('1.2.3.4', 'http', INET, STREAM, TCP))
153-
154-
self.assertEqual(
155-
(INET, STREAM, TCP, '', ('1.2.3.4', 80)),
156-
base_events._ipaddr_info('1.2.3.4', b'http', INET, STREAM, TCP))
157-
158-
# Raises "service/proto not found".
159-
with self.assertRaises(OSError):
160-
base_events._ipaddr_info('1.2.3.4', 'nonsense', INET, STREAM, TCP)
161-
162-
with self.assertRaises(OSError):
163-
base_events._ipaddr_info('1.2.3.4', 'nonsense', INET, STREAM, TCP)
164-
165145
@patch_socket
166146
def test_ipaddr_info_no_inet_pton(self, m_socket):
167147
del m_socket.inet_pton
@@ -1209,6 +1189,37 @@ def test_create_connection_ip_addr(self, m_socket):
12091189
def test_create_connection_no_inet_pton(self, m_socket):
12101190
self._test_create_connection_ip_addr(m_socket, False)
12111191

1192+
@patch_socket
1193+
def test_create_connection_service_name(self, m_socket):
1194+
m_socket.getaddrinfo = socket.getaddrinfo
1195+
sock = m_socket.socket.return_value
1196+
1197+
self.loop.add_reader = mock.Mock()
1198+
self.loop.add_reader._is_coroutine = False
1199+
self.loop.add_writer = mock.Mock()
1200+
self.loop.add_writer._is_coroutine = False
1201+
1202+
for service, port in ('http', 80), (b'http', 80):
1203+
coro = self.loop.create_connection(asyncio.Protocol,
1204+
'127.0.0.1', service)
1205+
1206+
t, p = self.loop.run_until_complete(coro)
1207+
try:
1208+
sock.connect.assert_called_with(('127.0.0.1', port))
1209+
_, kwargs = m_socket.socket.call_args
1210+
self.assertEqual(kwargs['family'], m_socket.AF_INET)
1211+
self.assertEqual(kwargs['type'], m_socket.SOCK_STREAM)
1212+
finally:
1213+
t.close()
1214+
test_utils.run_briefly(self.loop) # allow transport to close
1215+
1216+
for service in 'nonsense', b'nonsense':
1217+
coro = self.loop.create_connection(asyncio.Protocol,
1218+
'127.0.0.1', service)
1219+
1220+
with self.assertRaises(OSError):
1221+
self.loop.run_until_complete(coro)
1222+
12121223
def test_create_connection_no_local_addr(self):
12131224
@asyncio.coroutine
12141225
def getaddrinfo(host, *args, **kw):

Lib/test/test_asyncio/test_selector_events.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import errno
44
import socket
5+
import threading
6+
import time
57
import unittest
68
from unittest import mock
79
try:
@@ -1784,5 +1786,89 @@ def test_fatal_error_connected(self, m_exc):
17841786
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
17851787
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
17861788

1789+
1790+
class SelectorLoopFunctionalTests(unittest.TestCase):
1791+
1792+
def setUp(self):
1793+
self.loop = asyncio.new_event_loop()
1794+
asyncio.set_event_loop(None)
1795+
1796+
def tearDown(self):
1797+
self.loop.close()
1798+
1799+
@asyncio.coroutine
1800+
def recv_all(self, sock, nbytes):
1801+
buf = b''
1802+
while len(buf) < nbytes:
1803+
buf += yield from self.loop.sock_recv(sock, nbytes - len(buf))
1804+
return buf
1805+
1806+
def test_sock_connect_sock_write_race(self):
1807+
TIMEOUT = 3.0
1808+
PAYLOAD = b'DATA' * 1024 * 1024
1809+
1810+
class Server(threading.Thread):
1811+
def __init__(self, *args, srv_sock, **kwargs):
1812+
super().__init__(*args, **kwargs)
1813+
self.srv_sock = srv_sock
1814+
1815+
def run(self):
1816+
with self.srv_sock:
1817+
srv_sock.listen(100)
1818+
1819+
sock, addr = self.srv_sock.accept()
1820+
sock.settimeout(TIMEOUT)
1821+
1822+
with sock:
1823+
sock.sendall(b'helo')
1824+
1825+
buf = bytearray()
1826+
while len(buf) < len(PAYLOAD):
1827+
pack = sock.recv(1024 * 65)
1828+
if not pack:
1829+
break
1830+
buf.extend(pack)
1831+
1832+
@asyncio.coroutine
1833+
def client(addr):
1834+
sock = socket.socket()
1835+
with sock:
1836+
sock.setblocking(False)
1837+
1838+
started = time.monotonic()
1839+
while True:
1840+
if time.monotonic() - started > TIMEOUT:
1841+
self.fail('unable to connect to the socket')
1842+
return
1843+
try:
1844+
yield from self.loop.sock_connect(sock, addr)
1845+
except OSError:
1846+
yield from asyncio.sleep(0.05, loop=self.loop)
1847+
else:
1848+
break
1849+
1850+
# Give 'Server' thread a chance to accept and send b'helo'
1851+
time.sleep(0.1)
1852+
1853+
data = yield from self.recv_all(sock, 4)
1854+
self.assertEqual(data, b'helo')
1855+
yield from self.loop.sock_sendall(sock, PAYLOAD)
1856+
1857+
srv_sock = socket.socket()
1858+
srv_sock.settimeout(TIMEOUT)
1859+
srv_sock.bind(('127.0.0.1', 0))
1860+
srv_addr = srv_sock.getsockname()
1861+
1862+
srv = Server(srv_sock=srv_sock, daemon=True)
1863+
srv.start()
1864+
1865+
try:
1866+
self.loop.run_until_complete(
1867+
asyncio.wait_for(client(srv_addr), loop=self.loop,
1868+
timeout=TIMEOUT))
1869+
finally:
1870+
srv.join()
1871+
1872+
17871873
if __name__ == '__main__':
17881874
unittest.main()

Lib/test/test_asyncio/test_tasks.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,37 @@ def foo(): yield from []
17231723
wd['cw'] = cw # Would fail without __weakref__ slot.
17241724
cw.gen = None # Suppress warning from __del__.
17251725

1726+
def test_corowrapper_throw(self):
1727+
# Issue 429: CoroWrapper.throw must be compatible with gen.throw
1728+
def foo():
1729+
value = None
1730+
while True:
1731+
try:
1732+
value = yield value
1733+
except Exception as e:
1734+
value = e
1735+
1736+
exception = Exception("foo")
1737+
cw = asyncio.coroutines.CoroWrapper(foo())
1738+
cw.send(None)
1739+
self.assertIs(exception, cw.throw(exception))
1740+
1741+
cw = asyncio.coroutines.CoroWrapper(foo())
1742+
cw.send(None)
1743+
self.assertIs(exception, cw.throw(Exception, exception))
1744+
1745+
cw = asyncio.coroutines.CoroWrapper(foo())
1746+
cw.send(None)
1747+
exception = cw.throw(Exception, "foo")
1748+
self.assertIsInstance(exception, Exception)
1749+
self.assertEqual(exception.args, ("foo", ))
1750+
1751+
cw = asyncio.coroutines.CoroWrapper(foo())
1752+
cw.send(None)
1753+
exception = cw.throw(Exception, "foo", None)
1754+
self.assertIsInstance(exception, Exception)
1755+
self.assertEqual(exception.args, ("foo", ))
1756+
17261757
@unittest.skipUnless(PY34,
17271758
'need python 3.4 or later')
17281759
def test_log_destroyed_pending_task(self):

0 commit comments

Comments
 (0)