diff options
-rw-r--r-- | Doc/c-api/conversion.rst | 4 | ||||
-rw-r--r-- | Doc/c-api/exceptions.rst | 10 | ||||
-rw-r--r-- | Doc/c-api/import.rst | 4 | ||||
-rw-r--r-- | Doc/c-api/init.rst | 2 | ||||
-rw-r--r-- | Doc/c-api/mapping.rst | 2 | ||||
-rw-r--r-- | Doc/c-api/marshal.rst | 2 | ||||
-rw-r--r-- | Doc/c-api/sys.rst | 4 | ||||
-rw-r--r-- | Doc/c-api/unicode.rst | 2 | ||||
-rw-r--r-- | Doc/extending/extending.rst | 6 | ||||
-rw-r--r-- | Doc/faq/extending.rst | 4 | ||||
-rw-r--r-- | Doc/library/asyncio-eventloop.rst | 16 | ||||
-rw-r--r-- | Doc/library/urllib.parse.rst | 16 | ||||
-rw-r--r-- | Include/ceval.h | 2 | ||||
-rw-r--r-- | Include/traceback.h | 2 | ||||
-rw-r--r-- | Lib/asyncio/coroutines.py | 100 | ||||
-rw-r--r-- | Lib/contextlib.py | 6 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_tasks.py | 3 | ||||
-rw-r--r-- | Lib/test/test_cmath.py | 51 | ||||
-rw-r--r-- | Lib/test/test_contextlib.py | 8 | ||||
-rw-r--r-- | Lib/test/test_urlparse.py | 41 | ||||
-rw-r--r-- | Lib/test/test_with.py | 6 | ||||
-rw-r--r-- | Lib/tkinter/test/test_tkinter/test_font.py | 11 | ||||
-rw-r--r-- | Misc/NEWS | 7 | ||||
-rw-r--r-- | Modules/_pickle.c | 26 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 13 | ||||
-rw-r--r-- | Modules/cmathmodule.c | 3 | ||||
-rw-r--r-- | Python/ceval.c | 2 | ||||
-rw-r--r-- | Python/traceback.c | 2 |
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, ) @@ -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; |