summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Lib')
-rw-r--r--Lib/asyncio/base_events.py53
-rw-r--r--Lib/asyncio/queues.py6
-rw-r--r--Lib/asyncio/selector_events.py54
-rw-r--r--Lib/asyncio/tasks.py12
-rw-r--r--Lib/asyncio/test_utils.py18
-rw-r--r--Lib/distutils/command/upload.py9
-rw-r--r--Lib/distutils/tests/test_upload.py16
-rw-r--r--Lib/heapq.py32
-rw-r--r--Lib/http/server.py2
-rw-r--r--Lib/idlelib/HyperParser.py174
-rw-r--r--Lib/idlelib/ParenMatch.py14
-rw-r--r--Lib/idlelib/idle_test/test_hyperparser.py191
-rw-r--r--Lib/idlelib/idle_test/test_parenmatch.py109
-rw-r--r--Lib/os.py12
-rw-r--r--Lib/posixpath.py1
-rw-r--r--Lib/socketserver.py56
-rw-r--r--Lib/stat.py23
-rw-r--r--Lib/test/script_helper.py4
-rw-r--r--Lib/test/test_asyncio/test_base_events.py68
-rw-r--r--Lib/test/test_asyncio/test_events.py14
-rw-r--r--Lib/test/test_asyncio/test_futures.py25
-rw-r--r--Lib/test/test_asyncio/test_locks.py68
-rw-r--r--Lib/test/test_asyncio/test_proactor_events.py7
-rw-r--r--Lib/test/test_asyncio/test_queues.py47
-rw-r--r--Lib/test/test_asyncio/test_selector_events.py26
-rw-r--r--Lib/test/test_asyncio/test_streams.py5
-rw-r--r--Lib/test/test_asyncio/test_subprocess.py10
-rw-r--r--Lib/test/test_asyncio/test_tasks.py152
-rw-r--r--Lib/test/test_asyncio/test_unix_events.py40
-rw-r--r--Lib/test/test_asyncio/test_windows_events.py9
-rw-r--r--Lib/test/test_deque.py5
-rw-r--r--Lib/test/test_descr.py2
-rw-r--r--Lib/test/test_enum.py4
-rw-r--r--Lib/test/test_generators.py39
-rw-r--r--Lib/test/test_grammar.py25
-rw-r--r--Lib/test/test_heapq.py4
-rw-r--r--Lib/test/test_httpservers.py5
-rw-r--r--Lib/test/test_minidom.py7
-rw-r--r--Lib/test/test_os.py22
-rw-r--r--Lib/test/test_pydoc.py5
-rw-r--r--Lib/test/test_stat.py29
-rw-r--r--Lib/test/test_subprocess.py38
-rw-r--r--Lib/test/test_sys.py2
-rw-r--r--Lib/xml/dom/minidom.py2
44 files changed, 1017 insertions, 429 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
index 5ee21d1..9f9067e 100644
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -17,6 +17,7 @@ to modify the meaning of the API call itself.
import collections
import concurrent.futures
import heapq
+import inspect
import logging
import socket
import subprocess
@@ -37,6 +38,15 @@ __all__ = ['BaseEventLoop', 'Server']
_MAX_WORKERS = 5
+def _format_handle(handle):
+ cb = handle._callback
+ if inspect.ismethod(cb) and isinstance(cb.__self__, tasks.Task):
+ # format the task
+ return repr(cb.__self__)
+ else:
+ return str(handle)
+
+
class _StopError(BaseException):
"""Raised to stop the event loop."""
@@ -128,6 +138,9 @@ class BaseEventLoop(events.AbstractEventLoop):
self._clock_resolution = time.get_clock_info('monotonic').resolution
self._exception_handler = None
self._debug = False
+ # In debug mode, if the execution of a callback or a step of a task
+ # exceed this duration in seconds, the slow callback/task is logged.
+ self.slow_callback_duration = 0.1
def __repr__(self):
return ('<%s running=%s closed=%s debug=%s>'
@@ -320,7 +333,7 @@ class BaseEventLoop(events.AbstractEventLoop):
"than the current one")
def call_soon_threadsafe(self, callback, *args):
- """XXX"""
+ """Like call_soon(), but thread safe."""
handle = self._call_soon(callback, args, check_loop=False)
self._write_to_self()
return handle
@@ -358,7 +371,17 @@ class BaseEventLoop(events.AbstractEventLoop):
def create_connection(self, protocol_factory, host=None, port=None, *,
ssl=None, family=0, proto=0, flags=0, sock=None,
local_addr=None, server_hostname=None):
- """XXX"""
+ """Connect to a TCP server.
+
+ Create a streaming transport connection to a given Internet host and
+ port: socket family AF_INET or socket.AF_INET6 depending on host (or
+ family if specified), socket type SOCK_STREAM. protocol_factory must be
+ a callable returning a protocol instance.
+
+ This method is a coroutine which will try to establish the connection
+ in the background. When successful, the coroutine returns a
+ (transport, protocol) pair.
+ """
if server_hostname is not None and not ssl:
raise ValueError('server_hostname is only meaningful with ssl')
@@ -557,7 +580,12 @@ class BaseEventLoop(events.AbstractEventLoop):
backlog=100,
ssl=None,
reuse_address=None):
- """XXX"""
+ """Create a TCP server bound to host and port.
+
+ Return an AbstractServer object which can be used to stop the service.
+
+ This method is a coroutine.
+ """
if isinstance(ssl, bool):
raise TypeError('ssl argument must be an SSLContext or None')
if host is not None or port is not None:
@@ -808,16 +836,16 @@ class BaseEventLoop(events.AbstractEventLoop):
if logger.isEnabledFor(logging.INFO):
t0 = self.time()
event_list = self._selector.select(timeout)
- t1 = self.time()
- if t1-t0 >= 1:
+ dt = self.time() - t0
+ if dt >= 1:
level = logging.INFO
else:
level = logging.DEBUG
if timeout is not None:
logger.log(level, 'poll %.3f took %.3f seconds',
- timeout, t1-t0)
+ timeout, dt)
else:
- logger.log(level, 'poll took %.3f seconds', t1-t0)
+ logger.log(level, 'poll took %.3f seconds', dt)
else:
event_list = self._selector.select(timeout)
self._process_events(event_list)
@@ -840,7 +868,16 @@ class BaseEventLoop(events.AbstractEventLoop):
ntodo = len(self._ready)
for i in range(ntodo):
handle = self._ready.popleft()
- if not handle._cancelled:
+ if handle._cancelled:
+ continue
+ if self._debug:
+ t0 = self.time()
+ handle._run()
+ dt = self.time() - t0
+ if dt >= self.slow_callback_duration:
+ logger.warning('Executing %s took %.3f seconds',
+ _format_handle(handle), dt)
+ else:
handle._run()
handle = None # Needed to break cycles when an exception occurs.
diff --git a/Lib/asyncio/queues.py b/Lib/asyncio/queues.py
index 6283db3..57afb05 100644
--- a/Lib/asyncio/queues.py
+++ b/Lib/asyncio/queues.py
@@ -105,7 +105,7 @@ class Queue:
if self._maxsize <= 0:
return False
else:
- return self.qsize() == self._maxsize
+ return self.qsize() >= self._maxsize
@coroutine
def put(self, item):
@@ -126,7 +126,7 @@ class Queue:
self._put(item)
getter.set_result(self._get())
- elif self._maxsize > 0 and self._maxsize == self.qsize():
+ elif self._maxsize > 0 and self._maxsize <= self.qsize():
waiter = futures.Future(loop=self._loop)
self._putters.append((item, waiter))
@@ -152,7 +152,7 @@ class Queue:
self._put(item)
getter.set_result(self._get())
- elif self._maxsize > 0 and self._maxsize == self.qsize():
+ elif self._maxsize > 0 and self._maxsize <= self.qsize():
raise QueueFull
else:
self._put(item)
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index 1f8e5c8..a62a8e5 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -83,10 +83,15 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
self.add_reader(self._ssock.fileno(), self._read_from_self)
def _read_from_self(self):
- try:
- self._ssock.recv(1)
- except (BlockingIOError, InterruptedError):
- pass
+ while True:
+ try:
+ data = self._ssock.recv(4096)
+ if not data:
+ break
+ except InterruptedError:
+ continue
+ except BlockingIOError:
+ break
def _write_to_self(self):
# This may be called from a different thread, possibly after
@@ -221,7 +226,14 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
return False
def sock_recv(self, sock, n):
- """XXX"""
+ """Receive data from the socket.
+
+ The return value is a bytes object representing the data received.
+ The maximum amount of data to be received at once is specified by
+ nbytes.
+
+ This method is a coroutine.
+ """
fut = futures.Future(loop=self)
self._sock_recv(fut, False, sock, n)
return fut
@@ -248,7 +260,16 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
fut.set_result(data)
def sock_sendall(self, sock, data):
- """XXX"""
+ """Send data to the socket.
+
+ The socket must be connected to a remote socket. This method continues
+ to send data from data until either all data has been sent or an
+ error occurs. None is returned on success. On error, an exception is
+ raised, and there is no way to determine how much data, if any, was
+ successfully processed by the receiving end of the connection.
+
+ This method is a coroutine.
+ """
fut = futures.Future(loop=self)
if data:
self._sock_sendall(fut, False, sock, data)
@@ -280,7 +301,16 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
self.add_writer(fd, self._sock_sendall, fut, True, sock, data)
def sock_connect(self, sock, address):
- """XXX"""
+ """Connect to a remote socket at address.
+
+ The address must be already resolved to avoid the trap of hanging the
+ entire event loop when the address requires doing a DNS lookup. For
+ example, it must be an IP address, not an hostname, for AF_INET and
+ AF_INET6 address families. Use getaddrinfo() to resolve the hostname
+ asynchronously.
+
+ This method is a coroutine.
+ """
fut = futures.Future(loop=self)
try:
base_events._check_resolved_address(sock, address)
@@ -313,7 +343,15 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
fut.set_result(None)
def sock_accept(self, sock):
- """XXX"""
+ """Accept a connection.
+
+ The socket must be bound to an address and listening for connections.
+ The return value is a pair (conn, address) where conn is a new socket
+ object usable to send and receive data on the connection, and address
+ is the address bound to the socket on the other end of the connection.
+
+ This method is a coroutine.
+ """
fut = futures.Future(loop=self)
self._sock_accept(fut, False, sock)
return fut
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index e6fd3d3..eaf93f8 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -32,12 +32,12 @@ from .log import logger
_DEBUG = (not sys.flags.ignore_environment
and bool(os.environ.get('PYTHONASYNCIODEBUG')))
+_PY35 = (sys.version_info >= (3, 5))
+
class CoroWrapper:
# Wrapper for coroutine in _DEBUG mode.
- __slots__ = ['gen', 'func', '__name__', '__doc__', '__weakref__']
-
def __init__(self, gen, func):
assert inspect.isgenerator(gen), gen
self.gen = gen
@@ -111,8 +111,10 @@ def coroutine(func):
@functools.wraps(func)
def wrapper(*args, **kwds):
w = CoroWrapper(coro(*args, **kwds), func)
- w.__name__ = coro.__name__
- w.__doc__ = coro.__doc__
+ w.__name__ = func.__name__
+ if _PY35:
+ w.__qualname__ = func.__qualname__
+ w.__doc__ = func.__doc__
return w
wrapper._is_coroutine = True # For iscoroutinefunction().
@@ -190,7 +192,7 @@ class Task(futures.Future):
i = len(res)
text = self._coro.__name__
coro = self._coro
- if inspect.isgenerator(coro):
+ if iscoroutine(coro):
filename = coro.gi_code.co_filename
if coro.gi_frame is not None:
text += ' at %s:%s' % (filename, coro.gi_frame.f_lineno)
diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py
index 1062bae..d9c7ae2 100644
--- a/Lib/asyncio/test_utils.py
+++ b/Lib/asyncio/test_utils.py
@@ -11,6 +11,7 @@ import sys
import tempfile
import threading
import time
+import unittest
from unittest import mock
from http.server import HTTPServer
@@ -379,3 +380,20 @@ def get_function_source(func):
if source is None:
raise ValueError("unable to get the source of %r" % (func,))
return source
+
+
+class TestCase(unittest.TestCase):
+ def set_event_loop(self, loop, *, cleanup=True):
+ assert loop is not None
+ # ensure that the event loop is passed explicitly in asyncio
+ events.set_event_loop(None)
+ if cleanup:
+ self.addCleanup(loop.close)
+
+ def new_test_loop(self, gen=None):
+ loop = TestLoop(gen)
+ self.set_event_loop(loop)
+ return loop
+
+ def tearDown(self):
+ events.set_event_loop(None)
diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py
index b906435..1fdb456 100644
--- a/Lib/distutils/command/upload.py
+++ b/Lib/distutils/command/upload.py
@@ -12,7 +12,7 @@ import hashlib
from base64 import standard_b64encode
from urllib.request import urlopen, Request, HTTPError
from urllib.parse import urlparse
-from distutils.errors import DistutilsOptionError
+from distutils.errors import DistutilsError, DistutilsOptionError
from distutils.core import PyPIRCCommand
from distutils.spawn import spawn
from distutils import log
@@ -184,7 +184,7 @@ class upload(PyPIRCCommand):
reason = result.msg
except OSError as e:
self.announce(str(e), log.ERROR)
- return
+ raise
except HTTPError as e:
status = e.code
reason = e.msg
@@ -193,8 +193,9 @@ class upload(PyPIRCCommand):
self.announce('Server response (%s): %s' % (status, reason),
log.INFO)
else:
- self.announce('Upload failed (%s): %s' % (status, reason),
- log.ERROR)
+ msg = 'Upload failed (%s): %s' % (status, reason)
+ self.announce(msg, log.ERROR)
+ raise DistutilsError(msg)
if self.show_response:
text = self._read_pypi_response(result)
msg = '\n'.join(('-' * 75, text, '-' * 75))
diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py
index f53eb26..0380f97 100644
--- a/Lib/distutils/tests/test_upload.py
+++ b/Lib/distutils/tests/test_upload.py
@@ -6,6 +6,7 @@ from test.support import run_unittest
from distutils.command import upload as upload_mod
from distutils.command.upload import upload
from distutils.core import Distribution
+from distutils.errors import DistutilsError
from distutils.log import INFO
from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase
@@ -41,13 +42,14 @@ username:me
class FakeOpen(object):
- def __init__(self, url):
+ def __init__(self, url, msg=None, code=None):
self.url = url
if not isinstance(url, str):
self.req = url
else:
self.req = None
- self.msg = 'OK'
+ self.msg = msg or 'OK'
+ self.code = code or 200
def getheader(self, name, default=None):
return {
@@ -58,7 +60,7 @@ class FakeOpen(object):
return b'xyzzy'
def getcode(self):
- return 200
+ return self.code
class uploadTestCase(PyPIRCCommandTestCase):
@@ -68,13 +70,15 @@ class uploadTestCase(PyPIRCCommandTestCase):
self.old_open = upload_mod.urlopen
upload_mod.urlopen = self._urlopen
self.last_open = None
+ self.next_msg = None
+ self.next_code = None
def tearDown(self):
upload_mod.urlopen = self.old_open
super(uploadTestCase, self).tearDown()
def _urlopen(self, url):
- self.last_open = FakeOpen(url)
+ self.last_open = FakeOpen(url, msg=self.next_msg, code=self.next_code)
return self.last_open
def test_finalize_options(self):
@@ -135,6 +139,10 @@ class uploadTestCase(PyPIRCCommandTestCase):
results = self.get_logs(INFO)
self.assertIn('xyzzy\n', results[-1])
+ def test_upload_fails(self):
+ self.next_msg = "Not Found"
+ self.next_code = 404
+ self.assertRaises(DistutilsError, self.test_upload)
def test_suite():
return unittest.makeSuite(uploadTestCase)
diff --git a/Lib/heapq.py b/Lib/heapq.py
index b20f04d..258c0ba 100644
--- a/Lib/heapq.py
+++ b/Lib/heapq.py
@@ -311,16 +311,6 @@ def _siftup_max(heap, pos):
heap[pos] = newitem
_siftdown_max(heap, startpos, pos)
-# If available, use C implementation
-try:
- from _heapq import *
-except ImportError:
- pass
-try:
- from _heapq import _heapreplace_max
-except ImportError:
- pass
-
def merge(*iterables, key=None, reverse=False):
'''Merge multiple sorted inputs into a single sorted output.
@@ -474,7 +464,7 @@ def nsmallest(n, iterable, key=None):
Equivalent to: sorted(iterable, key=key)[:n]
"""
- # Short-cut for n==1 is to use min() when len(iterable)>0
+ # Short-cut for n==1 is to use min()
if n == 1:
it = iter(iterable)
sentinel = object()
@@ -537,7 +527,7 @@ def nlargest(n, iterable, key=None):
Equivalent to: sorted(iterable, key=key, reverse=True)[:n]
"""
- # Short-cut for n==1 is to use max() when len(iterable)>0
+ # Short-cut for n==1 is to use max()
if n == 1:
it = iter(iterable)
sentinel = object()
@@ -592,6 +582,24 @@ def nlargest(n, iterable, key=None):
result.sort(reverse=True)
return [r[2] for r in result]
+# If available, use C implementation
+try:
+ from _heapq import *
+except ImportError:
+ pass
+try:
+ from _heapq import _heapreplace_max
+except ImportError:
+ pass
+try:
+ from _heapq import _heapify_max
+except ImportError:
+ pass
+try:
+ from _heapq import _heappop_max
+except ImportError:
+ pass
+
if __name__ == "__main__":
diff --git a/Lib/http/server.py b/Lib/http/server.py
index 6ce6bda..c98df19 100644
--- a/Lib/http/server.py
+++ b/Lib/http/server.py
@@ -977,7 +977,7 @@ class CGIHTTPRequestHandler(SimpleHTTPRequestHandler):
(and the next character is a '/' or the end of the string).
"""
- collapsed_path = _url_collapse_path(self.path)
+ collapsed_path = _url_collapse_path(urllib.parse.unquote(self.path))
dir_sep = collapsed_path.find('/', 1)
head, tail = collapsed_path[:dir_sep], collapsed_path[dir_sep+1:]
if head in self.cgi_directories:
diff --git a/Lib/idlelib/HyperParser.py b/Lib/idlelib/HyperParser.py
index 4af4b08..d376568 100644
--- a/Lib/idlelib/HyperParser.py
+++ b/Lib/idlelib/HyperParser.py
@@ -1,11 +1,8 @@
-"""
-HyperParser
-===========
-This module defines the HyperParser class, which provides advanced parsing
-abilities for the ParenMatch and other extensions.
-The HyperParser uses PyParser. PyParser is intended mostly to give information
-on the proper indentation of code. HyperParser gives some information on the
-structure of code, used by extensions to help the user.
+"""Provide advanced parsing abilities for ParenMatch and other extensions.
+
+HyperParser uses PyParser. PyParser mostly gives information on the
+proper indentation of code. HyperParser gives additional information on
+the structure of code.
"""
import string
@@ -15,9 +12,7 @@ from idlelib import PyParse
class HyperParser:
def __init__(self, editwin, index):
- """Initialize the HyperParser to analyze the surroundings of the given
- index.
- """
+ "To initialize, analyze the surroundings of the given index."
self.editwin = editwin
self.text = text = editwin.text
@@ -33,9 +28,10 @@ class HyperParser:
startat = max(lno - context, 1)
startatindex = repr(startat) + ".0"
stopatindex = "%d.end" % lno
- # We add the newline because PyParse requires a newline at end.
- # We add a space so that index won't be at end of line, so that
- # its status will be the same as the char before it, if should.
+ # We add the newline because PyParse requires a newline
+ # at end. We add a space so that index won't be at end
+ # of line, so that its status will be the same as the
+ # char before it, if should.
parser.set_str(text.get(startatindex, stopatindex)+' \n')
bod = parser.find_good_parse_start(
editwin._build_char_in_string_func(startatindex))
@@ -49,122 +45,131 @@ class HyperParser:
else:
startatindex = "1.0"
stopatindex = "%d.end" % lno
- # We add the newline because PyParse requires a newline at end.
- # We add a space so that index won't be at end of line, so that
- # its status will be the same as the char before it, if should.
+ # We add the newline because PyParse requires it. We add a
+ # space so that index won't be at end of line, so that its
+ # status will be the same as the char before it, if should.
parser.set_str(text.get(startatindex, stopatindex)+' \n')
parser.set_lo(0)
- # We want what the parser has, except for the last newline and space.
+ # We want what the parser has, minus the last newline and space.
self.rawtext = parser.str[:-2]
- # As far as I can see, parser.str preserves the statement we are in,
- # so that stopatindex can be used to synchronize the string with the
- # text box indices.
+ # Parser.str apparently preserves the statement we are in, so
+ # that stopatindex can be used to synchronize the string with
+ # the text box indices.
self.stopatindex = stopatindex
self.bracketing = parser.get_last_stmt_bracketing()
- # find which pairs of bracketing are openers. These always correspond
- # to a character of rawtext.
- self.isopener = [i>0 and self.bracketing[i][1] > self.bracketing[i-1][1]
+ # find which pairs of bracketing are openers. These always
+ # correspond to a character of rawtext.
+ self.isopener = [i>0 and self.bracketing[i][1] >
+ self.bracketing[i-1][1]
for i in range(len(self.bracketing))]
self.set_index(index)
def set_index(self, index):
- """Set the index to which the functions relate. Note that it must be
- in the same statement.
+ """Set the index to which the functions relate.
+
+ The index must be in the same statement.
"""
- indexinrawtext = \
- len(self.rawtext) - len(self.text.get(index, self.stopatindex))
+ indexinrawtext = (len(self.rawtext) -
+ len(self.text.get(index, self.stopatindex)))
if indexinrawtext < 0:
- raise ValueError("The index given is before the analyzed statement")
+ raise ValueError("Index %s precedes the analyzed statement"
+ % index)
self.indexinrawtext = indexinrawtext
# find the rightmost bracket to which index belongs
self.indexbracket = 0
- while self.indexbracket < len(self.bracketing)-1 and \
- self.bracketing[self.indexbracket+1][0] < self.indexinrawtext:
+ while (self.indexbracket < len(self.bracketing)-1 and
+ self.bracketing[self.indexbracket+1][0] < self.indexinrawtext):
self.indexbracket += 1
- if self.indexbracket < len(self.bracketing)-1 and \
- self.bracketing[self.indexbracket+1][0] == self.indexinrawtext and \
- not self.isopener[self.indexbracket+1]:
+ if (self.indexbracket < len(self.bracketing)-1 and
+ self.bracketing[self.indexbracket+1][0] == self.indexinrawtext and
+ not self.isopener[self.indexbracket+1]):
self.indexbracket += 1
def is_in_string(self):
- """Is the index given to the HyperParser is in a string?"""
+ """Is the index given to the HyperParser in a string?"""
# The bracket to which we belong should be an opener.
# If it's an opener, it has to have a character.
- return self.isopener[self.indexbracket] and \
- self.rawtext[self.bracketing[self.indexbracket][0]] in ('"', "'")
+ return (self.isopener[self.indexbracket] and
+ self.rawtext[self.bracketing[self.indexbracket][0]]
+ in ('"', "'"))
def is_in_code(self):
- """Is the index given to the HyperParser is in a normal code?"""
- return not self.isopener[self.indexbracket] or \
- self.rawtext[self.bracketing[self.indexbracket][0]] not in \
- ('#', '"', "'")
+ """Is the index given to the HyperParser in normal code?"""
+ return (not self.isopener[self.indexbracket] or
+ self.rawtext[self.bracketing[self.indexbracket][0]]
+ not in ('#', '"', "'"))
def get_surrounding_brackets(self, openers='([{', mustclose=False):
- """If the index given to the HyperParser is surrounded by a bracket
- defined in openers (or at least has one before it), return the
- indices of the opening bracket and the closing bracket (or the
- end of line, whichever comes first).
- If it is not surrounded by brackets, or the end of line comes before
- the closing bracket and mustclose is True, returns None.
+ """Return bracket indexes or None.
+
+ If the index given to the HyperParser is surrounded by a
+ bracket defined in openers (or at least has one before it),
+ return the indices of the opening bracket and the closing
+ bracket (or the end of line, whichever comes first).
+
+ If it is not surrounded by brackets, or the end of line comes
+ before the closing bracket and mustclose is True, returns None.
"""
+
bracketinglevel = self.bracketing[self.indexbracket][1]
before = self.indexbracket
- while not self.isopener[before] or \
- self.rawtext[self.bracketing[before][0]] not in openers or \
- self.bracketing[before][1] > bracketinglevel:
+ while (not self.isopener[before] or
+ self.rawtext[self.bracketing[before][0]] not in openers or
+ self.bracketing[before][1] > bracketinglevel):
before -= 1
if before < 0:
return None
bracketinglevel = min(bracketinglevel, self.bracketing[before][1])
after = self.indexbracket + 1
- while after < len(self.bracketing) and \
- self.bracketing[after][1] >= bracketinglevel:
+ while (after < len(self.bracketing) and
+ self.bracketing[after][1] >= bracketinglevel):
after += 1
beforeindex = self.text.index("%s-%dc" %
(self.stopatindex, len(self.rawtext)-self.bracketing[before][0]))
- if after >= len(self.bracketing) or \
- self.bracketing[after][0] > len(self.rawtext):
+ if (after >= len(self.bracketing) or
+ self.bracketing[after][0] > len(self.rawtext)):
if mustclose:
return None
afterindex = self.stopatindex
else:
- # We are after a real char, so it is a ')' and we give the index
- # before it.
- afterindex = self.text.index("%s-%dc" %
- (self.stopatindex,
+ # We are after a real char, so it is a ')' and we give the
+ # index before it.
+ afterindex = self.text.index(
+ "%s-%dc" % (self.stopatindex,
len(self.rawtext)-(self.bracketing[after][0]-1)))
return beforeindex, afterindex
- # This string includes all chars that may be in a white space
+ # Ascii chars that may be in a white space
_whitespace_chars = " \t\n\\"
- # This string includes all chars that may be in an identifier
+ # Ascii chars that may be in an identifier
_id_chars = string.ascii_letters + string.digits + "_"
- # This string includes all chars that may be the first char of an identifier
+ # Ascii chars that may be the first char of an identifier
_id_first_chars = string.ascii_letters + "_"
- # Given a string and pos, return the number of chars in the identifier
- # which ends at pos, or 0 if there is no such one. Saved words are not
- # identifiers.
+ # Given a string and pos, return the number of chars in the
+ # identifier which ends at pos, or 0 if there is no such one. Saved
+ # words are not identifiers.
def _eat_identifier(self, str, limit, pos):
i = pos
while i > limit and str[i-1] in self._id_chars:
i -= 1
- if i < pos and (str[i] not in self._id_first_chars or \
- keyword.iskeyword(str[i:pos])):
+ if (i < pos and (str[i] not in self._id_first_chars or
+ (keyword.iskeyword(str[i:pos]) and
+ str[i:pos] not in {'None', 'False', 'True'}))):
i = pos
return pos - i
def get_expression(self):
- """Return a string with the Python expression which ends at the given
- index, which is empty if there is no real one.
+ """Return a string with the Python expression which ends at the
+ given index, which is empty if there is no real one.
"""
if not self.is_in_code():
- raise ValueError("get_expression should only be called if index "\
- "is inside a code.")
+ raise ValueError("get_expression should only be called"
+ "if index is inside a code.")
rawtext = self.rawtext
bracketing = self.bracketing
@@ -177,20 +182,20 @@ class HyperParser:
postdot_phase = True
while 1:
- # Eat whitespaces, comments, and if postdot_phase is False - one dot
+ # Eat whitespaces, comments, and if postdot_phase is False - a dot
while 1:
if pos>brck_limit and rawtext[pos-1] in self._whitespace_chars:
# Eat a whitespace
pos -= 1
- elif not postdot_phase and \
- pos > brck_limit and rawtext[pos-1] == '.':
+ elif (not postdot_phase and
+ pos > brck_limit and rawtext[pos-1] == '.'):
# Eat a dot
pos -= 1
postdot_phase = True
- # The next line will fail if we are *inside* a comment, but we
- # shouldn't be.
- elif pos == brck_limit and brck_index > 0 and \
- rawtext[bracketing[brck_index-1][0]] == '#':
+ # The next line will fail if we are *inside* a comment,
+ # but we shouldn't be.
+ elif (pos == brck_limit and brck_index > 0 and
+ rawtext[bracketing[brck_index-1][0]] == '#'):
# Eat a comment
brck_index -= 2
brck_limit = bracketing[brck_index][0]
@@ -200,8 +205,8 @@ class HyperParser:
break
if not postdot_phase:
- # We didn't find a dot, so the expression end at the last
- # identifier pos.
+ # We didn't find a dot, so the expression end at the
+ # last identifier pos.
break
ret = self._eat_identifier(rawtext, brck_limit, pos)
@@ -209,13 +214,13 @@ class HyperParser:
# There is an identifier to eat
pos = pos - ret
last_identifier_pos = pos
- # Now, in order to continue the search, we must find a dot.
+ # Now, to continue the search, we must find a dot.
postdot_phase = False
# (the loop continues now)
elif pos == brck_limit:
- # We are at a bracketing limit. If it is a closing bracket,
- # eat the bracket, otherwise, stop the search.
+ # We are at a bracketing limit. If it is a closing
+ # bracket, eat the bracket, otherwise, stop the search.
level = bracketing[brck_index][1]
while brck_index > 0 and bracketing[brck_index-1][1] > level:
brck_index -= 1
@@ -244,3 +249,8 @@ class HyperParser:
break
return rawtext[last_identifier_pos:self.indexinrawtext]
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main('idlelib.idle_test.test_hyperparser', verbosity=2)
diff --git a/Lib/idlelib/ParenMatch.py b/Lib/idlelib/ParenMatch.py
index 6d91b39..19bad8c 100644
--- a/Lib/idlelib/ParenMatch.py
+++ b/Lib/idlelib/ParenMatch.py
@@ -90,7 +90,8 @@ class ParenMatch:
self.set_timeout = self.set_timeout_none
def flash_paren_event(self, event):
- indices = HyperParser(self.editwin, "insert").get_surrounding_brackets()
+ indices = (HyperParser(self.editwin, "insert")
+ .get_surrounding_brackets())
if indices is None:
self.warn_mismatched()
return
@@ -167,6 +168,11 @@ class ParenMatch:
# associate a counter with an event; only disable the "paren"
# tag if the event is for the most recent timer.
self.counter += 1
- self.editwin.text_frame.after(self.FLASH_DELAY,
- lambda self=self, c=self.counter: \
- self.handle_restore_timer(c))
+ self.editwin.text_frame.after(
+ self.FLASH_DELAY,
+ lambda self=self, c=self.counter: self.handle_restore_timer(c))
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main('idlelib.idle_test.test_parenmatch', verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_hyperparser.py b/Lib/idlelib/idle_test/test_hyperparser.py
new file mode 100644
index 0000000..68e97fc
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_hyperparser.py
@@ -0,0 +1,191 @@
+"""Unittest for idlelib.HyperParser"""
+import unittest
+from test.support import requires
+from tkinter import Tk, Text
+from idlelib.EditorWindow import EditorWindow
+from idlelib.HyperParser import HyperParser
+
+class DummyEditwin:
+ def __init__(self, text):
+ self.text = text
+ self.indentwidth = 8
+ self.tabwidth = 8
+ self.context_use_ps1 = True
+ self.num_context_lines = 50, 500, 1000
+
+ _build_char_in_string_func = EditorWindow._build_char_in_string_func
+ is_char_in_string = EditorWindow.is_char_in_string
+
+
+class HyperParserTest(unittest.TestCase):
+ code = (
+ '"""This is a module docstring"""\n'
+ '# this line is a comment\n'
+ 'x = "this is a string"\n'
+ "y = 'this is also a string'\n"
+ 'l = [i for i in range(10)]\n'
+ 'm = [py*py for # comment\n'
+ ' py in l]\n'
+ 'x.__len__\n'
+ "z = ((r'asdf')+('a')))\n"
+ '[x for x in\n'
+ 'for = False\n'
+ )
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.text = Text(cls.root)
+ cls.editwin = DummyEditwin(cls.text)
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.text, cls.editwin
+ cls.root.destroy()
+ del cls.root
+
+ def setUp(self):
+ self.text.insert('insert', self.code)
+
+ def tearDown(self):
+ self.text.delete('1.0', 'end')
+ self.editwin.context_use_ps1 = True
+
+ def get_parser(self, index):
+ """
+ Return a parser object with index at 'index'
+ """
+ return HyperParser(self.editwin, index)
+
+ def test_init(self):
+ """
+ test corner cases in the init method
+ """
+ with self.assertRaises(ValueError) as ve:
+ self.text.tag_add('console', '1.0', '1.end')
+ p = self.get_parser('1.5')
+ self.assertIn('precedes', str(ve.exception))
+
+ # test without ps1
+ self.editwin.context_use_ps1 = False
+
+ # number of lines lesser than 50
+ p = self.get_parser('end')
+ self.assertEqual(p.rawtext, self.text.get('1.0', 'end'))
+
+ # number of lines greater than 50
+ self.text.insert('end', self.text.get('1.0', 'end')*4)
+ p = self.get_parser('54.5')
+
+ def test_is_in_string(self):
+ get = self.get_parser
+
+ p = get('1.0')
+ self.assertFalse(p.is_in_string())
+ p = get('1.4')
+ self.assertTrue(p.is_in_string())
+ p = get('2.3')
+ self.assertFalse(p.is_in_string())
+ p = get('3.3')
+ self.assertFalse(p.is_in_string())
+ p = get('3.7')
+ self.assertTrue(p.is_in_string())
+ p = get('4.6')
+ self.assertTrue(p.is_in_string())
+
+ def test_is_in_code(self):
+ get = self.get_parser
+
+ p = get('1.0')
+ self.assertTrue(p.is_in_code())
+ p = get('1.1')
+ self.assertFalse(p.is_in_code())
+ p = get('2.5')
+ self.assertFalse(p.is_in_code())
+ p = get('3.4')
+ self.assertTrue(p.is_in_code())
+ p = get('3.6')
+ self.assertFalse(p.is_in_code())
+ p = get('4.14')
+ self.assertFalse(p.is_in_code())
+
+ def test_get_surrounding_bracket(self):
+ get = self.get_parser
+
+ def without_mustclose(parser):
+ # a utility function to get surrounding bracket
+ # with mustclose=False
+ return parser.get_surrounding_brackets(mustclose=False)
+
+ def with_mustclose(parser):
+ # a utility function to get surrounding bracket
+ # with mustclose=True
+ return parser.get_surrounding_brackets(mustclose=True)
+
+ p = get('3.2')
+ self.assertIsNone(with_mustclose(p))
+ self.assertIsNone(without_mustclose(p))
+
+ p = get('5.6')
+ self.assertTupleEqual(without_mustclose(p), ('5.4', '5.25'))
+ self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
+
+ p = get('5.23')
+ self.assertTupleEqual(without_mustclose(p), ('5.21', '5.24'))
+ self.assertTupleEqual(without_mustclose(p), with_mustclose(p))
+
+ p = get('6.15')
+ self.assertTupleEqual(without_mustclose(p), ('6.4', '6.end'))
+ self.assertIsNone(with_mustclose(p))
+
+ p = get('9.end')
+ self.assertIsNone(with_mustclose(p))
+ self.assertIsNone(without_mustclose(p))
+
+ def test_get_expression(self):
+ get = self.get_parser
+
+ p = get('4.2')
+ self.assertEqual(p.get_expression(), 'y ')
+
+ p = get('4.7')
+ with self.assertRaises(ValueError) as ve:
+ p.get_expression()
+ self.assertIn('is inside a code', str(ve.exception))
+
+ p = get('5.25')
+ self.assertEqual(p.get_expression(), 'range(10)')
+
+ p = get('6.7')
+ self.assertEqual(p.get_expression(), 'py')
+
+ p = get('6.8')
+ self.assertEqual(p.get_expression(), '')
+
+ p = get('7.9')
+ self.assertEqual(p.get_expression(), 'py')
+
+ p = get('8.end')
+ self.assertEqual(p.get_expression(), 'x.__len__')
+
+ p = get('9.13')
+ self.assertEqual(p.get_expression(), "r'asdf'")
+
+ p = get('9.17')
+ with self.assertRaises(ValueError) as ve:
+ p.get_expression()
+ self.assertIn('is inside a code', str(ve.exception))
+
+ p = get('10.0')
+ self.assertEqual(p.get_expression(), '')
+
+ p = get('11.3')
+ self.assertEqual(p.get_expression(), '')
+
+ p = get('11.11')
+ self.assertEqual(p.get_expression(), 'False')
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/Lib/idlelib/idle_test/test_parenmatch.py b/Lib/idlelib/idle_test/test_parenmatch.py
new file mode 100644
index 0000000..9aba4be
--- /dev/null
+++ b/Lib/idlelib/idle_test/test_parenmatch.py
@@ -0,0 +1,109 @@
+"""Test idlelib.ParenMatch."""
+# This must currently be a gui test because ParenMatch methods use
+# several text methods not defined on idlelib.idle_test.mock_tk.Text.
+
+import unittest
+from unittest.mock import Mock
+from test.support import requires
+from tkinter import Tk, Text
+from idlelib.ParenMatch import ParenMatch
+
+class DummyEditwin:
+ def __init__(self, text):
+ self.text = text
+ self.indentwidth = 8
+ self.tabwidth = 8
+ self.context_use_ps1 = True
+
+
+class ParenMatchTest(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ requires('gui')
+ cls.root = Tk()
+ cls.text = Text(cls.root)
+ cls.editwin = DummyEditwin(cls.text)
+ cls.editwin.text_frame = Mock()
+
+ @classmethod
+ def tearDownClass(cls):
+ del cls.text, cls.editwin
+ cls.root.destroy()
+ del cls.root
+
+ def tearDown(self):
+ self.text.delete('1.0', 'end')
+
+ def test_paren_expression(self):
+ """
+ Test ParenMatch with 'expression' style.
+ """
+ text = self.text
+ pm = ParenMatch(self.editwin)
+ pm.set_style('expression')
+
+ text.insert('insert', 'def foobar(a, b')
+ pm.flash_paren_event('event')
+ self.assertIn('<<parenmatch-check-restore>>', text.event_info())
+ self.assertTupleEqual(text.tag_prevrange('paren', 'end'),
+ ('1.10', '1.15'))
+ text.insert('insert', ')')
+ pm.restore_event()
+ self.assertNotIn('<<parenmatch-check-restore>>', text.event_info())
+ self.assertEqual(text.tag_prevrange('paren', 'end'), ())
+
+ # paren_closed_event can only be tested as below
+ pm.paren_closed_event('event')
+ self.assertTupleEqual(text.tag_prevrange('paren', 'end'),
+ ('1.10', '1.16'))
+
+ def test_paren_default(self):
+ """
+ Test ParenMatch with 'default' style.
+ """
+ text = self.text
+ pm = ParenMatch(self.editwin)
+ pm.set_style('default')
+
+ text.insert('insert', 'def foobar(a, b')
+ pm.flash_paren_event('event')
+ self.assertIn('<<parenmatch-check-restore>>', text.event_info())
+ self.assertTupleEqual(text.tag_prevrange('paren', 'end'),
+ ('1.10', '1.11'))
+ text.insert('insert', ')')
+ pm.restore_event()
+ self.assertNotIn('<<parenmatch-check-restore>>', text.event_info())
+ self.assertEqual(text.tag_prevrange('paren', 'end'), ())
+
+ def test_paren_corner(self):
+ """
+ Test corner cases in flash_paren_event and paren_closed_event.
+
+ These cases force conditional expression and alternate paths.
+ """
+ text = self.text
+ pm = ParenMatch(self.editwin)
+
+ text.insert('insert', '# this is a commen)')
+ self.assertIsNone(pm.paren_closed_event('event'))
+
+ text.insert('insert', '\ndef')
+ self.assertIsNone(pm.flash_paren_event('event'))
+ self.assertIsNone(pm.paren_closed_event('event'))
+
+ text.insert('insert', ' a, *arg)')
+ self.assertIsNone(pm.paren_closed_event('event'))
+
+ def test_handle_restore_timer(self):
+ pm = ParenMatch(self.editwin)
+ pm.restore_event = Mock()
+ pm.handle_restore_timer(0)
+ self.assertTrue(pm.restore_event.called)
+ pm.restore_event.reset_mock()
+ pm.handle_restore_timer(1)
+ self.assertFalse(pm.restore_event.called)
+
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/Lib/os.py b/Lib/os.py
index 8567f50..327656a 100644
--- a/Lib/os.py
+++ b/Lib/os.py
@@ -312,11 +312,12 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
When topdown is true, the caller can modify the dirnames list in-place
(e.g., via del or slice assignment), and walk will only recurse into the
- subdirectories whose names remain in dirnames; this can be used to prune
- the search, or to impose a specific order of visiting. Modifying
- dirnames when topdown is false is ineffective, since the directories in
- dirnames have already been generated by the time dirnames itself is
- generated.
+ subdirectories whose names remain in dirnames; this can be used to prune the
+ search, or to impose a specific order of visiting. Modifying dirnames when
+ topdown is false is ineffective, since the directories in dirnames have
+ already been generated by the time dirnames itself is generated. No matter
+ the value of topdown, the list of subdirectories is retrieved before the
+ tuples for the directory and its subdirectories are generated.
By default errors from the os.listdir() call are ignored. If
optional arg 'onerror' is specified, it should be a function; it
@@ -344,6 +345,7 @@ def walk(top, topdown=True, onerror=None, followlinks=False):
print("bytes in", len(files), "non-directory files")
if 'CVS' in dirs:
dirs.remove('CVS') # don't visit CVS directories
+
"""
islink, join, isdir = path.islink, path.join, path.isdir
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
index 3e13239..eb17dba 100644
--- a/Lib/posixpath.py
+++ b/Lib/posixpath.py
@@ -48,7 +48,6 @@ def _get_sep(path):
def normcase(s):
"""Normalize case of pathname. Has no effect under Posix"""
- # TODO: on Mac OS X, this should really return s.lower().
if not isinstance(s, (bytes, str)):
raise TypeError("normcase() argument must be str or bytes, "
"not '{}'".format(s.__class__.__name__))
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 7c85fbc..b585640 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -539,35 +539,39 @@ class ForkingMixIn:
def collect_children(self):
"""Internal routine to wait for children that have exited."""
- if self.active_children is None: return
+ if self.active_children is None:
+ return
+
+ # If we're above the max number of children, wait and reap them until
+ # we go back below threshold. Note that we use waitpid(-1) below to be
+ # able to collect children in size(<defunct children>) syscalls instead
+ # of size(<children>): the downside is that this might reap children
+ # which we didn't spawn, which is why we only resort to this when we're
+ # above max_children.
while len(self.active_children) >= self.max_children:
- # XXX: This will wait for any child process, not just ones
- # spawned by this library. This could confuse other
- # libraries that expect to be able to wait for their own
- # children.
try:
- pid, status = os.waitpid(0, 0)
+ pid, _ = os.waitpid(-1, 0)
+ self.active_children.discard(pid)
+ except InterruptedError:
+ pass
+ except ChildProcessError:
+ # we don't have any children, we're done
+ self.active_children.clear()
except OSError:
- pid = None
- if pid not in self.active_children: continue
- self.active_children.remove(pid)
-
- # XXX: This loop runs more system calls than it ought
- # to. There should be a way to put the active_children into a
- # process group and then use os.waitpid(-pgid) to wait for any
- # of that set, but I couldn't find a way to allocate pgids
- # that couldn't collide.
- for child in self.active_children:
+ break
+
+ # Now reap all defunct children.
+ for pid in self.active_children.copy():
try:
- pid, status = os.waitpid(child, os.WNOHANG)
+ pid, _ = os.waitpid(pid, os.WNOHANG)
+ # if the child hasn't exited yet, pid will be 0 and ignored by
+ # discard() below
+ self.active_children.discard(pid)
+ except ChildProcessError:
+ # someone else reaped it
+ self.active_children.discard(pid)
except OSError:
- pid = None
- if not pid: continue
- try:
- self.active_children.remove(pid)
- except ValueError as e:
- raise ValueError('%s. x=%d and list=%r' % (e.message, pid,
- self.active_children))
+ pass
def handle_timeout(self):
"""Wait for zombies after self.timeout seconds of inactivity.
@@ -589,8 +593,8 @@ class ForkingMixIn:
if pid:
# Parent process
if self.active_children is None:
- self.active_children = []
- self.active_children.append(pid)
+ self.active_children = set()
+ self.active_children.add(pid)
self.close_request(request)
return
else:
diff --git a/Lib/stat.py b/Lib/stat.py
index 3eecc3e..46837c0 100644
--- a/Lib/stat.py
+++ b/Lib/stat.py
@@ -148,6 +148,29 @@ def filemode(mode):
perm.append("-")
return "".join(perm)
+
+# Windows FILE_ATTRIBUTE constants for interpreting os.stat()'s
+# "st_file_attributes" member
+
+FILE_ATTRIBUTE_ARCHIVE = 32
+FILE_ATTRIBUTE_COMPRESSED = 2048
+FILE_ATTRIBUTE_DEVICE = 64
+FILE_ATTRIBUTE_DIRECTORY = 16
+FILE_ATTRIBUTE_ENCRYPTED = 16384
+FILE_ATTRIBUTE_HIDDEN = 2
+FILE_ATTRIBUTE_INTEGRITY_STREAM = 32768
+FILE_ATTRIBUTE_NORMAL = 128
+FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 8192
+FILE_ATTRIBUTE_NO_SCRUB_DATA = 131072
+FILE_ATTRIBUTE_OFFLINE = 4096
+FILE_ATTRIBUTE_READONLY = 1
+FILE_ATTRIBUTE_REPARSE_POINT = 1024
+FILE_ATTRIBUTE_SPARSE_FILE = 512
+FILE_ATTRIBUTE_SYSTEM = 4
+FILE_ATTRIBUTE_TEMPORARY = 256
+FILE_ATTRIBUTE_VIRTUAL = 65536
+
+
# If available, use C implementation
try:
from _stat import *
diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py
index 5559349..a7bb0d5 100644
--- a/Lib/test/script_helper.py
+++ b/Lib/test/script_helper.py
@@ -155,8 +155,8 @@ def make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename,
script_name = make_script(zip_dir, script_basename, source)
unlink.append(script_name)
if compiled:
- init_name = py_compile(init_name, doraise=True)
- script_name = py_compile(script_name, doraise=True)
+ init_name = py_compile.compile(init_name, doraise=True)
+ script_name = py_compile.compile(script_name, doraise=True)
unlink.extend((init_name, script_name))
pkg_names = [os.sep.join([pkg_name]*i) for i in range(1, depth+1)]
script_name_in_zip = os.path.join(pkg_names[-1], os.path.basename(script_name))
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
index 1611a11..352af48 100644
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -19,12 +19,12 @@ MOCK_ANY = mock.ANY
PY34 = sys.version_info >= (3, 4)
-class BaseEventLoopTests(unittest.TestCase):
+class BaseEventLoopTests(test_utils.TestCase):
def setUp(self):
self.loop = base_events.BaseEventLoop()
self.loop._selector = mock.Mock()
- asyncio.set_event_loop(None)
+ self.set_event_loop(self.loop)
def test_not_implemented(self):
m = mock.Mock()
@@ -240,30 +240,23 @@ class BaseEventLoopTests(unittest.TestCase):
self.loop.set_debug(False)
self.assertFalse(self.loop.get_debug())
- @mock.patch('asyncio.base_events.time')
@mock.patch('asyncio.base_events.logger')
- def test__run_once_logging(self, m_logger, m_time):
- # Log to INFO level if timeout > 1.0 sec.
- idx = -1
- data = [10.0, 10.0, 12.0, 13.0]
-
- def monotonic():
- nonlocal data, idx
- idx += 1
- return data[idx]
-
- m_time.monotonic = monotonic
+ def test__run_once_logging(self, m_logger):
+ def slow_select(timeout):
+ time.sleep(1.0)
+ return []
- self.loop._scheduled.append(
- asyncio.TimerHandle(11.0, lambda: True, (), self.loop))
+ # Log to INFO level if timeout > 1.0 sec.
+ self.loop._selector.select = slow_select
self.loop._process_events = mock.Mock()
self.loop._run_once()
self.assertEqual(logging.INFO, m_logger.log.call_args[0][0])
- idx = -1
- data = [10.0, 10.0, 10.3, 13.0]
- self.loop._scheduled = [asyncio.TimerHandle(11.0, lambda: True, (),
- self.loop)]
+ def fast_select(timeout):
+ time.sleep(0.001)
+ return []
+
+ self.loop._selector.select = fast_select
self.loop._run_once()
self.assertEqual(logging.DEBUG, m_logger.log.call_args[0][0])
@@ -555,14 +548,11 @@ class MyDatagramProto(asyncio.DatagramProtocol):
self.done.set_result(None)
-class BaseEventLoopWithSelectorTests(unittest.TestCase):
+class BaseEventLoopWithSelectorTests(test_utils.TestCase):
def setUp(self):
self.loop = asyncio.new_event_loop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.set_event_loop(self.loop)
@mock.patch('asyncio.base_events.socket')
def test_create_connection_multiple_errors(self, m_socket):
@@ -979,6 +969,34 @@ class BaseEventLoopWithSelectorTests(unittest.TestCase):
with self.assertRaises(TypeError):
self.loop.run_in_executor(None, coroutine_function)
+ @mock.patch('asyncio.base_events.logger')
+ def test_log_slow_callbacks(self, m_logger):
+ def stop_loop_cb(loop):
+ loop.stop()
+
+ @asyncio.coroutine
+ def stop_loop_coro(loop):
+ yield from ()
+ loop.stop()
+
+ asyncio.set_event_loop(self.loop)
+ self.loop.set_debug(True)
+ self.loop.slow_callback_duration = 0.0
+
+ # slow callback
+ self.loop.call_soon(stop_loop_cb, self.loop)
+ self.loop.run_forever()
+ fmt, *args = m_logger.warning.call_args[0]
+ self.assertRegex(fmt % tuple(args),
+ "^Executing Handle.*stop_loop_cb.* took .* seconds$")
+
+ # slow task
+ asyncio.async(stop_loop_coro(self.loop), loop=self.loop)
+ self.loop.run_forever()
+ fmt, *args = m_logger.warning.call_args[0]
+ self.assertRegex(fmt % tuple(args),
+ "^Executing Task.*stop_loop_coro.* took .* seconds$")
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
index 2262a75..37e45e1 100644
--- a/Lib/test/test_asyncio/test_events.py
+++ b/Lib/test/test_asyncio/test_events.py
@@ -224,7 +224,7 @@ class EventLoopTestsMixin:
def setUp(self):
super().setUp()
self.loop = self.create_event_loop()
- asyncio.set_event_loop(None)
+ self.set_event_loop(self.loop)
def tearDown(self):
# just in case if we have transport close callbacks
@@ -1629,14 +1629,14 @@ class SubprocessTestsMixin:
if sys.platform == 'win32':
- class SelectEventLoopTests(EventLoopTestsMixin, unittest.TestCase):
+ class SelectEventLoopTests(EventLoopTestsMixin, test_utils.TestCase):
def create_event_loop(self):
return asyncio.SelectorEventLoop()
class ProactorEventLoopTests(EventLoopTestsMixin,
SubprocessTestsMixin,
- unittest.TestCase):
+ test_utils.TestCase):
def create_event_loop(self):
return asyncio.ProactorEventLoop()
@@ -1691,7 +1691,7 @@ else:
if hasattr(selectors, 'KqueueSelector'):
class KqueueEventLoopTests(UnixEventLoopTestsMixin,
SubprocessTestsMixin,
- unittest.TestCase):
+ test_utils.TestCase):
def create_event_loop(self):
return asyncio.SelectorEventLoop(
@@ -1716,7 +1716,7 @@ else:
if hasattr(selectors, 'EpollSelector'):
class EPollEventLoopTests(UnixEventLoopTestsMixin,
SubprocessTestsMixin,
- unittest.TestCase):
+ test_utils.TestCase):
def create_event_loop(self):
return asyncio.SelectorEventLoop(selectors.EpollSelector())
@@ -1724,7 +1724,7 @@ else:
if hasattr(selectors, 'PollSelector'):
class PollEventLoopTests(UnixEventLoopTestsMixin,
SubprocessTestsMixin,
- unittest.TestCase):
+ test_utils.TestCase):
def create_event_loop(self):
return asyncio.SelectorEventLoop(selectors.PollSelector())
@@ -1732,7 +1732,7 @@ else:
# Should always exist.
class SelectEventLoopTests(UnixEventLoopTestsMixin,
SubprocessTestsMixin,
- unittest.TestCase):
+ test_utils.TestCase):
def create_event_loop(self):
return asyncio.SelectorEventLoop(selectors.SelectSelector())
diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py
index 399e8f4..a230d61 100644
--- a/Lib/test/test_asyncio/test_futures.py
+++ b/Lib/test/test_asyncio/test_futures.py
@@ -13,14 +13,10 @@ def _fakefunc(f):
return f
-class FutureTests(unittest.TestCase):
+class FutureTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def test_initial_state(self):
f = asyncio.Future(loop=self.loop)
@@ -30,12 +26,9 @@ class FutureTests(unittest.TestCase):
self.assertTrue(f.cancelled())
def test_init_constructor_default_loop(self):
- try:
- asyncio.set_event_loop(self.loop)
- f = asyncio.Future()
- self.assertIs(f._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ f = asyncio.Future()
+ self.assertIs(f._loop, self.loop)
def test_constructor_positional(self):
# Make sure Future doesn't accept a positional argument
@@ -264,14 +257,10 @@ class FutureTests(unittest.TestCase):
self.assertTrue(f2.cancelled())
-class FutureDoneCallbackTests(unittest.TestCase):
+class FutureDoneCallbackTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def run_briefly(self):
test_utils.run_briefly(self.loop)
diff --git a/Lib/test/test_asyncio/test_locks.py b/Lib/test/test_asyncio/test_locks.py
index f542463..9d50a71 100644
--- a/Lib/test/test_asyncio/test_locks.py
+++ b/Lib/test/test_asyncio/test_locks.py
@@ -17,14 +17,10 @@ STR_RGX_REPR = (
RGX_REPR = re.compile(STR_RGX_REPR)
-class LockTests(unittest.TestCase):
+class LockTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def test_ctor_loop(self):
loop = mock.Mock()
@@ -35,12 +31,9 @@ class LockTests(unittest.TestCase):
self.assertIs(lock._loop, self.loop)
def test_ctor_noloop(self):
- try:
- asyncio.set_event_loop(self.loop)
- lock = asyncio.Lock()
- self.assertIs(lock._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ lock = asyncio.Lock()
+ self.assertIs(lock._loop, self.loop)
def test_repr(self):
lock = asyncio.Lock(loop=self.loop)
@@ -240,14 +233,10 @@ class LockTests(unittest.TestCase):
self.assertFalse(lock.locked())
-class EventTests(unittest.TestCase):
+class EventTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def test_ctor_loop(self):
loop = mock.Mock()
@@ -258,12 +247,9 @@ class EventTests(unittest.TestCase):
self.assertIs(ev._loop, self.loop)
def test_ctor_noloop(self):
- try:
- asyncio.set_event_loop(self.loop)
- ev = asyncio.Event()
- self.assertIs(ev._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ ev = asyncio.Event()
+ self.assertIs(ev._loop, self.loop)
def test_repr(self):
ev = asyncio.Event(loop=self.loop)
@@ -376,14 +362,10 @@ class EventTests(unittest.TestCase):
self.assertTrue(t.result())
-class ConditionTests(unittest.TestCase):
+class ConditionTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def test_ctor_loop(self):
loop = mock.Mock()
@@ -394,12 +376,9 @@ class ConditionTests(unittest.TestCase):
self.assertIs(cond._loop, self.loop)
def test_ctor_noloop(self):
- try:
- asyncio.set_event_loop(self.loop)
- cond = asyncio.Condition()
- self.assertIs(cond._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ cond = asyncio.Condition()
+ self.assertIs(cond._loop, self.loop)
def test_wait(self):
cond = asyncio.Condition(loop=self.loop)
@@ -678,14 +657,10 @@ class ConditionTests(unittest.TestCase):
self.assertFalse(cond.locked())
-class SemaphoreTests(unittest.TestCase):
+class SemaphoreTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
def test_ctor_loop(self):
loop = mock.Mock()
@@ -696,12 +671,9 @@ class SemaphoreTests(unittest.TestCase):
self.assertIs(sem._loop, self.loop)
def test_ctor_noloop(self):
- try:
- asyncio.set_event_loop(self.loop)
- sem = asyncio.Semaphore()
- self.assertIs(sem._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ sem = asyncio.Semaphore()
+ self.assertIs(sem._loop, self.loop)
def test_initial_value_zero(self):
sem = asyncio.Semaphore(0, loop=self.loop)
diff --git a/Lib/test/test_asyncio/test_proactor_events.py b/Lib/test/test_asyncio/test_proactor_events.py
index 5bf24a4..ddfceae 100644
--- a/Lib/test/test_asyncio/test_proactor_events.py
+++ b/Lib/test/test_asyncio/test_proactor_events.py
@@ -12,10 +12,10 @@ from asyncio.proactor_events import _ProactorDuplexPipeTransport
from asyncio import test_utils
-class ProactorSocketTransportTests(unittest.TestCase):
+class ProactorSocketTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.proactor = mock.Mock()
self.loop._proactor = self.proactor
self.protocol = test_utils.make_test_protocol(asyncio.Protocol)
@@ -343,7 +343,7 @@ class ProactorSocketTransportTests(unittest.TestCase):
tr.close()
-class BaseProactorEventLoopTests(unittest.TestCase):
+class BaseProactorEventLoopTests(test_utils.TestCase):
def setUp(self):
self.sock = mock.Mock(socket.socket)
@@ -356,6 +356,7 @@ class BaseProactorEventLoopTests(unittest.TestCase):
return (self.ssock, self.csock)
self.loop = EventLoop(self.proactor)
+ self.set_event_loop(self.loop, cleanup=False)
@mock.patch.object(BaseProactorEventLoop, 'call_soon')
@mock.patch.object(BaseProactorEventLoop, '_socketpair')
diff --git a/Lib/test/test_asyncio/test_queues.py b/Lib/test/test_asyncio/test_queues.py
index f79fee2..32c90f4 100644
--- a/Lib/test/test_asyncio/test_queues.py
+++ b/Lib/test/test_asyncio/test_queues.py
@@ -7,14 +7,10 @@ import asyncio
from asyncio import test_utils
-class _QueueTestBase(unittest.TestCase):
+class _QueueTestBase(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.loop = self.new_test_loop()
class QueueBasicTests(_QueueTestBase):
@@ -32,8 +28,7 @@ class QueueBasicTests(_QueueTestBase):
self.assertAlmostEqual(0.2, when)
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
q = asyncio.Queue(loop=loop)
self.assertTrue(fn(q).startswith('<Queue'), fn(q))
@@ -80,12 +75,9 @@ class QueueBasicTests(_QueueTestBase):
self.assertIs(q._loop, self.loop)
def test_ctor_noloop(self):
- try:
- asyncio.set_event_loop(self.loop)
- q = asyncio.Queue()
- self.assertIs(q._loop, self.loop)
- finally:
- asyncio.set_event_loop(None)
+ asyncio.set_event_loop(self.loop)
+ q = asyncio.Queue()
+ self.assertIs(q._loop, self.loop)
def test_repr(self):
self._test_repr_or_str(repr, True)
@@ -126,8 +118,7 @@ class QueueBasicTests(_QueueTestBase):
self.assertAlmostEqual(0.02, when)
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
q = asyncio.Queue(maxsize=2, loop=loop)
self.assertEqual(2, q.maxsize)
@@ -194,8 +185,7 @@ class QueueGetTests(_QueueTestBase):
self.assertAlmostEqual(0.01, when)
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
q = asyncio.Queue(loop=loop)
started = asyncio.Event(loop=loop)
@@ -241,8 +231,7 @@ class QueueGetTests(_QueueTestBase):
self.assertAlmostEqual(0.061, when)
yield 0.05
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
q = asyncio.Queue(loop=loop)
@@ -302,8 +291,7 @@ class QueuePutTests(_QueueTestBase):
self.assertAlmostEqual(0.01, when)
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
q = asyncio.Queue(maxsize=1, loop=loop)
started = asyncio.Event(loop=loop)
@@ -339,6 +327,21 @@ class QueuePutTests(_QueueTestBase):
q.put_nowait(1)
self.assertRaises(asyncio.QueueFull, q.put_nowait, 2)
+ def test_float_maxsize(self):
+ q = asyncio.Queue(maxsize=1.3, loop=self.loop)
+ q.put_nowait(1)
+ q.put_nowait(2)
+ self.assertTrue(q.full())
+ self.assertRaises(asyncio.QueueFull, q.put_nowait, 3)
+
+ q = asyncio.Queue(maxsize=1.3, loop=self.loop)
+ @asyncio.coroutine
+ def queue_put():
+ yield from q.put(1)
+ yield from q.put(2)
+ self.assertTrue(q.full())
+ self.loop.run_until_complete(queue_put())
+
def test_put_cancelled(self):
q = asyncio.Queue(loop=self.loop)
diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py
index 36f6508..7c84f03 100644
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -37,11 +37,12 @@ def list_to_buffer(l=()):
return bytearray().join(l)
-class BaseSelectorEventLoopTests(unittest.TestCase):
+class BaseSelectorEventLoopTests(test_utils.TestCase):
def setUp(self):
selector = mock.Mock()
self.loop = TestBaseSelectorEventLoop(selector)
+ self.set_event_loop(self.loop, cleanup=False)
def test_make_socket_transport(self):
m = mock.Mock()
@@ -107,10 +108,7 @@ class BaseSelectorEventLoopTests(unittest.TestCase):
self.assertRaises(RuntimeError, self.loop.add_writer, fd, callback)
def test_close_no_selector(self):
- ssock = self.loop._ssock
- csock = self.loop._csock
- remove_reader = self.loop.remove_reader = mock.Mock()
-
+ self.loop.remove_reader = mock.Mock()
self.loop._selector.close()
self.loop._selector = None
self.loop.close()
@@ -597,10 +595,10 @@ class BaseSelectorEventLoopTests(unittest.TestCase):
self.loop.remove_writer.assert_called_with(1)
-class SelectorTransportTests(unittest.TestCase):
+class SelectorTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.Protocol)
self.sock = mock.Mock(socket.socket)
self.sock.fileno.return_value = 7
@@ -684,14 +682,14 @@ class SelectorTransportTests(unittest.TestCase):
self.assertEqual(2, sys.getrefcount(self.protocol),
pprint.pformat(gc.get_referrers(self.protocol)))
self.assertIsNone(tr._loop)
- self.assertEqual(2, sys.getrefcount(self.loop),
+ self.assertEqual(3, sys.getrefcount(self.loop),
pprint.pformat(gc.get_referrers(self.loop)))
-class SelectorSocketTransportTests(unittest.TestCase):
+class SelectorSocketTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.Protocol)
self.sock = mock.Mock(socket.socket)
self.sock_fd = self.sock.fileno.return_value = 7
@@ -1061,10 +1059,10 @@ class SelectorSocketTransportTests(unittest.TestCase):
@unittest.skipIf(ssl is None, 'No ssl module')
-class SelectorSslTransportTests(unittest.TestCase):
+class SelectorSslTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.Protocol)
self.sock = mock.Mock(socket.socket)
self.sock.fileno.return_value = 7
@@ -1396,10 +1394,10 @@ class SelectorSslWithoutSslTransportTests(unittest.TestCase):
_SelectorSslTransport(Mock(), Mock(), Mock(), Mock())
-class SelectorDatagramTransportTests(unittest.TestCase):
+class SelectorDatagramTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.DatagramProtocol)
self.sock = mock.Mock(spec_set=socket.socket)
self.sock.fileno.return_value = 7
diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
index 1ecc8eb..73a375a 100644
--- a/Lib/test/test_asyncio/test_streams.py
+++ b/Lib/test/test_asyncio/test_streams.py
@@ -15,13 +15,13 @@ import asyncio
from asyncio import test_utils
-class StreamReaderTests(unittest.TestCase):
+class StreamReaderTests(test_utils.TestCase):
DATA = b'line1\nline2\nline3\n'
def setUp(self):
self.loop = asyncio.new_event_loop()
- asyncio.set_event_loop(None)
+ self.set_event_loop(self.loop)
def tearDown(self):
# just in case if we have transport close callbacks
@@ -29,6 +29,7 @@ class StreamReaderTests(unittest.TestCase):
self.loop.close()
gc.collect()
+ super().tearDown()
@mock.patch('asyncio.streams.events')
def test_ctor_global_loop(self, m_events):
diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py
index 14fd17e..3b962bf 100644
--- a/Lib/test/test_asyncio/test_subprocess.py
+++ b/Lib/test/test_asyncio/test_subprocess.py
@@ -1,4 +1,5 @@
from asyncio import subprocess
+from asyncio import test_utils
import asyncio
import signal
import sys
@@ -151,21 +152,21 @@ if sys.platform != 'win32':
policy = asyncio.get_event_loop_policy()
policy.set_child_watcher(None)
self.loop.close()
- policy.set_event_loop(None)
+ super().tearDown()
class SubprocessSafeWatcherTests(SubprocessWatcherMixin,
- unittest.TestCase):
+ test_utils.TestCase):
Watcher = unix_events.SafeChildWatcher
class SubprocessFastWatcherTests(SubprocessWatcherMixin,
- unittest.TestCase):
+ test_utils.TestCase):
Watcher = unix_events.FastChildWatcher
else:
# Windows
- class SubprocessProactorTests(SubprocessMixin, unittest.TestCase):
+ class SubprocessProactorTests(SubprocessMixin, test_utils.TestCase):
def setUp(self):
policy = asyncio.get_event_loop_policy()
@@ -178,6 +179,7 @@ else:
policy = asyncio.get_event_loop_policy()
self.loop.close()
policy.set_event_loop(None)
+ super().tearDown()
if __name__ == '__main__':
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 92eb9da..e95c7dc 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1,16 +1,20 @@
"""Tests for tasks.py."""
-import gc
import os.path
+import sys
import types
import unittest
import weakref
from test.script_helper import assert_python_ok
import asyncio
+from asyncio import tasks
from asyncio import test_utils
+PY35 = (sys.version_info >= (3, 5))
+
+
@asyncio.coroutine
def coroutine_function():
pass
@@ -25,15 +29,10 @@ class Dummy:
pass
-class TaskTests(unittest.TestCase):
+class TaskTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
- gc.collect()
+ self.loop = self.new_test_loop()
def test_task_class(self):
@asyncio.coroutine
@@ -46,6 +45,7 @@ class TaskTests(unittest.TestCase):
self.assertIs(t._loop, self.loop)
loop = asyncio.new_event_loop()
+ self.set_event_loop(loop)
t = asyncio.Task(notmuch(), loop=loop)
self.assertIs(t._loop, loop)
loop.close()
@@ -61,6 +61,7 @@ class TaskTests(unittest.TestCase):
self.assertIs(t._loop, self.loop)
loop = asyncio.new_event_loop()
+ self.set_event_loop(loop)
t = asyncio.async(notmuch(), loop=loop)
self.assertIs(t._loop, loop)
loop.close()
@@ -76,6 +77,7 @@ class TaskTests(unittest.TestCase):
self.assertIs(f, f_orig)
loop = asyncio.new_event_loop()
+ self.set_event_loop(loop)
with self.assertRaises(ValueError):
f = asyncio.async(f_orig, loop=loop)
@@ -97,6 +99,7 @@ class TaskTests(unittest.TestCase):
self.assertIs(t, t_orig)
loop = asyncio.new_event_loop()
+ self.set_event_loop(loop)
with self.assertRaises(ValueError):
t = asyncio.async(t_orig, loop=loop)
@@ -116,10 +119,22 @@ class TaskTests(unittest.TestCase):
yield from []
return 'abc'
+ self.assertEqual(notmuch.__name__, 'notmuch')
+ if PY35:
+ self.assertEqual(notmuch.__qualname__,
+ 'TaskTests.test_task_repr.<locals>.notmuch')
+ self.assertEqual(notmuch.__module__, __name__)
+
filename, lineno = test_utils.get_function_source(notmuch)
src = "%s:%s" % (filename, lineno)
- t = asyncio.Task(notmuch(), loop=self.loop)
+ gen = notmuch()
+ self.assertEqual(gen.__name__, 'notmuch')
+ if PY35:
+ self.assertEqual(gen.__qualname__,
+ 'TaskTests.test_task_repr.<locals>.notmuch')
+
+ t = asyncio.Task(gen, loop=self.loop)
t.add_done_callback(Dummy())
self.assertEqual(repr(t),
'Task(<notmuch at %s>)<PENDING, [Dummy()]>' % src)
@@ -142,6 +157,12 @@ class TaskTests(unittest.TestCase):
def notmuch():
pass
+ self.assertEqual(notmuch.__name__, 'notmuch')
+ self.assertEqual(notmuch.__module__, __name__)
+ if PY35:
+ self.assertEqual(notmuch.__qualname__,
+ 'TaskTests.test_task_repr_custom.<locals>.notmuch')
+
class T(asyncio.Future):
def __repr__(self):
return 'T[]'
@@ -151,13 +172,26 @@ class TaskTests(unittest.TestCase):
return super().__repr__()
gen = notmuch()
+ if PY35 or tasks._DEBUG:
+ # On Python >= 3.5, generators now inherit the name of the
+ # function, as expected, and have a qualified name (__qualname__
+ # attribute). In debug mode, @coroutine decorator uses CoroWrapper
+ # which gets its name (__name__ attribute) from the wrapped
+ # coroutine function.
+ coro_name = 'notmuch'
+ else:
+ # On Python < 3.5, generators inherit the name of the code, not of
+ # the function. See: http://bugs.python.org/issue21205
+ coro_name = 'coro'
+ self.assertEqual(gen.__name__, coro_name)
+ if PY35:
+ self.assertEqual(gen.__qualname__,
+ 'TaskTests.test_task_repr_custom.<locals>.notmuch')
+
t = MyTask(gen, loop=self.loop)
filename = gen.gi_code.co_filename
lineno = gen.gi_frame.f_lineno
- # FIXME: check for the name "coro" instead of "notmuch" because
- # @asyncio.coroutine drops the name of the wrapped function:
- # http://bugs.python.org/issue21205
- self.assertEqual(repr(t), 'T[](<coro at %s:%s>)' % (filename, lineno))
+ self.assertEqual(repr(t), 'T[](<%s at %s:%s>)' % (coro_name, filename, lineno))
def test_task_basics(self):
@asyncio.coroutine
@@ -184,8 +218,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(10.0, when)
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
@asyncio.coroutine
def task():
@@ -310,7 +343,7 @@ class TaskTests(unittest.TestCase):
def test_cancel_current_task(self):
loop = asyncio.new_event_loop()
- self.addCleanup(loop.close)
+ self.set_event_loop(loop)
@asyncio.coroutine
def task():
@@ -338,8 +371,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.3, when)
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
x = 0
waiters = []
@@ -374,8 +406,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.1, when)
when = yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
foo_running = None
@@ -400,8 +431,7 @@ class TaskTests(unittest.TestCase):
self.assertEqual(foo_running, False)
def test_wait_for_blocking(self):
- loop = test_utils.TestLoop()
- self.addCleanup(loop.close)
+ loop = self.new_test_loop()
@asyncio.coroutine
def coro():
@@ -421,8 +451,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.01, when)
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
@asyncio.coroutine
def foo():
@@ -450,8 +479,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.15, when)
yield 0.15
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop)
b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop)
@@ -481,8 +509,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.015, when)
yield 0.015
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(0.01, loop=loop), loop=loop)
b = asyncio.Task(asyncio.sleep(0.015, loop=loop), loop=loop)
@@ -495,11 +522,8 @@ class TaskTests(unittest.TestCase):
return 42
asyncio.set_event_loop(loop)
- try:
- res = loop.run_until_complete(
- asyncio.Task(foo(), loop=loop))
- finally:
- asyncio.set_event_loop(None)
+ res = loop.run_until_complete(
+ asyncio.Task(foo(), loop=loop))
self.assertEqual(res, 42)
@@ -537,8 +561,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.1, when)
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop)
b = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop)
@@ -593,8 +616,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(10.0, when)
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
# first_exception, task already has exception
a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop)
@@ -627,8 +649,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.01, when)
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
# first_exception, exception during waiting
a = asyncio.Task(asyncio.sleep(10.0, loop=loop), loop=loop)
@@ -660,8 +681,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.15, when)
yield 0.15
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop)
@@ -697,8 +717,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.11, when)
yield 0.11
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop)
b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop)
@@ -728,8 +747,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.1, when)
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.Task(asyncio.sleep(0.1, loop=loop), loop=loop)
b = asyncio.Task(asyncio.sleep(0.15, loop=loop), loop=loop)
@@ -753,8 +771,7 @@ class TaskTests(unittest.TestCase):
yield 0.01
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
completed = set()
time_shifted = False
@@ -797,8 +814,7 @@ class TaskTests(unittest.TestCase):
yield 0
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.sleep(0.1, 'a', loop=loop)
b = asyncio.sleep(0.15, 'b', loop=loop)
@@ -834,8 +850,7 @@ class TaskTests(unittest.TestCase):
yield 0
yield 0.01
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.sleep(0.01, 'a', loop=loop)
@@ -854,8 +869,7 @@ class TaskTests(unittest.TestCase):
yield 0.05
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.sleep(0.05, 'a', loop=loop)
b = asyncio.sleep(0.10, 'b', loop=loop)
@@ -880,8 +894,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.05, when)
yield 0.05
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
a = asyncio.sleep(0.05, 'a', loop=loop)
b = asyncio.sleep(0.05, 'b', loop=loop)
@@ -922,8 +935,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(0.1, when)
yield 0.05
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleeper(dt, arg):
@@ -944,8 +956,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(10.0, when)
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
t = asyncio.Task(asyncio.sleep(10.0, 'yeah', loop=loop),
loop=loop)
@@ -976,8 +987,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(5000, when)
yield 0.1
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleep(dt):
@@ -1087,8 +1097,7 @@ class TaskTests(unittest.TestCase):
self.assertAlmostEqual(10.0, when)
yield 0
- loop = test_utils.TestLoop(gen)
- self.addCleanup(loop.close)
+ loop = self.new_test_loop(gen)
@asyncio.coroutine
def sleeper():
@@ -1500,12 +1509,9 @@ class TaskTests(unittest.TestCase):
class GatherTestsBase:
def setUp(self):
- self.one_loop = test_utils.TestLoop()
- self.other_loop = test_utils.TestLoop()
-
- def tearDown(self):
- self.one_loop.close()
- self.other_loop.close()
+ self.one_loop = self.new_test_loop()
+ self.other_loop = self.new_test_loop()
+ self.set_event_loop(self.one_loop, cleanup=False)
def _run_loop(self, loop):
while loop._ready:
@@ -1597,7 +1603,7 @@ class GatherTestsBase:
self.assertEqual(stdout.rstrip(), b'False')
-class FutureGatherTests(GatherTestsBase, unittest.TestCase):
+class FutureGatherTests(GatherTestsBase, test_utils.TestCase):
def wrap_futures(self, *futures):
return futures
@@ -1681,16 +1687,12 @@ class FutureGatherTests(GatherTestsBase, unittest.TestCase):
cb.assert_called_once_with(fut)
-class CoroutineGatherTests(GatherTestsBase, unittest.TestCase):
+class CoroutineGatherTests(GatherTestsBase, test_utils.TestCase):
def setUp(self):
super().setUp()
asyncio.set_event_loop(self.one_loop)
- def tearDown(self):
- asyncio.set_event_loop(None)
- super().tearDown()
-
def wrap_futures(self, *futures):
coros = []
for fut in futures:
diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
index cec7a11..89a4c10 100644
--- a/Lib/test/test_asyncio/test_unix_events.py
+++ b/Lib/test/test_asyncio/test_unix_events.py
@@ -29,14 +29,11 @@ MOCK_ANY = mock.ANY
@unittest.skipUnless(signal, 'Signals are not supported')
-class SelectorEventLoopSignalTests(unittest.TestCase):
+class SelectorEventLoopSignalTests(test_utils.TestCase):
def setUp(self):
self.loop = asyncio.SelectorEventLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.set_event_loop(self.loop)
def test_check_signal(self):
self.assertRaises(
@@ -208,14 +205,11 @@ class SelectorEventLoopSignalTests(unittest.TestCase):
@unittest.skipUnless(hasattr(socket, 'AF_UNIX'),
'UNIX Sockets are not supported')
-class SelectorEventLoopUnixSocketTests(unittest.TestCase):
+class SelectorEventLoopUnixSocketTests(test_utils.TestCase):
def setUp(self):
self.loop = asyncio.SelectorEventLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
+ self.set_event_loop(self.loop)
def test_create_unix_server_existing_path_sock(self):
with test_utils.unix_socket_path() as path:
@@ -304,10 +298,10 @@ class SelectorEventLoopUnixSocketTests(unittest.TestCase):
self.loop.run_until_complete(coro)
-class UnixReadPipeTransportTests(unittest.TestCase):
+class UnixReadPipeTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.Protocol)
self.pipe = mock.Mock(spec_set=io.RawIOBase)
self.pipe.fileno.return_value = 5
@@ -451,7 +445,7 @@ class UnixReadPipeTransportTests(unittest.TestCase):
self.assertEqual(2, sys.getrefcount(self.protocol),
pprint.pformat(gc.get_referrers(self.protocol)))
self.assertIsNone(tr._loop)
- self.assertEqual(4, sys.getrefcount(self.loop),
+ self.assertEqual(5, sys.getrefcount(self.loop),
pprint.pformat(gc.get_referrers(self.loop)))
def test__call_connection_lost_with_err(self):
@@ -468,14 +462,14 @@ class UnixReadPipeTransportTests(unittest.TestCase):
self.assertEqual(2, sys.getrefcount(self.protocol),
pprint.pformat(gc.get_referrers(self.protocol)))
self.assertIsNone(tr._loop)
- self.assertEqual(4, sys.getrefcount(self.loop),
+ self.assertEqual(5, sys.getrefcount(self.loop),
pprint.pformat(gc.get_referrers(self.loop)))
-class UnixWritePipeTransportTests(unittest.TestCase):
+class UnixWritePipeTransportTests(test_utils.TestCase):
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.protocol = test_utils.make_test_protocol(asyncio.BaseProtocol)
self.pipe = mock.Mock(spec_set=io.RawIOBase)
self.pipe.fileno.return_value = 5
@@ -737,7 +731,7 @@ class UnixWritePipeTransportTests(unittest.TestCase):
self.assertEqual(2, sys.getrefcount(self.protocol),
pprint.pformat(gc.get_referrers(self.protocol)))
self.assertIsNone(tr._loop)
- self.assertEqual(4, sys.getrefcount(self.loop),
+ self.assertEqual(5, sys.getrefcount(self.loop),
pprint.pformat(gc.get_referrers(self.loop)))
def test__call_connection_lost_with_err(self):
@@ -753,7 +747,7 @@ class UnixWritePipeTransportTests(unittest.TestCase):
self.assertEqual(2, sys.getrefcount(self.protocol),
pprint.pformat(gc.get_referrers(self.protocol)))
self.assertIsNone(tr._loop)
- self.assertEqual(4, sys.getrefcount(self.loop),
+ self.assertEqual(5, sys.getrefcount(self.loop),
pprint.pformat(gc.get_referrers(self.loop)))
def test_close(self):
@@ -834,7 +828,7 @@ class ChildWatcherTestsMixin:
ignore_warnings = mock.patch.object(log.logger, "warning")
def setUp(self):
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
self.running = False
self.zombies = {}
@@ -1392,7 +1386,7 @@ class ChildWatcherTestsMixin:
# attach a new loop
old_loop = self.loop
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
patch = mock.patch.object
with patch(old_loop, "remove_signal_handler") as m_old_remove, \
@@ -1447,7 +1441,7 @@ class ChildWatcherTestsMixin:
self.assertFalse(callback3.called)
# attach a new loop
- self.loop = test_utils.TestLoop()
+ self.loop = self.new_test_loop()
with mock.patch.object(
self.loop, "add_signal_handler") as m_add_signal_handler:
@@ -1505,12 +1499,12 @@ class ChildWatcherTestsMixin:
self.assertFalse(self.watcher._zombies)
-class SafeChildWatcherTests (ChildWatcherTestsMixin, unittest.TestCase):
+class SafeChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase):
def create_watcher(self):
return asyncio.SafeChildWatcher()
-class FastChildWatcherTests (ChildWatcherTestsMixin, unittest.TestCase):
+class FastChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase):
def create_watcher(self):
return asyncio.FastChildWatcher()
diff --git a/Lib/test/test_asyncio/test_windows_events.py b/Lib/test/test_asyncio/test_windows_events.py
index f652258..4ab56e6 100644
--- a/Lib/test/test_asyncio/test_windows_events.py
+++ b/Lib/test/test_asyncio/test_windows_events.py
@@ -9,6 +9,7 @@ import _winapi
import asyncio
from asyncio import _overlapped
+from asyncio import test_utils
from asyncio import windows_events
@@ -26,15 +27,11 @@ class UpperProto(asyncio.Protocol):
self.trans.close()
-class ProactorTests(unittest.TestCase):
+class ProactorTests(test_utils.TestCase):
def setUp(self):
self.loop = asyncio.ProactorEventLoop()
- asyncio.set_event_loop(None)
-
- def tearDown(self):
- self.loop.close()
- self.loop = None
+ self.set_event_loop(self.loop)
def test_close(self):
a, b = self.loop._socketpair()
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index 7bff1d2..787181c 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -507,6 +507,11 @@ class TestBasic(unittest.TestCase):
for s in ('abcd', range(2000)):
self.assertEqual(list(reversed(deque(s))), list(reversed(s)))
+ def test_reversed_new(self):
+ klass = type(reversed(deque()))
+ for s in ('abcd', range(2000)):
+ self.assertEqual(list(klass(deque(s))), list(reversed(s)))
+
def test_gc_doesnt_blowup(self):
import gc
# This used to assert-fail in deque_traverse() under a debug
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index e65edb2..634ba7e 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1149,7 +1149,7 @@ order (MRO) for bases """
except (TypeError, UnicodeEncodeError):
pass
else:
- raise TestFailed("[chr(128)] slots not caught")
+ self.fail("[chr(128)] slots not caught")
# Test leaks
class Counted(object):
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index b8ef632..f1f8063 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -1528,9 +1528,7 @@ class TestStdLib(unittest.TestCase):
helper = pydoc.Helper(output=output)
helper(self.Color)
result = output.getvalue().strip()
- if result != expected_text:
- print_diffs(expected_text, result)
- self.fail("outputs are not equal, see diff above")
+ self.assertEqual(result, expected_text)
def test_inspect_getmembers(self):
values = dict((
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 91afe47..3882f4c 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -50,6 +50,45 @@ class FinalizationTest(unittest.TestCase):
self.assertEqual(gc.garbage, old_garbage)
+class GeneratorTest(unittest.TestCase):
+
+ def test_name(self):
+ def func():
+ yield 1
+
+ # check generator names
+ gen = func()
+ self.assertEqual(gen.__name__, "func")
+ self.assertEqual(gen.__qualname__,
+ "GeneratorTest.test_name.<locals>.func")
+
+ # modify generator names
+ gen.__name__ = "name"
+ gen.__qualname__ = "qualname"
+ self.assertEqual(gen.__name__, "name")
+ self.assertEqual(gen.__qualname__, "qualname")
+
+ # generator names must be a string and cannot be deleted
+ self.assertRaises(TypeError, setattr, gen, '__name__', 123)
+ self.assertRaises(TypeError, setattr, gen, '__qualname__', 123)
+ self.assertRaises(TypeError, delattr, gen, '__name__')
+ self.assertRaises(TypeError, delattr, gen, '__qualname__')
+
+ # modify names of the function creating the generator
+ func.__qualname__ = "func_qualname"
+ func.__name__ = "func_name"
+ gen = func()
+ self.assertEqual(gen.__name__, "func_name")
+ self.assertEqual(gen.__qualname__, "func_qualname")
+
+ # unnamed generator
+ gen = (x for x in range(10))
+ self.assertEqual(gen.__name__,
+ "<genexpr>")
+ self.assertEqual(gen.__qualname__,
+ "GeneratorTest.test_name.<locals>.<genexpr>")
+
+
tutorial_tests = """
Let's try a simple generator:
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index b363f99..7069fb9 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -390,6 +390,31 @@ class GrammarTests(unittest.TestCase):
check_syntax_error(self, "x + 1 = 1")
check_syntax_error(self, "a + 1 = b + 2")
+ # Check the heuristic for print & exec covers significant cases
+ # As well as placing some limits on false positives
+ def test_former_statements_refer_to_builtins(self):
+ keywords = "print", "exec"
+ # Cases where we want the custom error
+ cases = [
+ "{} foo",
+ "{} {{1:foo}}",
+ "if 1: {} foo",
+ "if 1: {} {{1:foo}}",
+ "if 1:\n {} foo",
+ "if 1:\n {} {{1:foo}}",
+ ]
+ for keyword in keywords:
+ custom_msg = "call to '{}'".format(keyword)
+ for case in cases:
+ source = case.format(keyword)
+ with self.subTest(source=source):
+ with self.assertRaisesRegex(SyntaxError, custom_msg):
+ exec(source)
+ source = source.replace("foo", "(foo.)")
+ with self.subTest(source=source):
+ with self.assertRaisesRegex(SyntaxError, "invalid syntax"):
+ exec(source)
+
def test_del_stmt(self):
# 'del' exprlist
abc = [1,2,3]
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index 685797a..0dcd8c5 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -13,8 +13,8 @@ c_heapq = support.import_fresh_module('heapq', fresh=['_heapq'])
# _heapq.nlargest/nsmallest are saved in heapq._nlargest/_smallest when
# _heapq is imported, so check them there
-func_names = ['heapify', 'heappop', 'heappush', 'heappushpop',
- 'heapreplace', '_heapreplace_max']
+func_names = ['heapify', 'heappop', 'heappush', 'heappushpop', 'heapreplace',
+ '_heappop_max', '_heapreplace_max', '_heapify_max']
class TestModules(TestCase):
def test_py_functions(self):
diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
index 15694af..493fade 100644
--- a/Lib/test/test_httpservers.py
+++ b/Lib/test/test_httpservers.py
@@ -485,6 +485,11 @@ class CGIHTTPServerTestCase(BaseTestCase):
(res.read(), res.getheader('Content-type'), res.status))
self.assertEqual(os.environ['SERVER_SOFTWARE'], signature)
+ def test_urlquote_decoding_in_cgi_check(self):
+ res = self.request('/cgi-bin%2ffile1.py')
+ self.assertEqual((b'Hello World' + self.linesep, 'text/html', 200),
+ (res.read(), res.getheader('Content-type'), res.status))
+
class SocketlessRequestHandler(SimpleHTTPRequestHandler):
def __init__(self):
diff --git a/Lib/test/test_minidom.py b/Lib/test/test_minidom.py
index 5ab4bfe..2489ff7 100644
--- a/Lib/test/test_minidom.py
+++ b/Lib/test/test_minidom.py
@@ -1531,6 +1531,13 @@ class MinidomTest(unittest.TestCase):
num_children_after = len(doc.childNodes)
self.assertTrue(num_children_after == num_children_before - 1)
+ def testProcessingInstructionNameError(self):
+ # wrong variable in .nodeValue property will
+ # lead to "NameError: name 'data' is not defined"
+ doc = parse(tstfile)
+ pi = doc.createProcessingInstruction("y", "z")
+ pi.nodeValue = "crash"
+
def test_main():
run_unittest(MinidomTest)
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 7d5ee69..f559841 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -530,6 +530,28 @@ class StatAttributeTests(unittest.TestCase):
os.stat(r)
self.assertEqual(ctx.exception.errno, errno.EBADF)
+ def check_file_attributes(self, result):
+ self.assertTrue(hasattr(result, 'st_file_attributes'))
+ self.assertTrue(isinstance(result.st_file_attributes, int))
+ self.assertTrue(0 <= result.st_file_attributes <= 0xFFFFFFFF)
+
+ @unittest.skipUnless(sys.platform == "win32",
+ "st_file_attributes is Win32 specific")
+ def test_file_attributes(self):
+ # test file st_file_attributes (FILE_ATTRIBUTE_DIRECTORY not set)
+ result = os.stat(self.fname)
+ self.check_file_attributes(result)
+ self.assertEqual(
+ result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
+ 0)
+
+ # test directory st_file_attributes (FILE_ATTRIBUTE_DIRECTORY set)
+ result = os.stat(support.TESTFN)
+ self.check_file_attributes(result)
+ self.assertEqual(
+ result.st_file_attributes & stat.FILE_ATTRIBUTE_DIRECTORY,
+ stat.FILE_ATTRIBUTE_DIRECTORY)
+
from test import mapping_tests
class EnvironTests(mapping_tests.BasicTestMappingProtocol):
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index 542b433..3bce66e 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -402,6 +402,7 @@ class PydocDocTest(unittest.TestCase):
"Docstrings are omitted with -O2 and above")
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
+ @requires_docstrings
def test_html_doc(self):
result, doc_loc = get_pydoc_html(pydoc_mod)
mod_file = inspect.getabsfile(pydoc_mod)
@@ -421,6 +422,7 @@ class PydocDocTest(unittest.TestCase):
"Docstrings are omitted with -O2 and above")
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
+ @requires_docstrings
def test_text_doc(self):
result, doc_loc = get_pydoc_text(pydoc_mod)
expected_text = expected_text_pattern % (
@@ -495,6 +497,7 @@ class PydocDocTest(unittest.TestCase):
'Docstrings are omitted with -O2 and above')
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __locals__ unexpectedly')
+ @requires_docstrings
def test_help_output_redirect(self):
# issue 940286, if output is set in Helper, then all output from
# Helper.help should be redirected
@@ -746,7 +749,7 @@ class TestDescriptions(unittest.TestCase):
try:
pydoc.render_doc(name)
except ImportError:
- self.fail('finding the doc of {!r} failed'.format(o))
+ self.fail('finding the doc of {!r} failed'.format(name))
for name in ('notbuiltins', 'strrr', 'strr.translate',
'str.trrrranslate', 'builtins.strrr',
diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py
index af6ced4..f1a5938 100644
--- a/Lib/test/test_stat.py
+++ b/Lib/test/test_stat.py
@@ -1,5 +1,6 @@
import unittest
import os
+import sys
from test.support import TESTFN, import_fresh_module
c_stat = import_fresh_module('stat', fresh=['_stat'])
@@ -52,6 +53,26 @@ class TestFilemode:
'S_IWOTH': 0o002,
'S_IXOTH': 0o001}
+ # defined by the Windows API documentation
+ file_attributes = {
+ 'FILE_ATTRIBUTE_ARCHIVE': 32,
+ 'FILE_ATTRIBUTE_COMPRESSED': 2048,
+ 'FILE_ATTRIBUTE_DEVICE': 64,
+ 'FILE_ATTRIBUTE_DIRECTORY': 16,
+ 'FILE_ATTRIBUTE_ENCRYPTED': 16384,
+ 'FILE_ATTRIBUTE_HIDDEN': 2,
+ 'FILE_ATTRIBUTE_INTEGRITY_STREAM': 32768,
+ 'FILE_ATTRIBUTE_NORMAL': 128,
+ 'FILE_ATTRIBUTE_NOT_CONTENT_INDEXED': 8192,
+ 'FILE_ATTRIBUTE_NO_SCRUB_DATA': 131072,
+ 'FILE_ATTRIBUTE_OFFLINE': 4096,
+ 'FILE_ATTRIBUTE_READONLY': 1,
+ 'FILE_ATTRIBUTE_REPARSE_POINT': 1024,
+ 'FILE_ATTRIBUTE_SPARSE_FILE': 512,
+ 'FILE_ATTRIBUTE_SYSTEM': 4,
+ 'FILE_ATTRIBUTE_TEMPORARY': 256,
+ 'FILE_ATTRIBUTE_VIRTUAL': 65536}
+
def setUp(self):
try:
os.remove(TESTFN)
@@ -185,6 +206,14 @@ class TestFilemode:
self.assertTrue(callable(func))
self.assertEqual(func(0), 0)
+ @unittest.skipUnless(sys.platform == "win32",
+ "FILE_ATTRIBUTE_* constants are Win32 specific")
+ def test_file_attribute_constants(self):
+ for key, value in sorted(self.file_attributes.items()):
+ self.assertTrue(hasattr(self.statmod, key), key)
+ modvalue = getattr(self.statmod, key)
+ self.assertEqual(value, modvalue, key)
+
class TestFilemodeCStat(TestFilemode, unittest.TestCase):
statmod = c_stat
diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py
index 720025a..d0ab718 100644
--- a/Lib/test/test_subprocess.py
+++ b/Lib/test/test_subprocess.py
@@ -1934,6 +1934,20 @@ class POSIXProcessTestCase(BaseTestCase):
"""Confirm that issue21618 is fixed (may fail under valgrind)."""
fd_status = support.findfile("fd_status.py", subdir="subprocessdata")
+ # This launches the meat of the test in a child process to
+ # avoid messing with the larger unittest processes maximum
+ # number of file descriptors.
+ # This process launches:
+ # +--> Process that lowers its RLIMIT_NOFILE aftr setting up
+ # a bunch of high open fds above the new lower rlimit.
+ # Those are reported via stdout before launching a new
+ # process with close_fds=False to run the actual test:
+ # +--> The TEST: This one launches a fd_status.py
+ # subprocess with close_fds=True so we can find out if
+ # any of the fds above the lowered rlimit are still open.
+ p = subprocess.Popen([sys.executable, '-c', textwrap.dedent(
+ '''
+ import os, resource, subprocess, sys, textwrap
open_fds = set()
# Add a bunch more fds to pass down.
for _ in range(40):
@@ -1949,12 +1963,15 @@ class POSIXProcessTestCase(BaseTestCase):
open_fds.remove(fd)
for fd in open_fds:
- self.addCleanup(os.close, fd)
+ #self.addCleanup(os.close, fd)
os.set_inheritable(fd, True)
max_fd_open = max(open_fds)
- import resource
+ # Communicate the open_fds to the parent unittest.TestCase process.
+ print(','.join(map(str, sorted(open_fds))))
+ sys.stdout.flush()
+
rlim_cur, rlim_max = resource.getrlimit(resource.RLIMIT_NOFILE)
try:
# 29 is lower than the highest fds we are leaving open.
@@ -1965,22 +1982,27 @@ class POSIXProcessTestCase(BaseTestCase):
# An explicit list of fds to check is passed to fd_status.py as
# letting fd_status rely on its default logic would miss the
# fds above rlim_cur as it normally only checks up to that limit.
- p = subprocess.Popen(
+ subprocess.Popen(
[sys.executable, '-c',
textwrap.dedent("""
import subprocess, sys
- subprocess.Popen([sys.executable, {fd_status!r}] +
+ subprocess.Popen([sys.executable, %r] +
[str(x) for x in range({max_fd})],
close_fds=True).wait()
- """.format(fd_status=fd_status, max_fd=max_fd_open+1))],
- stdout=subprocess.PIPE, close_fds=False)
+ """.format(max_fd=max_fd_open+1))],
+ close_fds=False).wait()
finally:
resource.setrlimit(resource.RLIMIT_NOFILE, (rlim_cur, rlim_max))
+ ''' % fd_status)], stdout=subprocess.PIPE)
output, unused_stderr = p.communicate()
- remaining_fds = set(map(int, output.strip().split(b',')))
+ output_lines = output.splitlines()
+ self.assertEqual(len(output_lines), 2,
+ msg="expected exactly two lines of output:\n%r" % output)
+ opened_fds = set(map(int, output_lines[0].strip().split(b',')))
+ remaining_fds = set(map(int, output_lines[1].strip().split(b',')))
- self.assertFalse(remaining_fds & open_fds,
+ self.assertFalse(remaining_fds & opened_fds,
msg="Some fds were left open.")
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 4eadd4b..854e786 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -885,7 +885,7 @@ class SizeofTest(unittest.TestCase):
check(bar, size('PP'))
# generator
def get_gen(): yield 1
- check(get_gen(), size('Pb2P'))
+ check(get_gen(), size('Pb2PPP'))
# iterator
check(iter('abc'), size('lP'))
# callable-iterator
diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py
index 6f71631..c379a33 100644
--- a/Lib/xml/dom/minidom.py
+++ b/Lib/xml/dom/minidom.py
@@ -976,7 +976,7 @@ class ProcessingInstruction(Childless, Node):
def _get_nodeValue(self):
return self.data
def _set_nodeValue(self, value):
- self.data = data
+ self.data = value
nodeValue = property(_get_nodeValue, _set_nodeValue)
# nodeName is an alias for target