diff options
| -rw-r--r-- | Doc/library/asyncio-protocol.rst | 6 | ||||
| -rw-r--r-- | Doc/library/asyncio-stream.rst | 6 | ||||
| -rw-r--r-- | Doc/library/binascii.rst | 9 | ||||
| -rw-r--r-- | Lib/asyncio/base_events.py | 119 | ||||
| -rw-r--r-- | Lib/asyncio/proactor_events.py | 3 | ||||
| -rw-r--r-- | Lib/asyncio/selector_events.py | 3 | ||||
| -rw-r--r-- | Lib/asyncio/streams.py | 3 | ||||
| -rw-r--r-- | Lib/asyncio/tasks.py | 8 | ||||
| -rw-r--r-- | Lib/asyncio/test_utils.py | 9 | ||||
| -rw-r--r-- | Lib/idlelib/README.txt | 2 | ||||
| -rw-r--r-- | Lib/subprocess.py | 3 | ||||
| -rw-r--r-- | Lib/test/script_helper.py | 2 | ||||
| -rw-r--r-- | Lib/test/test__locale.py | 4 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_base_events.py | 223 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_events.py | 4 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_proactor_events.py | 6 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_streams.py | 17 | ||||
| -rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 19 | ||||
| -rw-r--r-- | Lib/test/test_cmd_line.py | 18 | ||||
| -rw-r--r--[-rwxr-xr-x] | Lib/test/test_script_helper.py | 0 | ||||
| -rw-r--r-- | Modules/_elementtree.c | 127 |
21 files changed, 408 insertions, 183 deletions
diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst index 78faeae..f9298b2 100644 --- a/Doc/library/asyncio-protocol.rst +++ b/Doc/library/asyncio-protocol.rst @@ -1,8 +1,8 @@ .. currentmodule:: asyncio -+++++++++++++++++++++++++++++++++++++++++ -Transports and protocols (low-level API) -+++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++ +Transports and protocols (callback based API) +++++++++++++++++++++++++++++++++++++++++++++++ .. _asyncio-transport: diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index 171fd86..52b93f9 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -2,9 +2,9 @@ .. _asyncio-streams: -++++++++++++++++++++++++ -Streams (high-level API) -++++++++++++++++++++++++ ++++++++++++++++++++++++++++++ +Streams (coroutine based API) ++++++++++++++++++++++++++++++ Stream functions ================ diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index e3f134b..dbe535d 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -55,8 +55,10 @@ The :mod:`binascii` module defines the following functions: .. function:: b2a_base64(data) Convert binary data to a line of ASCII characters in base64 coding. The return - value is the converted line, including a newline char. The length of *data* - should be at most 57 to adhere to the base64 standard. + value is the converted line, including a newline char. The newline is + added because the original use case for this function was to feed it a + series of 57 byte input lines to get output lines that conform to the + MIME-base64 standard. Otherwise the output conforms to :rfc:`3548`. .. function:: a2b_qp(data, header=False) @@ -168,7 +170,8 @@ The :mod:`binascii` module defines the following functions: .. seealso:: Module :mod:`base64` - Support for base64 encoding used in MIME email messages. + Support for RFC compliant base64-style encoding in base 16, 32, 64, + and 85. Module :mod:`binhex` Support for the binhex format used on the Macintosh. diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index c5ffad4..4505732 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -16,8 +16,10 @@ to modify the meaning of the API call itself. import collections import concurrent.futures +import functools import heapq import inspect +import ipaddress import itertools import logging import os @@ -70,49 +72,83 @@ def _format_pipe(fd): return repr(fd) +# Linux's sock.type is a bitmask that can include extra info about socket. +_SOCKET_TYPE_MASK = 0 +if hasattr(socket, 'SOCK_NONBLOCK'): + _SOCKET_TYPE_MASK |= socket.SOCK_NONBLOCK +if hasattr(socket, 'SOCK_CLOEXEC'): + _SOCKET_TYPE_MASK |= socket.SOCK_CLOEXEC + + +@functools.lru_cache(maxsize=1024) +def _ipaddr_info(host, port, family, type, proto): + # Try to skip getaddrinfo if "host" is already an IP. Since getaddrinfo + # blocks on an exclusive lock on some platforms, users might handle name + # resolution in their own code and pass in resolved IPs. + if proto not in {0, socket.IPPROTO_TCP, socket.IPPROTO_UDP} or host is None: + return None + + type &= ~_SOCKET_TYPE_MASK + if type == socket.SOCK_STREAM: + proto = socket.IPPROTO_TCP + elif type == socket.SOCK_DGRAM: + proto = socket.IPPROTO_UDP + else: + return None + + if hasattr(socket, 'inet_pton'): + if family == socket.AF_UNSPEC: + afs = [socket.AF_INET, socket.AF_INET6] + else: + afs = [family] + + for af in afs: + # Linux's inet_pton doesn't accept an IPv6 zone index after host, + # like '::1%lo0', so strip it. If we happen to make an invalid + # address look valid, we fail later in sock.connect or sock.bind. + try: + if af == socket.AF_INET6: + socket.inet_pton(af, host.partition('%')[0]) + else: + socket.inet_pton(af, host) + return af, type, proto, '', (host, port) + except OSError: + pass + + # "host" is not an IP address. + return None + + # No inet_pton. (On Windows it's only available since Python 3.4.) + # Even though getaddrinfo with AI_NUMERICHOST would be non-blocking, it + # still requires a lock on some platforms, and waiting for that lock could + # block the event loop. Use ipaddress instead, it's just text parsing. + try: + addr = ipaddress.IPv4Address(host) + except ValueError: + try: + addr = ipaddress.IPv6Address(host.partition('%')[0]) + except ValueError: + return None + + af = socket.AF_INET if addr.version == 4 else socket.AF_INET6 + if family not in (socket.AF_UNSPEC, af): + # "host" is wrong IP version for "family". + return None + + return af, type, proto, '', (host, port) + + def _check_resolved_address(sock, address): # Ensure that the address is already resolved to avoid the trap of hanging # the entire event loop when the address requires doing a DNS lookup. - # - # getaddrinfo() is slow (around 10 us per call): this function should only - # be called in debug mode - family = sock.family - - if family == socket.AF_INET: - host, port = address - elif family == socket.AF_INET6: - host, port = address[:2] - else: + + if hasattr(socket, 'AF_UNIX') and sock.family == socket.AF_UNIX: return - # On Windows, socket.inet_pton() is only available since Python 3.4 - if hasattr(socket, 'inet_pton'): - # getaddrinfo() is slow and has known issue: prefer inet_pton() - # if available - try: - socket.inet_pton(family, host) - except OSError as exc: - raise ValueError("address must be resolved (IP address), " - "got host %r: %s" - % (host, exc)) - else: - # Use getaddrinfo(flags=AI_NUMERICHOST) to ensure that the address is - # already resolved. - type_mask = 0 - if hasattr(socket, 'SOCK_NONBLOCK'): - type_mask |= socket.SOCK_NONBLOCK - if hasattr(socket, 'SOCK_CLOEXEC'): - type_mask |= socket.SOCK_CLOEXEC - try: - socket.getaddrinfo(host, port, - family=family, - type=(sock.type & ~type_mask), - proto=sock.proto, - flags=socket.AI_NUMERICHOST) - except socket.gaierror as err: - raise ValueError("address must be resolved (IP address), " - "got host %r: %s" - % (host, err)) + host, port = address[:2] + if _ipaddr_info(host, port, sock.family, sock.type, sock.proto) is None: + raise ValueError("address must be resolved (IP address)," + " got host %r" % host) def _run_until_complete_cb(fut): @@ -535,7 +571,12 @@ class BaseEventLoop(events.AbstractEventLoop): def getaddrinfo(self, host, port, *, family=0, type=0, proto=0, flags=0): - if self._debug: + info = _ipaddr_info(host, port, family, type, proto) + if info is not None: + fut = futures.Future(loop=self) + fut.set_result([info]) + return fut + elif self._debug: return self.run_in_executor(None, self._getaddrinfo_debug, host, port, family, type, proto, flags) else: diff --git a/Lib/asyncio/proactor_events.py b/Lib/asyncio/proactor_events.py index 7eac41e..14c0659 100644 --- a/Lib/asyncio/proactor_events.py +++ b/Lib/asyncio/proactor_events.py @@ -441,8 +441,7 @@ class BaseProactorEventLoop(base_events.BaseEventLoop): def sock_connect(self, sock, address): try: - if self._debug: - base_events._check_resolved_address(sock, address) + base_events._check_resolved_address(sock, address) except ValueError as err: fut = futures.Future(loop=self) fut.set_exception(err) diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py index a05f81c..5b26631 100644 --- a/Lib/asyncio/selector_events.py +++ b/Lib/asyncio/selector_events.py @@ -397,8 +397,7 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop): raise ValueError("the socket must be non-blocking") fut = futures.Future(loop=self) try: - if self._debug: - base_events._check_resolved_address(sock, address) + base_events._check_resolved_address(sock, address) except ValueError as err: fut.set_exception(err) else: diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index 6b5e96a..9097e38 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -494,6 +494,9 @@ class StreamReader: @coroutine def readexactly(self, n): + if n < 0: + raise ValueError('readexactly size can not be less than zero') + if self._exception is not None: raise self._exception diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py index e6389d8..a2ab881 100644 --- a/Lib/asyncio/tasks.py +++ b/Lib/asyncio/tasks.py @@ -251,7 +251,13 @@ class Task(futures.Future): else: if isinstance(result, futures.Future): # Yielded Future must come from Future.__iter__(). - if result._blocking: + if result._loop is not self._loop: + self._loop.call_soon( + self._step, + RuntimeError( + 'Task {!r} got Future {!r} attached to a ' + 'different loop'.format(self, result))) + elif result._blocking: result._blocking = False result.add_done_callback(self._wakeup) self._fut_waiter = result diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py index 8170533..396e6ae 100644 --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -446,9 +446,14 @@ def disable_logger(): finally: logger.setLevel(old_level) -def mock_nonblocking_socket(): + +def mock_nonblocking_socket(proto=socket.IPPROTO_TCP, type=socket.SOCK_STREAM, + family=socket.AF_INET): """Create a mock of a non-blocking socket.""" - sock = mock.Mock(socket.socket) + sock = mock.MagicMock(socket.socket) + sock.proto = proto + sock.type = type + sock.family = family sock.gettimeout.return_value = 0.0 return sock diff --git a/Lib/idlelib/README.txt b/Lib/idlelib/README.txt index b5663c2..7bf74c0 100644 --- a/Lib/idlelib/README.txt +++ b/Lib/idlelib/README.txt @@ -1,6 +1,6 @@ README.txt: an index to idlelib files and the IDLE menu. -IDLE is Python’s Integrated Development and Learning +IDLE is Python's Integrated Development and Learning Environment. The user documentation is part of the Library Reference and is available in IDLE by selecting Help => IDLE Help. This README documents idlelib for IDLE developers and curious users. diff --git a/Lib/subprocess.py b/Lib/subprocess.py index abf43e5..04cfb44 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -512,14 +512,11 @@ def _args_from_interpreter_flags(): 'verbose': 'v', 'bytes_warning': 'b', 'quiet': 'q', - 'hash_randomization': 'R', } args = [] for flag, opt in flag_opt_map.items(): v = getattr(sys.flags, flag) if v > 0: - if flag == 'hash_randomization': - v = 1 # Handle specification of an exact seed args.append('-' + opt * v) for opt in sys.warnoptions: args.append('-W' + opt) diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py index b29392f..d27496b 100644 --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -107,7 +107,7 @@ def assert_python_ok(*args, **env_vars): variables `env_vars` succeeds (rc == 0) and return a (return code, stdout, stderr) tuple. - If the __cleanenv keyword is set, env_vars is used a fresh environment. + If the __cleanenv keyword is set, env_vars is used as a fresh environment. Python is started in isolated mode (command line option -I), except if the __isolated keyword is set to False. diff --git a/Lib/test/test__locale.py b/Lib/test/test__locale.py index d95d3a4..58f2f04 100644 --- a/Lib/test/test__locale.py +++ b/Lib/test/test__locale.py @@ -67,7 +67,9 @@ def setUpModule(): known_numerics = { 'en_US': ('.', ','), 'de_DE' : (',', '.'), - 'fr_FR.UTF-8' : (',', ' '), + # The French thousands separator may be a breaking or non-breaking space + # depending on the platform, so do not test it + 'fr_FR' : (',', ''), 'ps_AF': ('\u066b', '\u066c'), } diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py index 072fe2f..d660717 100644 --- a/Lib/test/test_asyncio/test_base_events.py +++ b/Lib/test/test_asyncio/test_base_events.py @@ -32,6 +32,124 @@ MOCK_ANY = mock.ANY PY34 = sys.version_info >= (3, 4) +def mock_socket_module(): + m_socket = mock.MagicMock(spec=socket) + for name in ( + 'AF_INET', 'AF_INET6', 'AF_UNSPEC', 'IPPROTO_TCP', 'IPPROTO_UDP', + 'SOCK_STREAM', 'SOCK_DGRAM', 'SOL_SOCKET', 'SO_REUSEADDR', 'inet_pton' + ): + if hasattr(socket, name): + setattr(m_socket, name, getattr(socket, name)) + else: + delattr(m_socket, name) + + m_socket.socket = mock.MagicMock() + m_socket.socket.return_value = test_utils.mock_nonblocking_socket() + + return m_socket + + +def patch_socket(f): + return mock.patch('asyncio.base_events.socket', + new_callable=mock_socket_module)(f) + + +class BaseEventTests(test_utils.TestCase): + + def setUp(self): + super().setUp() + base_events._ipaddr_info.cache_clear() + + def tearDown(self): + base_events._ipaddr_info.cache_clear() + super().tearDown() + + def test_ipaddr_info(self): + UNSPEC = socket.AF_UNSPEC + INET = socket.AF_INET + INET6 = socket.AF_INET6 + STREAM = socket.SOCK_STREAM + DGRAM = socket.SOCK_DGRAM + TCP = socket.IPPROTO_TCP + UDP = socket.IPPROTO_UDP + + self.assertEqual( + (INET, STREAM, TCP, '', ('1.2.3.4', 1)), + base_events._ipaddr_info('1.2.3.4', 1, INET, STREAM, TCP)) + + self.assertEqual( + (INET, STREAM, TCP, '', ('1.2.3.4', 1)), + base_events._ipaddr_info('1.2.3.4', 1, UNSPEC, STREAM, TCP)) + + self.assertEqual( + (INET, DGRAM, UDP, '', ('1.2.3.4', 1)), + base_events._ipaddr_info('1.2.3.4', 1, UNSPEC, DGRAM, UDP)) + + # Socket type STREAM implies TCP protocol. + self.assertEqual( + (INET, STREAM, TCP, '', ('1.2.3.4', 1)), + base_events._ipaddr_info('1.2.3.4', 1, UNSPEC, STREAM, 0)) + + # Socket type DGRAM implies UDP protocol. + self.assertEqual( + (INET, DGRAM, UDP, '', ('1.2.3.4', 1)), + base_events._ipaddr_info('1.2.3.4', 1, UNSPEC, DGRAM, 0)) + + # No socket type. + self.assertIsNone( + base_events._ipaddr_info('1.2.3.4', 1, UNSPEC, 0, 0)) + + # IPv4 address with family IPv6. + self.assertIsNone( + base_events._ipaddr_info('1.2.3.4', 1, INET6, STREAM, TCP)) + + self.assertEqual( + (INET6, STREAM, TCP, '', ('::3', 1)), + base_events._ipaddr_info('::3', 1, INET6, STREAM, TCP)) + + self.assertEqual( + (INET6, STREAM, TCP, '', ('::3', 1)), + base_events._ipaddr_info('::3', 1, UNSPEC, STREAM, TCP)) + + # IPv6 address with family IPv4. + self.assertIsNone( + base_events._ipaddr_info('::3', 1, INET, STREAM, TCP)) + + # IPv6 address with zone index. + self.assertEqual( + (INET6, STREAM, TCP, '', ('::3%lo0', 1)), + base_events._ipaddr_info('::3%lo0', 1, INET6, STREAM, TCP)) + + @patch_socket + def test_ipaddr_info_no_inet_pton(self, m_socket): + del m_socket.inet_pton + self.test_ipaddr_info() + + def test_check_resolved_address(self): + sock = socket.socket(socket.AF_INET) + with sock: + base_events._check_resolved_address(sock, ('1.2.3.4', 1)) + + sock = socket.socket(socket.AF_INET6) + with sock: + base_events._check_resolved_address(sock, ('::3', 1)) + base_events._check_resolved_address(sock, ('::3%lo0', 1)) + with self.assertRaises(ValueError): + base_events._check_resolved_address(sock, ('foo', 1)) + + def test_check_resolved_sock_type(self): + # Ensure we ignore extra flags in sock.type. + if hasattr(socket, 'SOCK_NONBLOCK'): + sock = socket.socket(type=socket.SOCK_STREAM | socket.SOCK_NONBLOCK) + with sock: + base_events._check_resolved_address(sock, ('1.2.3.4', 1)) + + if hasattr(socket, 'SOCK_CLOEXEC'): + sock = socket.socket(type=socket.SOCK_STREAM | socket.SOCK_CLOEXEC) + with sock: + base_events._check_resolved_address(sock, ('1.2.3.4', 1)) + + class BaseEventLoopTests(test_utils.TestCase): def setUp(self): @@ -875,7 +993,12 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.loop = asyncio.new_event_loop() self.set_event_loop(self.loop) - @mock.patch('asyncio.base_events.socket') + def tearDown(self): + # Clear mocked constants like AF_INET from the cache. + base_events._ipaddr_info.cache_clear() + super().tearDown() + + @patch_socket def test_create_connection_multiple_errors(self, m_socket): class MyProto(asyncio.Protocol): @@ -908,7 +1031,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertEqual(str(cm.exception), 'Multiple exceptions: err1, err2') - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_connection_timeout(self, m_socket): # Ensure that the socket is closed on timeout sock = mock.Mock() @@ -986,7 +1109,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): with self.assertRaises(OSError): self.loop.run_until_complete(coro) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_connection_multiple_errors_local_addr(self, m_socket): def bind(addr): @@ -1018,6 +1141,53 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertTrue(str(cm.exception).startswith('Multiple exceptions: ')) self.assertTrue(m_socket.socket.return_value.close.called) + def _test_create_connection_ip_addr(self, m_socket, allow_inet_pton): + # Test the fallback code, even if this system has inet_pton. + if not allow_inet_pton: + del m_socket.inet_pton + + def getaddrinfo(*args, **kw): + self.fail('should not have called getaddrinfo') + + m_socket.getaddrinfo = getaddrinfo + sock = m_socket.socket.return_value + + self.loop.add_reader = mock.Mock() + self.loop.add_reader._is_coroutine = False + self.loop.add_writer = mock.Mock() + self.loop.add_writer._is_coroutine = False + + coro = self.loop.create_connection(asyncio.Protocol, '1.2.3.4', 80) + t, p = self.loop.run_until_complete(coro) + try: + sock.connect.assert_called_with(('1.2.3.4', 80)) + m_socket.socket.assert_called_with(family=m_socket.AF_INET, + proto=m_socket.IPPROTO_TCP, + type=m_socket.SOCK_STREAM) + finally: + t.close() + test_utils.run_briefly(self.loop) # allow transport to close + + sock.family = socket.AF_INET6 + coro = self.loop.create_connection(asyncio.Protocol, '::2', 80) + t, p = self.loop.run_until_complete(coro) + try: + sock.connect.assert_called_with(('::2', 80)) + m_socket.socket.assert_called_with(family=m_socket.AF_INET6, + proto=m_socket.IPPROTO_TCP, + type=m_socket.SOCK_STREAM) + finally: + t.close() + test_utils.run_briefly(self.loop) # allow transport to close + + @patch_socket + def test_create_connection_ip_addr(self, m_socket): + self._test_create_connection_ip_addr(m_socket, True) + + @patch_socket + def test_create_connection_no_inet_pton(self, m_socket): + self._test_create_connection_ip_addr(m_socket, False) + def test_create_connection_no_local_addr(self): @asyncio.coroutine def getaddrinfo(host, *args, **kw): @@ -1153,11 +1323,9 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): f = self.loop.create_server(MyProto, '0.0.0.0', 0) self.assertRaises(OSError, self.loop.run_until_complete, f) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_server_nosoreuseport(self, m_socket): m_socket.getaddrinfo = socket.getaddrinfo - m_socket.SOCK_STREAM = socket.SOCK_STREAM - m_socket.SOL_SOCKET = socket.SOL_SOCKET del m_socket.SO_REUSEPORT m_socket.socket.return_value = mock.Mock() @@ -1166,7 +1334,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises(ValueError, self.loop.run_until_complete, f) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_server_cant_bind(self, m_socket): class Err(OSError): @@ -1182,7 +1350,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises(OSError, self.loop.run_until_complete, fut) self.assertTrue(m_sock.close.called) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_datagram_endpoint_no_addrinfo(self, m_socket): m_socket.getaddrinfo.return_value = [] m_socket.getaddrinfo._is_coroutine = False @@ -1211,7 +1379,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises( OSError, self.loop.run_until_complete, coro) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_datagram_endpoint_socket_err(self, m_socket): m_socket.getaddrinfo = socket.getaddrinfo m_socket.socket.side_effect = OSError @@ -1234,7 +1402,7 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises( ValueError, self.loop.run_until_complete, coro) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_datagram_endpoint_setblk_err(self, m_socket): m_socket.socket.return_value.setblocking.side_effect = OSError @@ -1250,12 +1418,11 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): asyncio.DatagramProtocol) self.assertRaises(ValueError, self.loop.run_until_complete, coro) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_datagram_endpoint_cant_bind(self, m_socket): class Err(OSError): pass - m_socket.AF_INET6 = socket.AF_INET6 m_socket.getaddrinfo = socket.getaddrinfo m_sock = m_socket.socket.return_value = mock.Mock() m_sock.bind.side_effect = Err @@ -1369,11 +1536,8 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.loop.run_until_complete(protocol.done) self.assertEqual('CLOSED', protocol.state) - @mock.patch('asyncio.base_events.socket') + @patch_socket def test_create_datagram_endpoint_nosoreuseport(self, m_socket): - m_socket.getaddrinfo = socket.getaddrinfo - m_socket.SOCK_DGRAM = socket.SOCK_DGRAM - m_socket.SOL_SOCKET = socket.SOL_SOCKET del m_socket.SO_REUSEPORT m_socket.socket.return_value = mock.Mock() @@ -1385,6 +1549,33 @@ class BaseEventLoopWithSelectorTests(test_utils.TestCase): self.assertRaises(ValueError, self.loop.run_until_complete, coro) + @patch_socket + def test_create_datagram_endpoint_ip_addr(self, m_socket): + def getaddrinfo(*args, **kw): + self.fail('should not have called getaddrinfo') + + m_socket.getaddrinfo = getaddrinfo + m_socket.socket.return_value.bind = bind = mock.Mock() + self.loop.add_reader = mock.Mock() + self.loop.add_reader._is_coroutine = False + + reuseport_supported = hasattr(socket, 'SO_REUSEPORT') + coro = self.loop.create_datagram_endpoint( + lambda: MyDatagramProto(loop=self.loop), + local_addr=('1.2.3.4', 0), + reuse_address=False, + reuse_port=reuseport_supported) + + t, p = self.loop.run_until_complete(coro) + try: + bind.assert_called_with(('1.2.3.4', 0)) + m_socket.socket.assert_called_with(family=m_socket.AF_INET, + proto=m_socket.IPPROTO_UDP, + type=m_socket.SOCK_DGRAM) + finally: + t.close() + test_utils.run_briefly(self.loop) # allow transport to close + def test_accept_connection_retry(self): sock = mock.Mock() sock.accept.side_effect = BlockingIOError() diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py index 141fde7..f174604 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -1573,10 +1573,6 @@ class EventLoopTestsMixin: 'selector': self.loop._selector.__class__.__name__}) def test_sock_connect_address(self): - # In debug mode, sock_connect() must ensure that the address is already - # resolved (call _check_resolved_address()) - self.loop.set_debug(True) - addresses = [(socket.AF_INET, ('www.python.org', 80))] if support.IPV6_ENABLED: addresses.extend(( diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py index 5a0f088..5a92b1e 100644 --- a/Lib/test/test_asyncio/test_proactor_events.py +++ b/Lib/test/test_asyncio/test_proactor_events.py @@ -436,7 +436,7 @@ class ProactorSocketTransportTests(test_utils.TestCase): class BaseProactorEventLoopTests(test_utils.TestCase): def setUp(self): - self.sock = mock.Mock(socket.socket) + self.sock = test_utils.mock_nonblocking_socket() self.proactor = mock.Mock() self.ssock, self.csock = mock.Mock(), mock.Mock() @@ -491,8 +491,8 @@ class BaseProactorEventLoopTests(test_utils.TestCase): self.proactor.send.assert_called_with(self.sock, b'data') def test_sock_connect(self): - self.loop.sock_connect(self.sock, 123) - self.proactor.connect.assert_called_with(self.sock, 123) + self.loop.sock_connect(self.sock, ('1.2.3.4', 123)) + self.proactor.connect.assert_called_with(self.sock, ('1.2.3.4', 123)) def test_sock_accept(self): self.loop.sock_accept(self.sock) diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index 6f657ad..3b115b1 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -351,8 +351,8 @@ class StreamReaderTests(test_utils.TestCase): self.assertEqual(b'', data) self.assertEqual(self.DATA, stream._buffer) - data = self.loop.run_until_complete(stream.readexactly(-1)) - self.assertEqual(b'', data) + with self.assertRaisesRegex(ValueError, 'less than zero'): + self.loop.run_until_complete(stream.readexactly(-1)) self.assertEqual(self.DATA, stream._buffer) def test_readexactly(self): @@ -647,12 +647,13 @@ os.close(fd) def server(): # Runs in a separate thread. sock = socket.socket() - sock.bind(('localhost', 0)) - sock.listen(1) - addr = sock.getsockname() - q.put(addr) - clt, _ = sock.accept() - clt.close() + with sock: + sock.bind(('localhost', 0)) + sock.listen(1) + addr = sock.getsockname() + q.put(addr) + clt, _ = sock.accept() + clt.close() @asyncio.coroutine def client(host, port): diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index 04d19ac..5ee20f6 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -76,6 +76,21 @@ class TaskTests(test_utils.TestCase): def setUp(self): self.loop = self.new_test_loop() + def test_other_loop_future(self): + other_loop = asyncio.new_event_loop() + fut = asyncio.Future(loop=other_loop) + + @asyncio.coroutine + def run(fut): + yield from fut + + try: + with self.assertRaisesRegex(RuntimeError, + r'Task .* got Future .* attached'): + self.loop.run_until_complete(run(fut)) + finally: + other_loop.close() + def test_task_class(self): @asyncio.coroutine def notmuch(): @@ -2197,6 +2212,10 @@ class SleepTests(test_utils.TestCase): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(None) + def tearDown(self): + self.loop.close() + self.loop = None + def test_sleep_zero(self): result = 0 diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index cb9bbdd..5cad3ec 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -402,12 +402,24 @@ class CmdLineTest(unittest.TestCase): # Verify that -R enables hash randomization: self.verify_valid_flag('-R') hashes = [] - for i in range(2): + if os.environ.get('PYTHONHASHSEED', 'random') != 'random': + env = dict(os.environ) # copy + # We need to test that it is enabled by default without + # the environment variable enabling it for us. + del env['PYTHONHASHSEED'] + env['__cleanenv'] = '1' # consumed by assert_python_ok() + else: + env = {} + for i in range(3): code = 'print(hash("spam"))' - rc, out, err = assert_python_ok('-c', code) + rc, out, err = assert_python_ok('-c', code, **env) self.assertEqual(rc, 0) hashes.append(out) - self.assertNotEqual(hashes[0], hashes[1]) + hashes = sorted(set(hashes)) # uniq + # Rare chance of failure due to 3 random seeds honestly being equal. + self.assertGreater(len(hashes), 1, + msg='3 runs produced an identical random hash ' + ' for "spam": {}'.format(hashes)) # Verify that sys.flags contains hash_randomization code = 'import sys; print("random is", sys.flags.hash_randomization)' diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py index 372d6a7..372d6a7 100755..100644 --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index ad2f2f2..cf819e8 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -2448,6 +2448,23 @@ treebuilder_add_subelement(PyObject *element, PyObject *child) } } +LOCAL(int) +treebuilder_append_event(TreeBuilderObject *self, PyObject *action, + PyObject *node) +{ + if (action != NULL) { + PyObject *res = PyTuple_Pack(2, action, node); + if (res == NULL) + return -1; + if (PyList_Append(self->events, res) < 0) { + Py_DECREF(res); + return -1; + } + Py_DECREF(res); + } + return 0; +} + /* -------------------------------------------------------------------- */ /* handlers */ @@ -2515,16 +2532,8 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag, Py_INCREF(node); self->last = node; - if (self->start_event_obj) { - PyObject* res; - PyObject* action = self->start_event_obj; - res = PyTuple_Pack(2, action, node); - if (res) { - PyList_Append(self->events, res); - Py_DECREF(res); - } else - PyErr_Clear(); /* FIXME: propagate error */ - } + if (treebuilder_append_event(self, self->start_event_obj, node) < 0) + goto error; return node; @@ -2604,65 +2613,13 @@ treebuilder_handle_end(TreeBuilderObject* self, PyObject* tag) self->last = self->this; self->this = item; - if (self->end_event_obj) { - PyObject* res; - PyObject* action = self->end_event_obj; - PyObject* node = (PyObject*) self->last; - res = PyTuple_Pack(2, action, node); - if (res) { - PyList_Append(self->events, res); - Py_DECREF(res); - } else - PyErr_Clear(); /* FIXME: propagate error */ - } + if (treebuilder_append_event(self, self->end_event_obj, self->last) < 0) + return NULL; Py_INCREF(self->last); return (PyObject*) self->last; } -LOCAL(void) -treebuilder_handle_namespace(TreeBuilderObject* self, int start, - PyObject *prefix, PyObject *uri) -{ - PyObject* res; - PyObject* action; - PyObject* parcel; - - if (!self->events) - return; - - if (start) { - if (!self->start_ns_event_obj) - return; - action = self->start_ns_event_obj; - parcel = Py_BuildValue("OO", prefix, uri); - if (!parcel) - return; - Py_INCREF(action); - } else { - if (!self->end_ns_event_obj) - return; - action = self->end_ns_event_obj; - Py_INCREF(action); - parcel = Py_None; - Py_INCREF(parcel); - } - - res = PyTuple_New(2); - - if (res) { - PyTuple_SET_ITEM(res, 0, action); - PyTuple_SET_ITEM(res, 1, parcel); - PyList_Append(self->events, res); - Py_DECREF(res); - } - else { - Py_DECREF(action); - Py_DECREF(parcel); - PyErr_Clear(); /* FIXME: propagate error */ - } -} - /* -------------------------------------------------------------------- */ /* methods (in alphabetical order) */ @@ -3100,45 +3057,39 @@ static void expat_start_ns_handler(XMLParserObject* self, const XML_Char* prefix, const XML_Char *uri) { - PyObject* sprefix = NULL; - PyObject* suri = NULL; + TreeBuilderObject *target = (TreeBuilderObject*) self->target; + PyObject *parcel; if (PyErr_Occurred()) return; - if (uri) - suri = PyUnicode_DecodeUTF8(uri, strlen(uri), "strict"); - else - suri = PyUnicode_FromString(""); - if (!suri) - return; - - if (prefix) - sprefix = PyUnicode_DecodeUTF8(prefix, strlen(prefix), "strict"); - else - sprefix = PyUnicode_FromString(""); - if (!sprefix) { - Py_DECREF(suri); + if (!target->events || !target->start_ns_event_obj) return; - } - treebuilder_handle_namespace( - (TreeBuilderObject*) self->target, 1, sprefix, suri - ); + if (!uri) + uri = ""; + if (!prefix) + prefix = ""; - Py_DECREF(sprefix); - Py_DECREF(suri); + parcel = Py_BuildValue("ss", prefix, uri); + if (!parcel) + return; + treebuilder_append_event(target, target->start_ns_event_obj, parcel); + Py_DECREF(parcel); } static void expat_end_ns_handler(XMLParserObject* self, const XML_Char* prefix_in) { + TreeBuilderObject *target = (TreeBuilderObject*) self->target; + if (PyErr_Occurred()) return; - treebuilder_handle_namespace( - (TreeBuilderObject*) self->target, 0, NULL, NULL - ); + if (!target->events) + return; + + treebuilder_append_event(target, target->end_ns_event_obj, Py_None); } static void |
