summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/conversion.rst4
-rw-r--r--Doc/c-api/exceptions.rst10
-rw-r--r--Doc/c-api/import.rst4
-rw-r--r--Doc/c-api/init.rst2
-rw-r--r--Doc/c-api/mapping.rst2
-rw-r--r--Doc/c-api/marshal.rst2
-rw-r--r--Doc/c-api/sys.rst4
-rw-r--r--Doc/c-api/unicode.rst2
-rw-r--r--Doc/extending/extending.rst6
-rw-r--r--Doc/faq/extending.rst4
-rw-r--r--Doc/library/asyncio-eventloop.rst16
-rw-r--r--Doc/library/urllib.parse.rst16
-rw-r--r--Include/ceval.h2
-rw-r--r--Include/traceback.h2
-rw-r--r--Lib/asyncio/coroutines.py100
-rw-r--r--Lib/contextlib.py6
-rw-r--r--Lib/test/test_asyncio/test_tasks.py3
-rw-r--r--Lib/test/test_cmath.py51
-rw-r--r--Lib/test/test_contextlib.py8
-rw-r--r--Lib/test/test_urlparse.py41
-rw-r--r--Lib/test/test_with.py6
-rw-r--r--Lib/tkinter/test/test_tkinter/test_font.py11
-rw-r--r--Misc/NEWS7
-rw-r--r--Modules/_pickle.c26
-rw-r--r--Modules/_testcapimodule.c13
-rw-r--r--Modules/cmathmodule.c3
-rw-r--r--Python/ceval.c2
-rw-r--r--Python/traceback.c2
28 files changed, 243 insertions, 112 deletions
diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst
index 9578f984fd..9566d9d792 100644
--- a/Doc/c-api/conversion.rst
+++ b/Doc/c-api/conversion.rst
@@ -119,13 +119,13 @@ The following functions provide locale-independent string to number conversions.
.. versionadded:: 3.1
-.. c:function:: int PyOS_stricmp(char *s1, char *s2)
+.. c:function:: int PyOS_stricmp(const char *s1, const char *s2)
Case insensitive comparison of strings. The function works almost
identically to :c:func:`strcmp` except that it ignores the case.
-.. c:function:: int PyOS_strnicmp(char *s1, char *s2, Py_ssize_t size)
+.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size)
Case insensitive comparison of strings. The function works almost
identically to :c:func:`strncmp` except that it ignores the case.
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 66b7752661..c2df767998 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -324,7 +324,7 @@ in various ways. There is a separate error indicator for each thread.
.. versionadded:: 3.4
-.. c:function:: void PyErr_SyntaxLocationEx(char *filename, int lineno, int col_offset)
+.. c:function:: void PyErr_SyntaxLocationEx(const char *filename, int lineno, int col_offset)
Like :c:func:`PyErr_SyntaxLocationObject`, but *filename* is a byte string
decoded from the filesystem encoding (:func:`os.fsdecode`).
@@ -332,7 +332,7 @@ in various ways. There is a separate error indicator for each thread.
.. versionadded:: 3.2
-.. c:function:: void PyErr_SyntaxLocation(char *filename, int lineno)
+.. c:function:: void PyErr_SyntaxLocation(const char *filename, int lineno)
Like :c:func:`PyErr_SyntaxLocationEx`, but the col_offset parameter is
omitted.
@@ -451,7 +451,7 @@ in various ways. There is a separate error indicator for each thread.
only be called from the main thread.
-.. c:function:: PyObject* PyErr_NewException(char *name, PyObject *base, PyObject *dict)
+.. c:function:: PyObject* PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
This utility function creates and returns a new exception class. The *name*
argument must be the name of the new exception, a C string of the form
@@ -466,7 +466,7 @@ in various ways. There is a separate error indicator for each thread.
argument can be used to specify a dictionary of class variables and methods.
-.. c:function:: PyObject* PyErr_NewExceptionWithDoc(char *name, char *doc, PyObject *base, PyObject *dict)
+.. c:function:: PyObject* PyErr_NewExceptionWithDoc(const char *name, const char *doc, PyObject *base, PyObject *dict)
Same as :c:func:`PyErr_NewException`, except that the new exception class can
easily be given a docstring: If *doc* is non-*NULL*, it will be used as the
@@ -621,7 +621,7 @@ level, both in the core and in extension modules. They are needed if the
recursive code does not necessarily invoke Python code (which tracks its
recursion depth automatically).
-.. c:function:: int Py_EnterRecursiveCall(char *where)
+.. c:function:: int Py_EnterRecursiveCall(const char *where)
Marks a point where a recursive C-level call is about to be performed.
diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
index 3641fc69b1..60865f456f 100644
--- a/Doc/c-api/import.rst
+++ b/Doc/c-api/import.rst
@@ -39,7 +39,7 @@ Importing Modules
behaviour isn't needed anymore.
-.. c:function:: PyObject* PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
+.. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
.. index:: builtin: __import__
@@ -70,7 +70,7 @@ Importing Modules
.. versionadded:: 3.3
-.. c:function:: PyObject* PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level)
+.. c:function:: PyObject* PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist, int level)
Similar to :c:func:`PyImport_ImportModuleLevelObject`, but the name is an
UTF-8 encoded string instead of a Unicode object.
diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
index 4d358ca757..4bb50649ef 100644
--- a/Doc/c-api/init.rst
+++ b/Doc/c-api/init.rst
@@ -86,7 +86,7 @@ Process-wide parameters
=======================
-.. c:function:: int Py_SetStandardStreamEncoding(char *encoding, char *errors)
+.. c:function:: int Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
.. index::
single: Py_Initialize()
diff --git a/Doc/c-api/mapping.rst b/Doc/c-api/mapping.rst
index 2803fd044e..e34104708c 100644
--- a/Doc/c-api/mapping.rst
+++ b/Doc/c-api/mapping.rst
@@ -34,7 +34,7 @@ Mapping Protocol
failure. This is equivalent to the Python statement ``del o[key]``.
-.. c:function:: int PyMapping_HasKeyString(PyObject *o, char *key)
+.. c:function:: int PyMapping_HasKeyString(PyObject *o, const char *key)
On success, return ``1`` if the mapping object has the key *key* and ``0``
otherwise. This is equivalent to the Python expression ``key in o``.
diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst
index 9ea0aaa54f..a6d0f4688d 100644
--- a/Doc/c-api/marshal.rst
+++ b/Doc/c-api/marshal.rst
@@ -88,7 +88,7 @@ written using these routines?
:exc:`TypeError`) and returns *NULL*.
-.. c:function:: PyObject* PyMarshal_ReadObjectFromString(char *string, Py_ssize_t len)
+.. c:function:: PyObject* PyMarshal_ReadObjectFromString(const char *string, Py_ssize_t len)
Return a Python object from the data stream in a character buffer
containing *len* bytes pointed to by *string*.
diff --git a/Doc/c-api/sys.rst b/Doc/c-api/sys.rst
index 9760dca2df..7cead07081 100644
--- a/Doc/c-api/sys.rst
+++ b/Doc/c-api/sys.rst
@@ -56,12 +56,12 @@ These are utility functions that make functionality from the :mod:`sys` module
accessible to C code. They all work with the current interpreter thread's
:mod:`sys` module's dict, which is contained in the internal thread state structure.
-.. c:function:: PyObject *PySys_GetObject(char *name)
+.. c:function:: PyObject *PySys_GetObject(const char *name)
Return the object *name* from the :mod:`sys` module or *NULL* if it does
not exist, without setting an exception.
-.. c:function:: int PySys_SetObject(char *name, PyObject *v)
+.. c:function:: int PySys_SetObject(const char *name, PyObject *v)
Set *name* in the :mod:`sys` module to *v* unless *v* is *NULL*, in which
case *name* is deleted from the sys module. Returns ``0`` on success, ``-1``
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 65d24c4083..f7e99d6d99 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -1628,7 +1628,7 @@ They all return *NULL* or ``-1`` if an exception occurs.
respectively.
-.. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, char *string)
+.. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, const char *string)
Compare a unicode object, *uni*, with *string* and return -1, 0, 1 for less
than, equal, and greater than, respectively. It is best to pass only
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index c10efa976d..ba6bfa70a2 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -590,7 +590,7 @@ Extracting Parameters in Extension Functions
The :c:func:`PyArg_ParseTuple` function is declared as follows::
- int PyArg_ParseTuple(PyObject *arg, char *format, ...);
+ int PyArg_ParseTuple(PyObject *arg, const char *format, ...);
The *arg* argument must be a tuple object containing an argument list passed
from Python to a C function. The *format* argument must be a format string,
@@ -683,7 +683,7 @@ Keyword Parameters for Extension Functions
The :c:func:`PyArg_ParseTupleAndKeywords` function is declared as follows::
int PyArg_ParseTupleAndKeywords(PyObject *arg, PyObject *kwdict,
- char *format, char *kwlist[], ...);
+ const char *format, char *kwlist[], ...);
The *arg* and *format* parameters are identical to those of the
:c:func:`PyArg_ParseTuple` function. The *kwdict* parameter is the dictionary of
@@ -760,7 +760,7 @@ Building Arbitrary Values
This function is the counterpart to :c:func:`PyArg_ParseTuple`. It is declared
as follows::
- PyObject *Py_BuildValue(char *format, ...);
+ PyObject *Py_BuildValue(const char *format, ...);
It recognizes a set of format units similar to the ones recognized by
:c:func:`PyArg_ParseTuple`, but the arguments (which are input to the function,
diff --git a/Doc/faq/extending.rst b/Doc/faq/extending.rst
index 02bba591cf..fea5a57601 100644
--- a/Doc/faq/extending.rst
+++ b/Doc/faq/extending.rst
@@ -115,8 +115,8 @@ call, a format string like that used with :c:func:`Py_BuildValue`, and the
argument values::
PyObject *
- PyObject_CallMethod(PyObject *object, char *method_name,
- char *arg_format, ...);
+ PyObject_CallMethod(PyObject *object, const char *method_name,
+ const char *arg_format, ...);
This works for any object that has methods -- whether built-in or user-defined.
You are responsible for eventually :c:func:`Py_DECREF`\ 'ing the return value.
diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
index e1a9da1409..33d3148369 100644
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -97,7 +97,8 @@ keywords to your callback, use :func:`functools.partial`. For example,
Any positional arguments after the callback will be passed to the
callback when it is called.
- An instance of :class:`asyncio.Handle` is returned.
+ An instance of :class:`asyncio.Handle` is returned, which can be
+ used to cancel the callback.
:ref:`Use functools.partial to pass keywords to the callback
<asyncio-pass-keywords>`.
@@ -130,7 +131,8 @@ a different clock than :func:`time.time`.
Arrange for the *callback* to be called after the given *delay*
seconds (either an int or float).
- An instance of :class:`asyncio.Handle` is returned.
+ An instance of :class:`asyncio.Handle` is returned, which can be
+ used to cancel the callback.
*callback* will be called exactly once per call to :meth:`call_later`.
If two callbacks are scheduled for exactly the same time, it is
@@ -151,6 +153,9 @@ a different clock than :func:`time.time`.
This method's behavior is the same as :meth:`call_later`.
+ An instance of :class:`asyncio.Handle` is returned, which can be
+ used to cancel the callback.
+
:ref:`Use functools.partial to pass keywords to the callback
<asyncio-pass-keywords>`.
@@ -164,8 +169,8 @@ a different clock than :func:`time.time`.
The :func:`asyncio.sleep` function.
-Coroutines
-----------
+Tasks
+-----
.. method:: BaseEventLoop.create_task(coro)
@@ -704,7 +709,8 @@ Handle
.. method:: cancel()
- Cancel the call.
+ Cancel the call. If the callback is already canceled or executed,
+ this method has no effect.
Event loop examples
diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst
index 154a521fa1..fbbabcadf9 100644
--- a/Doc/library/urllib.parse.rst
+++ b/Doc/library/urllib.parse.rst
@@ -76,13 +76,15 @@ or on combining URL components into a URL string.
ParseResult(scheme='', netloc='', path='help/Python.html', params='',
query='', fragment='')
- If the *scheme* argument is specified, it gives the default addressing
- scheme, to be used only if the URL does not specify one. The default value for
- this argument is the empty string.
+ The *scheme* argument gives the default addressing scheme, to be
+ used only if the URL does not specify one. It should be the same type
+ (text or bytes) as *urlstring*, except that the default value ``''`` is
+ always allowed, and is automatically converted to ``b''`` if appropriate.
If the *allow_fragments* argument is false, fragment identifiers are not
- recognized and parsed as part of the preceding component. The default value
- for this argument is :const:`True`.
+ recognized. Instead, they are parsed as part of the path, parameters
+ or query component, and :attr:`fragment` is set to the empty string in
+ the return value.
The return value is actually an instance of a subclass of :class:`tuple`. This
class has the following additional read-only convenience attributes:
@@ -90,7 +92,7 @@ or on combining URL components into a URL string.
+------------------+-------+--------------------------+----------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+==========================+======================+
- | :attr:`scheme` | 0 | URL scheme specifier | empty string |
+ | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter |
+------------------+-------+--------------------------+----------------------+
| :attr:`netloc` | 1 | Network location part | empty string |
+------------------+-------+--------------------------+----------------------+
@@ -206,7 +208,7 @@ or on combining URL components into a URL string.
+------------------+-------+-------------------------+----------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+======================+
- | :attr:`scheme` | 0 | URL scheme specifier | empty string |
+ | :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter |
+------------------+-------+-------------------------+----------------------+
| :attr:`netloc` | 1 | Network location part | empty string |
+------------------+-------+-------------------------+----------------------+
diff --git a/Include/ceval.h b/Include/ceval.h
index 6811367d76..4937f2c431 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -77,7 +77,7 @@ PyAPI_FUNC(int) Py_GetRecursionLimit(void);
do{ if(_Py_MakeEndRecCheck(PyThreadState_GET()->recursion_depth)) \
PyThreadState_GET()->overflowed = 0; \
} while(0)
-PyAPI_FUNC(int) _Py_CheckRecursiveCall(char *where);
+PyAPI_FUNC(int) _Py_CheckRecursiveCall(const char *where);
PyAPI_DATA(int) _Py_CheckRecursionLimit;
#ifdef USE_STACKCHECK
diff --git a/Include/traceback.h b/Include/traceback.h
index 12d467a08d..891000c8fe 100644
--- a/Include/traceback.h
+++ b/Include/traceback.h
@@ -24,7 +24,7 @@ PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int);
-PyAPI_FUNC(void) _PyTraceback_Add(char *, char *, int);
+PyAPI_FUNC(void) _PyTraceback_Add(const char *, const char *, int);
#endif
/* Reveal traceback type so we can typecheck traceback objects */
diff --git a/Lib/asyncio/coroutines.py b/Lib/asyncio/coroutines.py
index edb6806210..a70eb1dd91 100644
--- a/Lib/asyncio/coroutines.py
+++ b/Lib/asyncio/coroutines.py
@@ -34,30 +34,20 @@ _DEBUG = (not sys.flags.ignore_environment
try:
- types.coroutine
+ _types_coroutine = types.coroutine
except AttributeError:
- native_coroutine_support = False
-else:
- native_coroutine_support = True
+ _types_coroutine = None
try:
- _iscoroutinefunction = inspect.iscoroutinefunction
+ _inspect_iscoroutinefunction = inspect.iscoroutinefunction
except AttributeError:
- _iscoroutinefunction = lambda func: False
+ _inspect_iscoroutinefunction = lambda func: False
try:
- inspect.CO_COROUTINE
-except AttributeError:
- _is_native_coro_code = lambda code: False
-else:
- _is_native_coro_code = lambda code: (code.co_flags &
- inspect.CO_COROUTINE)
-
-try:
- from collections.abc import Coroutine as CoroutineABC, \
- Awaitable as AwaitableABC
+ from collections.abc import Coroutine as _CoroutineABC, \
+ Awaitable as _AwaitableABC
except ImportError:
- CoroutineABC = AwaitableABC = None
+ _CoroutineABC = _AwaitableABC = None
# Check for CPython issue #21209
@@ -89,10 +79,7 @@ def debug_wrapper(gen):
# We only wrap here coroutines defined via 'async def' syntax.
# Generator-based coroutines are wrapped in @coroutine
# decorator.
- if _is_native_coro_code(gen.gi_code):
- return CoroWrapper(gen, None)
- else:
- return gen
+ return CoroWrapper(gen, None)
class CoroWrapper:
@@ -116,9 +103,6 @@ class CoroWrapper:
def __iter__(self):
return self
- if _PY35:
- __await__ = __iter__ # make compatible with 'await' expression
-
def __next__(self):
return self.gen.send(None)
@@ -156,10 +140,28 @@ class CoroWrapper:
def gi_code(self):
return self.gen.gi_code
+ if _PY35:
+
+ __await__ = __iter__ # make compatible with 'await' expression
+
+ @property
+ def cr_running(self):
+ return self.gen.cr_running
+
+ @property
+ def cr_code(self):
+ return self.gen.cr_code
+
+ @property
+ def cr_frame(self):
+ return self.gen.cr_frame
+
def __del__(self):
# Be careful accessing self.gen.frame -- self.gen might not exist.
gen = getattr(self, 'gen', None)
frame = getattr(gen, 'gi_frame', None)
+ if frame is None:
+ frame = getattr(gen, 'cr_frame', None)
if frame is not None and frame.f_lasti == -1:
msg = '%r was never yielded from' % self
tb = getattr(self, '_source_traceback', ())
@@ -177,8 +179,7 @@ def coroutine(func):
If the coroutine is not yielded from before it is destroyed,
an error message is logged.
"""
- is_coroutine = _iscoroutinefunction(func)
- if is_coroutine and _is_native_coro_code(func.__code__):
+ if _inspect_iscoroutinefunction(func):
# In Python 3.5 that's all we need to do for coroutines
# defiend with "async def".
# Wrapping in CoroWrapper will happen via
@@ -193,7 +194,7 @@ def coroutine(func):
res = func(*args, **kw)
if isinstance(res, futures.Future) or inspect.isgenerator(res):
res = yield from res
- elif AwaitableABC is not None:
+ elif _AwaitableABC is not None:
# If 'func' returns an Awaitable (new in 3.5) we
# want to run it.
try:
@@ -201,15 +202,15 @@ def coroutine(func):
except AttributeError:
pass
else:
- if isinstance(res, AwaitableABC):
+ if isinstance(res, _AwaitableABC):
res = yield from await_meth()
return res
if not _DEBUG:
- if native_coroutine_support:
- wrapper = types.coroutine(coro)
- else:
+ if _types_coroutine is None:
wrapper = coro
+ else:
+ wrapper = _types_coroutine(coro)
else:
@functools.wraps(func)
def wrapper(*args, **kwds):
@@ -231,12 +232,12 @@ def coroutine(func):
def iscoroutinefunction(func):
"""Return True if func is a decorated coroutine function."""
return (getattr(func, '_is_coroutine', False) or
- _iscoroutinefunction(func))
+ _inspect_iscoroutinefunction(func))
_COROUTINE_TYPES = (types.GeneratorType, CoroWrapper)
-if CoroutineABC is not None:
- _COROUTINE_TYPES += (CoroutineABC,)
+if _CoroutineABC is not None:
+ _COROUTINE_TYPES += (_CoroutineABC,)
def iscoroutine(obj):
@@ -247,28 +248,45 @@ def iscoroutine(obj):
def _format_coroutine(coro):
assert iscoroutine(coro)
+ coro_name = None
if isinstance(coro, CoroWrapper):
func = coro.func
+ coro_name = coro.__qualname__
+ if coro_name is not None:
+ coro_name = '{}()'.format(coro_name)
else:
func = coro
- coro_name = events._format_callback(func, ())
- filename = coro.gi_code.co_filename
+ if coro_name is None:
+ coro_name = events._format_callback(func, ())
+
+ try:
+ coro_code = coro.gi_code
+ except AttributeError:
+ coro_code = coro.cr_code
+
+ try:
+ coro_frame = coro.gi_frame
+ except AttributeError:
+ coro_frame = coro.cr_frame
+
+ filename = coro_code.co_filename
if (isinstance(coro, CoroWrapper)
- and not inspect.isgeneratorfunction(coro.func)):
+ and not inspect.isgeneratorfunction(coro.func)
+ and coro.func is not None):
filename, lineno = events._get_function_source(coro.func)
- if coro.gi_frame is None:
+ if coro_frame is None:
coro_repr = ('%s done, defined at %s:%s'
% (coro_name, filename, lineno))
else:
coro_repr = ('%s running, defined at %s:%s'
% (coro_name, filename, lineno))
- elif coro.gi_frame is not None:
- lineno = coro.gi_frame.f_lineno
+ elif coro_frame is not None:
+ lineno = coro_frame.f_lineno
coro_repr = ('%s running at %s:%s'
% (coro_name, filename, lineno))
else:
- lineno = coro.gi_code.co_firstlineno
+ lineno = coro_code.co_firstlineno
coro_repr = ('%s done, defined at %s:%s'
% (coro_name, filename, lineno))
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 82ee955a8b..07b2261115 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -34,7 +34,7 @@ class ContextDecorator(object):
class _GeneratorContextManager(ContextDecorator):
"""Helper for @contextmanager decorator."""
- def __init__(self, func, *args, **kwds):
+ def __init__(self, func, args, kwds):
self.gen = func(*args, **kwds)
self.func, self.args, self.kwds = func, args, kwds
# Issue 19330: ensure context manager instances have good docstrings
@@ -52,7 +52,7 @@ class _GeneratorContextManager(ContextDecorator):
# _GCM instances are one-shot context managers, so the
# CM must be recreated each time a decorated function is
# called
- return self.__class__(self.func, *self.args, **self.kwds)
+ return self.__class__(self.func, self.args, self.kwds)
def __enter__(self):
try:
@@ -123,7 +123,7 @@ def contextmanager(func):
"""
@wraps(func)
def helper(*args, **kwds):
- return _GeneratorContextManager(func, *args, **kwds)
+ return _GeneratorContextManager(func, args, kwds)
return helper
diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py
index 6541df75e0..251192acee 100644
--- a/Lib/test/test_asyncio/test_tasks.py
+++ b/Lib/test/test_asyncio/test_tasks.py
@@ -1715,7 +1715,8 @@ class TaskTests(test_utils.TestCase):
self.assertTrue(m_log.error.called)
message = m_log.error.call_args[0][0]
func_filename, func_lineno = test_utils.get_function_source(coro_noop)
- regex = (r'^<CoroWrapper %s\(\) .* at %s:%s, .*> '
+
+ regex = (r'^<CoroWrapper %s\(?\)? .* at %s:%s, .*> '
r'was never yielded from\n'
r'Coroutine object created at \(most recent call last\):\n'
r'.*\n'
diff --git a/Lib/test/test_cmath.py b/Lib/test/test_cmath.py
index 4db6b2b991..68bf16e51a 100644
--- a/Lib/test/test_cmath.py
+++ b/Lib/test/test_cmath.py
@@ -1,4 +1,4 @@
-from test.support import run_unittest, requires_IEEE_754
+from test.support import run_unittest, requires_IEEE_754, cpython_only
from test.test_math import parse_testfile, test_file
import unittest
import cmath, math
@@ -381,17 +381,48 @@ class CMathTests(unittest.TestCase):
self.rAssertAlmostEqual(expected.imag, actual.imag,
msg=error_message)
- def assertCISEqual(self, a, b):
- eps = 1E-7
- if abs(a[0] - b[0]) > eps or abs(a[1] - b[1]) > eps:
- self.fail((a ,b))
+ def check_polar(self, func):
+ def check(arg, expected):
+ got = func(arg)
+ for e, g in zip(expected, got):
+ self.rAssertAlmostEqual(e, g)
+ check(0, (0., 0.))
+ check(1, (1., 0.))
+ check(-1, (1., pi))
+ check(1j, (1., pi / 2))
+ check(-3j, (3., -pi / 2))
+ inf = float('inf')
+ check(complex(inf, 0), (inf, 0.))
+ check(complex(-inf, 0), (inf, pi))
+ check(complex(3, inf), (inf, pi / 2))
+ check(complex(5, -inf), (inf, -pi / 2))
+ check(complex(inf, inf), (inf, pi / 4))
+ check(complex(inf, -inf), (inf, -pi / 4))
+ check(complex(-inf, inf), (inf, 3 * pi / 4))
+ check(complex(-inf, -inf), (inf, -3 * pi / 4))
+ nan = float('nan')
+ check(complex(nan, 0), (nan, nan))
+ check(complex(0, nan), (nan, nan))
+ check(complex(nan, nan), (nan, nan))
+ check(complex(inf, nan), (inf, nan))
+ check(complex(-inf, nan), (inf, nan))
+ check(complex(nan, inf), (inf, nan))
+ check(complex(nan, -inf), (inf, nan))
def test_polar(self):
- self.assertCISEqual(polar(0), (0., 0.))
- self.assertCISEqual(polar(1.), (1., 0.))
- self.assertCISEqual(polar(-1.), (1., pi))
- self.assertCISEqual(polar(1j), (1., pi/2))
- self.assertCISEqual(polar(-1j), (1., -pi/2))
+ self.check_polar(polar)
+
+ @cpython_only
+ def test_polar_errno(self):
+ # Issue #24489: check a previously set C errno doesn't disturb polar()
+ from _testcapi import set_errno
+ def polar_with_errno_set(z):
+ set_errno(11)
+ try:
+ return polar(z)
+ finally:
+ set_errno(0)
+ self.check_polar(polar_with_errno_set)
def test_phase(self):
self.assertAlmostEqual(phase(0), 0.)
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index 39cc776dbc..8f849ae560 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -111,6 +111,14 @@ class ContextManagerTestCase(unittest.TestCase):
baz = self._create_contextmanager_attribs()(None)
self.assertEqual(baz.__doc__, "Whee!")
+ def test_keywords(self):
+ # Ensure no keyword arguments are inhibited
+ @contextmanager
+ def woohoo(self, func, args, kwds):
+ yield (self, func, args, kwds)
+ with woohoo(self=11, func=22, args=33, kwds=44) as target:
+ self.assertEqual(target, (11, 22, 33, 44))
+
class ClosingTestCase(unittest.TestCase):
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
index ad9820bf23..1775ef3353 100644
--- a/Lib/test/test_urlparse.py
+++ b/Lib/test/test_urlparse.py
@@ -663,6 +663,47 @@ class UrlParseTestCase(unittest.TestCase):
self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff?query"),
(b'x-newscheme', b'foo.com', b'/stuff', b'', b'query', b''))
+ def test_default_scheme(self):
+ # Exercise the scheme parameter of urlparse() and urlsplit()
+ for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
+ with self.subTest(function=func):
+ result = func("http://example.net/", "ftp")
+ self.assertEqual(result.scheme, "http")
+ result = func(b"http://example.net/", b"ftp")
+ self.assertEqual(result.scheme, b"http")
+ self.assertEqual(func("path", "ftp").scheme, "ftp")
+ self.assertEqual(func("path", scheme="ftp").scheme, "ftp")
+ self.assertEqual(func(b"path", scheme=b"ftp").scheme, b"ftp")
+ self.assertEqual(func("path").scheme, "")
+ self.assertEqual(func(b"path").scheme, b"")
+ self.assertEqual(func(b"path", "").scheme, b"")
+
+ def test_parse_fragments(self):
+ # Exercise the allow_fragments parameter of urlparse() and urlsplit()
+ tests = (
+ ("http:#frag", "path"),
+ ("//example.net#frag", "path"),
+ ("index.html#frag", "path"),
+ (";a=b#frag", "params"),
+ ("?a=b#frag", "query"),
+ ("#frag", "path"),
+ )
+ for url, attr in tests:
+ for func in (urllib.parse.urlparse, urllib.parse.urlsplit):
+ if attr == "params" and func is urllib.parse.urlsplit:
+ attr = "path"
+ with self.subTest(url=url, function=func):
+ result = func(url, allow_fragments=False)
+ self.assertEqual(result.fragment, "")
+ self.assertTrue(getattr(result, attr).endswith("#frag"))
+ self.assertEqual(func(url, "", False).fragment, "")
+
+ result = func(url, allow_fragments=True)
+ self.assertEqual(result.fragment, "frag")
+ self.assertFalse(getattr(result, attr).endswith("frag"))
+ self.assertEqual(func(url, "", True).fragment, "frag")
+ self.assertEqual(func(url).fragment, "frag")
+
def test_mixed_types_rejected(self):
# Several functions that process either strings or ASCII encoded bytes
# accept multiple arguments. Check they reject mixed type input
diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py
index 7068a80970..cbaafcf923 100644
--- a/Lib/test/test_with.py
+++ b/Lib/test/test_with.py
@@ -12,8 +12,8 @@ from test.support import run_unittest
class MockContextManager(_GeneratorContextManager):
- def __init__(self, func, *args, **kwds):
- super().__init__(func, *args, **kwds)
+ def __init__(self, *args):
+ super().__init__(*args)
self.enter_called = False
self.exit_called = False
self.exit_args = None
@@ -31,7 +31,7 @@ class MockContextManager(_GeneratorContextManager):
def mock_contextmanager(func):
def helper(*args, **kwds):
- return MockContextManager(func, *args, **kwds)
+ return MockContextManager(func, args, kwds)
return helper
diff --git a/Lib/tkinter/test/test_tkinter/test_font.py b/Lib/tkinter/test/test_tkinter/test_font.py
index ba3b9da498..25b59132ad 100644
--- a/Lib/tkinter/test/test_tkinter/test_font.py
+++ b/Lib/tkinter/test/test_tkinter/test_font.py
@@ -75,10 +75,19 @@ class FontTest(AbstractTkTest, unittest.TestCase):
def test_families(self):
families = font.families(self.root)
- self.assertIn(self.font.actual('family'), families)
+ self.assertIsInstance(families, tuple)
+ self.assertTrue(families)
+ for family in families:
+ self.assertIsInstance(family, str)
+ self.assertTrue(family)
def test_names(self):
names = font.names(self.root)
+ self.assertIsInstance(names, tuple)
+ self.assertTrue(names)
+ for name in names:
+ self.assertIsInstance(name, str)
+ self.assertTrue(name)
self.assertIn(fontname, names)
tests_gui = (FontTest, )
diff --git a/Misc/NEWS b/Misc/NEWS
index 496a92e194..f2539d1f8b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -63,6 +63,11 @@ Library
- Issue #20387: Restore semantic round-trip correctness in tokenize/untokenize
for tab-indented blocks.
+- Issue #24336: The contextmanager decorator now works with functions with
+ keyword arguments called "func" and "self". Patch by Martin Panter.
+
+- Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
+
- Issue #5633: Fixed timeit when the statement is a string and the setup is not.
- Issue #24326: Fixed audioop.ratecv() with non-default weightB argument.
@@ -92,6 +97,8 @@ Library
- Issue #23796: peek and read1 methods of BufferedReader now raise ValueError
if they called on a closed object. Patch by John Hergenroeder.
+- Issue #24521: Fix possible integer overflows in the pickle module.
+
- Issue #22931: Allow '[' and ']' in cookie values.
- Issue #20274: Remove ignored and erroneous "kwargs" parameters from three
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 435cbaea9d..19a1c88bd1 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -428,9 +428,7 @@ Pdata_grow(Pdata *self)
if (new_allocated > PY_SSIZE_T_MAX - allocated)
goto nomemory;
new_allocated += allocated;
- if (new_allocated > (PY_SSIZE_T_MAX / sizeof(PyObject *)))
- goto nomemory;
- data = PyMem_REALLOC(data, new_allocated * sizeof(PyObject *));
+ PyMem_RESIZE(data, PyObject *, new_allocated);
if (data == NULL)
goto nomemory;
@@ -660,7 +658,7 @@ PyMemoTable_Copy(PyMemoTable *self)
/* The table we get from _New() is probably smaller than we wanted.
Free it and allocate one that's the right size. */
PyMem_FREE(new->mt_table);
- new->mt_table = PyMem_MALLOC(self->mt_allocated * sizeof(PyMemoEntry));
+ new->mt_table = PyMem_NEW(PyMemoEntry, self->mt_allocated);
if (new->mt_table == NULL) {
PyMem_FREE(new);
PyErr_NoMemory();
@@ -755,7 +753,7 @@ _PyMemoTable_ResizeTable(PyMemoTable *self, Py_ssize_t min_size)
/* Allocate new table. */
oldtable = self->mt_table;
- self->mt_table = PyMem_MALLOC(new_size * sizeof(PyMemoEntry));
+ self->mt_table = PyMem_NEW(PyMemoEntry, new_size);
if (self->mt_table == NULL) {
self->mt_table = oldtable;
PyErr_NoMemory();
@@ -1261,16 +1259,14 @@ static int
_Unpickler_ResizeMemoList(UnpicklerObject *self, Py_ssize_t new_size)
{
Py_ssize_t i;
- PyObject **memo;
assert(new_size > self->memo_size);
- memo = PyMem_REALLOC(self->memo, new_size * sizeof(PyObject *));
- if (memo == NULL) {
+ PyMem_RESIZE(self->memo, PyObject *, new_size);
+ if (self->memo == NULL) {
PyErr_NoMemory();
return -1;
}
- self->memo = memo;
for (i = self->memo_size; i < new_size; i++)
self->memo[i] = NULL;
self->memo_size = new_size;
@@ -1314,7 +1310,7 @@ _Unpickler_MemoPut(UnpicklerObject *self, Py_ssize_t idx, PyObject *value)
static PyObject **
_Unpickler_NewMemo(Py_ssize_t new_size)
{
- PyObject **memo = PyMem_MALLOC(new_size * sizeof(PyObject *));
+ PyObject **memo = PyMem_NEW(PyObject *, new_size);
if (memo == NULL) {
PyErr_NoMemory();
return NULL;
@@ -5963,7 +5959,6 @@ load_mark(UnpicklerObject *self)
if ((self->num_marks + 1) >= self->marks_size) {
size_t alloc;
- Py_ssize_t *marks;
/* Use the size_t type to check for overflow. */
alloc = ((size_t)self->num_marks << 1) + 20;
@@ -5974,15 +5969,14 @@ load_mark(UnpicklerObject *self)
}
if (self->marks == NULL)
- marks = (Py_ssize_t *) PyMem_Malloc(alloc * sizeof(Py_ssize_t));
+ self->marks = PyMem_NEW(Py_ssize_t, alloc);
else
- marks = (Py_ssize_t *) PyMem_Realloc(self->marks,
- alloc * sizeof(Py_ssize_t));
- if (marks == NULL) {
+ PyMem_RESIZE(self->marks, Py_ssize_t, alloc);
+ if (self->marks == NULL) {
+ self->marks_size = 0;
PyErr_NoMemory();
return -1;
}
- self->marks = marks;
self->marks_size = (Py_ssize_t)alloc;
}
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index cf4b0e14f0..8ebe9709b7 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1784,6 +1784,18 @@ raise_exception(PyObject *self, PyObject *args)
}
static PyObject *
+set_errno(PyObject *self, PyObject *args)
+{
+ int new_errno;
+
+ if (!PyArg_ParseTuple(args, "i:set_errno", &new_errno))
+ return NULL;
+
+ errno = new_errno;
+ Py_RETURN_NONE;
+}
+
+static PyObject *
test_set_exc_info(PyObject *self, PyObject *args)
{
PyObject *orig_exc;
@@ -3208,6 +3220,7 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args)
static PyMethodDef TestMethods[] = {
{"raise_exception", raise_exception, METH_VARARGS},
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
+ {"set_errno", set_errno, METH_VARARGS},
{"test_config", (PyCFunction)test_config, METH_NOARGS},
{"test_sizeof_c_types", (PyCFunction)test_sizeof_c_types, METH_NOARGS},
{"test_datetime_capi", test_datetime_capi, METH_NOARGS},
diff --git a/Modules/cmathmodule.c b/Modules/cmathmodule.c
index eb2853cedd..b341c343e1 100644
--- a/Modules/cmathmodule.c
+++ b/Modules/cmathmodule.c
@@ -941,9 +941,10 @@ cmath_polar(PyObject *self, PyObject *args)
double r, phi;
if (!PyArg_ParseTuple(args, "D:polar", &z))
return NULL;
+ errno = 0;
PyFPE_START_PROTECT("polar function", return 0)
phi = c_atan2(z); /* should not cause any exception */
- r = c_abs(z); /* sets errno to ERANGE on overflow; otherwise 0 */
+ r = c_abs(z); /* sets errno to ERANGE on overflow */
PyFPE_END_PROTECT(r)
if (errno != 0)
return math_error();
diff --git a/Python/ceval.c b/Python/ceval.c
index 7656b8ef54..275229858e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -710,7 +710,7 @@ Py_SetRecursionLimit(int new_limit)
to guarantee that _Py_CheckRecursiveCall() is regularly called.
Without USE_STACKCHECK, there is no need for this. */
int
-_Py_CheckRecursiveCall(char *where)
+_Py_CheckRecursiveCall(const char *where)
{
PyThreadState *tstate = PyThreadState_GET();
diff --git a/Python/traceback.c b/Python/traceback.c
index 2bea29e44a..7d1fc2e8ac 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -143,7 +143,7 @@ PyTraceBack_Here(PyFrameObject *frame)
}
/* Insert a frame into the traceback for (funcname, filename, lineno). */
-void _PyTraceback_Add(char *funcname, char *filename, int lineno)
+void _PyTraceback_Add(const char *funcname, const char *filename, int lineno)
{
PyObject *globals = NULL;
PyCodeObject *code = NULL;