# Task C: Compute factorial(4)...
# Task C: factorial(4) = 24
+ .. note::
+ If *return_exceptions* is False, cancelling gather() after it
+ has been marked done won't cancel any submitted awaitables.
+ For instance, gather can be marked done after propagating an
+ exception to the caller, therefore, calling ``gather.cancel()``
+ after catching an exception (raised by one of the awaitables) from
+ gather won't cancel any other awaitables.
+
.. versionchanged:: 3.7
If the *gather* itself is cancelled, the cancellation is
propagated regardless of *return_exceptions*.
The rounding mode of the context is used. Results are always correctly-rounded
in the Python version.
+ ``Decimal(0) ** Decimal(0)`` results in ``InvalidOperation``, and if ``InvalidOperation``
+ is not trapped, then results in ``Decimal('NaN')``.
+
.. versionchanged:: 3.3
The C module computes :meth:`power` in terms of the correctly-rounded
:meth:`exp` and :meth:`ln` functions. The result is well-defined but
.. method:: apply_async(func[, args[, kwds[, callback[, error_callback]]]])
- A variant of the :meth:`apply` method which returns a result object.
+ A variant of the :meth:`apply` method which returns a
+ :class:`~multiprocessing.pool.AsyncResult` object.
If *callback* is specified then it should be a callable which accepts a
single argument. When the result becomes ready *callback* is applied to
.. method:: map_async(func, iterable[, chunksize[, callback[, error_callback]]])
- A variant of the :meth:`.map` method which returns a result object.
+ A variant of the :meth:`.map` method which returns a
+ :class:`~multiprocessing.pool.AsyncResult` object.
If *callback* is specified then it should be a callable which accepts a
single argument. When the result becomes ready *callback* is applied to
arguments and make more complex assertions. See
:ref:`calls as tuples <calls-as-tuples>`.
+ .. versionchanged:: 3.8
+ Added ``args`` and ``kwargs`` properties.
+
.. attribute:: call_args_list
.. doctest::
:options: +NORMALIZE_WHITESPACE
- >>> from urllib.parse import urlparse
- >>> urlparse('//www.cwi.nl:80/%7Eguido/Python.html')
- ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
+ >>> from urllib.parse import urlparse
+ >>> urlparse('//www.cwi.nl:80/%7Eguido/Python.html')
+ ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
params='', query='', fragment='')
- >>> urlparse('www.cwi.nl/%7Eguido/Python.html')
- ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html',
+ >>> urlparse('www.cwi.nl/%7Eguido/Python.html')
+ ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html',
params='', query='', fragment='')
- >>> urlparse('help/Python.html')
- ParseResult(scheme='', netloc='', path='help/Python.html', params='',
+ >>> urlparse('help/Python.html')
+ ParseResult(scheme='', netloc='', path='help/Python.html', params='',
query='', fragment='')
The *scheme* argument gives the default addressing scheme, to be
.. doctest::
:options: +NORMALIZE_WHITESPACE
- >>> from urllib.parse import urlparse
- >>> u = urlparse('//www.cwi.nl:80/%7Eguido/Python.html')
- >>> u
- ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
- params='', query='', fragment='')
- >>> u._replace(scheme='http')
- ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
- params='', query='', fragment='')
+ >>> from urllib.parse import urlparse
+ >>> u = urlparse('//www.cwi.nl:80/%7Eguido/Python.html')
+ >>> u
+ ParseResult(scheme='', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
+ params='', query='', fragment='')
+ >>> u._replace(scheme='http')
+ ParseResult(scheme='http', netloc='www.cwi.nl:80', path='/%7Eguido/Python.html',
+ params='', query='', fragment='')
.. versionchanged:: 3.2
name attempts to find the name in the namespace.
Although scopes are determined statically, they are used dynamically. At any
-time during execution, At any time during execution, there are 3 or 4 nested
-scopes whose namespaces are directly accessible:
+time during execution, there are 3 or 4 nested scopes whose namespaces are
+directly accessible:
* the innermost scope, which is searched first, contains the local names
* the scopes of any enclosing functions, which are searched starting with the
(Contributed by Yury Selivanov in :issue:`37028`.)
The exception :class:`asyncio.CancelledError` now inherits from
-:class:`BaseException` rather than :class:`Exception`.
+:class:`BaseException` rather than :class:`Exception` and no longer inherits
+from :class:`concurrent.futures.CancelledError`.
(Contributed by Yury Selivanov in :issue:`32528`.)
On Windows, the default event loop is now :class:`~asyncio.ProactorEventLoop`.
(Contributed by Anthony Sottile in :issue:`36264`.)
* The exception :class:`asyncio.CancelledError` now inherits from
- :class:`BaseException` rather than :class:`Exception`.
+ :class:`BaseException` rather than :class:`Exception` and no longer inherits
+ from :class:`concurrent.futures.CancelledError`.
(Contributed by Yury Selivanov in :issue:`32528`.)
* The function :func:`asyncio.wait_for` now correctly waits for cancellation
/*--start constants--*/
#define PY_MAJOR_VERSION 3
#define PY_MINOR_VERSION 8
-#define PY_MICRO_VERSION 4
+#define PY_MICRO_VERSION 5
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL
#define PY_RELEASE_SERIAL 0
/* Version as a string */
-#define PY_VERSION "3.8.4"
+#define PY_VERSION "3.8.5"
/*--end constants--*/
/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2.
the outer Future is *not* cancelled in this case. (This is to
prevent the cancellation of one child to cause other children to
be cancelled.)
+
+ If *return_exceptions* is False, cancelling gather() after it
+ has been marked done won't cancel any submitted awaitables.
+ For instance, gather can be marked done after propagating an
+ exception to the caller, therefore, calling ``gather.cancel()``
+ after catching an exception (raised by one of the awaitables) from
+ gather won't cancel any other awaitables.
"""
if not coros_or_futures:
if loop is None:
# _is_allowed_url_pchars_re = re.compile(r"^[/!$&'()*+,;=:@%a-zA-Z0-9._~-]+$")
# We are more lenient for assumed real world compatibility purposes.
+# These characters are not allowed within HTTP method names
+# to prevent http header injection.
+_contains_disallowed_method_pchar_re = re.compile('[\x00-\x1f]')
+
# We always set the Content-Length header for these methods because some
# servers will otherwise respond with a 411
_METHODS_EXPECTING_BODY = {'PATCH', 'POST', 'PUT'}
else:
raise CannotSendRequest(self.__state)
+ self._validate_method(method)
+
# Save the method for use later in the response phase
self._method = method
# ASCII also helps prevent CVE-2019-9740.
return request.encode('ascii')
+ def _validate_method(self, method):
+ """Validate a method name for putrequest."""
+ # prevent http header injection
+ match = _contains_disallowed_method_pchar_re.search(method)
+ if match:
+ raise ValueError(
+ f"method can't contain control characters. {method!r} "
+ f"(found at least {match.group()!r})")
+
def _validate_path(self, url):
"""Validate a url for putrequest."""
# Prevent CVE-2019-9740.
-What's New in IDLE 3.8.4
-Released on 2020-07-03?
+What's New in IDLE 3.8.5
+Released on 2020-07-20
======================================
+bpo-41300: Save files with non-ascii chars. Fix regression in
+3.9.0b4 and 3.8.4.
+
+What's New in IDLE 3.8.4
+Released on 2020-06-30
+======================================
+
bpo-37765: Add keywords to module name completion list. Rewrite
Completions section of IDLE doc.
+import io
import os
import shlex
import sys
# -*- coding: utf-8 -*-
-# Autogenerated by Sphinx on Mon Jul 13 13:47:56 2020
+# Autogenerated by Sphinx on Mon Jul 20 14:14:54 2020
topics = {'assert': 'The "assert" statement\n'
'**********************\n'
'\n'
length, keyword = match.groups()
length = int(length)
+ if length == 0:
+ raise InvalidHeaderError("invalid header")
value = buf[match.end(2) + 1:match.start(1) + length - 1]
# Normally, we could just use "utf-8" as the encoding and "strict"
self.assertIs(type(unpickled), collections.UserDict)
self.assertEqual(unpickled, collections.UserDict({1: 2}))
+ def test_bad_reduce(self):
+ self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0)
+ self.check_unpickling_error(TypeError, b'N)R.')
+ self.check_unpickling_error(TypeError, b'cbuiltins\nint\nNR.')
+
+ def test_bad_newobj(self):
+ error = (pickle.UnpicklingError, TypeError)
+ self.assertEqual(self.loads(b'cbuiltins\nint\n)\x81.'), 0)
+ self.check_unpickling_error(error, b'cbuiltins\nlen\n)\x81.')
+ self.check_unpickling_error(error, b'cbuiltins\nint\nN\x81.')
+
+ def test_bad_newobj_ex(self):
+ error = (pickle.UnpicklingError, TypeError)
+ self.assertEqual(self.loads(b'cbuiltins\nint\n)}\x92.'), 0)
+ self.check_unpickling_error(error, b'cbuiltins\nlen\n)}\x92.')
+ self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.')
+ self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.')
+
def test_bad_stack(self):
badpickles = [
b'.', # STOP
else:
self.fail("Carlo Verre __delattr__ succeeded!")
+ def test_carloverre_multi_inherit_valid(self):
+ class A(type):
+ def __setattr__(cls, key, value):
+ type.__setattr__(cls, key, value)
+
+ class B:
+ pass
+
+ class C(B, A):
+ pass
+
+ obj = C('D', (object,), {})
+ try:
+ obj.test = True
+ except TypeError:
+ self.fail("setattr through direct base types should be legal")
+
+ def test_carloverre_multi_inherit_invalid(self):
+ class A(type):
+ def __setattr__(cls, key, value):
+ object.__setattr__(cls, key, value) # this should fail!
+
+ class B:
+ pass
+
+ class C(B, A):
+ pass
+
+ obj = C('D', (object,), {})
+ try:
+ obj.test = True
+ except TypeError:
+ pass
+ else:
+ self.fail("setattr through indirect base types should be rejected")
+
def test_weakref_segfault(self):
# Testing weakref segfault...
# SF 742911
self.assertEqual(lines[3], "header: Second: val2")
+class HttpMethodTests(TestCase):
+ def test_invalid_method_names(self):
+ methods = (
+ 'GET\r',
+ 'POST\n',
+ 'PUT\n\r',
+ 'POST\nValue',
+ 'POST\nHOST:abc',
+ 'GET\nrHost:abc\n',
+ 'POST\rRemainder:\r',
+ 'GET\rHOST:\n',
+ '\nPUT'
+ )
+
+ for method in methods:
+ with self.assertRaisesRegex(
+ ValueError, "method can't contain control characters"):
+ conn = client.HTTPConnection('example.com')
+ conn.sock = FakeSocket(None)
+ conn.request(method=method, url="/")
+
+
class TransferEncodingTest(TestCase):
expected_body = b"It's just a flesh wound"
@unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
class _pthFileTests(unittest.TestCase):
- def _create_underpth_exe(self, lines):
+ def _create_underpth_exe(self, lines, exe_pth=True):
+ import _winapi
temp_dir = tempfile.mkdtemp()
self.addCleanup(test.support.rmtree, temp_dir)
exe_file = os.path.join(temp_dir, os.path.split(sys.executable)[1])
+ dll_src_file = _winapi.GetModuleFileName(sys.dllhandle)
+ dll_file = os.path.join(temp_dir, os.path.split(dll_src_file)[1])
shutil.copy(sys.executable, exe_file)
- _pth_file = os.path.splitext(exe_file)[0] + '._pth'
+ shutil.copy(dll_src_file, dll_file)
+ if exe_pth:
+ _pth_file = os.path.splitext(exe_file)[0] + '._pth'
+ else:
+ _pth_file = os.path.splitext(dll_file)[0] + '._pth'
with open(_pth_file, 'w') as f:
for line in lines:
print(line, file=f)
self.assertTrue(rc, "sys.path is incorrect")
+ def test_underpth_dll_file(self):
+ libpath = os.path.dirname(os.path.dirname(encodings.__file__))
+ exe_prefix = os.path.dirname(sys.executable)
+ exe_file = self._create_underpth_exe([
+ 'fake-path-name',
+ *[libpath for _ in range(200)],
+ '',
+ '# comment',
+ 'import site'
+ ], exe_pth=False)
+ sys_prefix = os.path.dirname(exe_file)
+ env = os.environ.copy()
+ env['PYTHONPATH'] = 'from-env'
+ env['PATH'] = '{};{}'.format(exe_prefix, os.getenv('PATH'))
+ rc = subprocess.call([exe_file, '-c',
+ 'import sys; sys.exit(not sys.flags.no_site and '
+ '%r in sys.path and %r in sys.path and %r not in sys.path and '
+ 'all("\\r" not in p and "\\n" not in p for p in sys.path))' % (
+ os.path.join(sys_prefix, 'fake-path-name'),
+ libpath,
+ os.path.join(sys_prefix, 'from-env'),
+ )], env=env)
+ self.assertTrue(rc, "sys.path is incorrect")
+
+
if __name__ == "__main__":
unittest.main()
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
tar.extractfile(t).read()
+ def test_length_zero_header(self):
+ # bpo-39017 (CVE-2019-20907): reading a zero-length header should fail
+ # with an exception
+ with self.assertRaisesRegex(tarfile.ReadError, "file could not be opened successfully"):
+ with tarfile.open(support.findfile('recursion.tar')) as tar:
+ pass
+
class MiscReadTestBase(CommonReadTest):
def requires_name_attribute(self):
pass
),
),
dict(
- name="SQLite 3.32.2",
- url="https://sqlite.org/2020/sqlite-autoconf-3320200.tar.gz",
- checksum='eb498918a33159cdf8104997aad29e83',
+ name="SQLite 3.32.3",
+ url="https://sqlite.org/2020/sqlite-autoconf-3320300.tar.gz",
+ checksum='2e3911a3c15e85c2f2d040154bbe5ce3',
extra_cflags=('-Os '
'-DSQLITE_ENABLE_FTS5 '
'-DSQLITE_ENABLE_FTS4 '
Python News
+++++++++++
+What's New in Python 3.8.5 final?
+=================================
+
+*Release date: 2020-07-20*
+
+Security
+--------
+
+- bpo-41304: Fixes `python3x._pth` being ignored on Windows, caused by the
+ fix for :issue:`29778` (CVE-2020-15801).
+
+- bpo-39603: Prevent http header injection by rejecting control characters
+ in http.client.putrequest(...).
+
+Core and Builtins
+-----------------
+
+- bpo-41295: Resolve a regression in CPython 3.8.4 where defining
+ "__setattr__" in a multi-inheritance setup and calling up the hierarchy
+ chain could fail if builtins/extension types were involved in the base
+ types.
+
+Library
+-------
+
+- bpo-41288: Unpickling invalid NEWOBJ_EX opcode with the C implementation
+ raises now UnpicklingError instead of crashing.
+
+- bpo-39017: Avoid infinite loop when reading specially crafted TAR files
+ using the tarfile module (CVE-2019-20907).
+
+Documentation
+-------------
+
+- bpo-37703: Updated Documentation to comprehensively elaborate on the
+ behaviour of gather.cancel()
+
+Build
+-----
+
+- bpo-41302: Enable building Python 3.8 with libmpdec-2.5.0 to ease
+ maintenance for Linux distributions. Patch by Felix Yan.
+
+macOS
+-----
+
+- bpo-40741: Update macOS installer to use SQLite 3.32.3.
+
+IDLE
+----
+
+- bpo-41300: Save files with non-ascii chars. Fix regression released in
+ 3.9.0b4 and 3.8.4.
+
+
What's New in Python 3.8.4 final?
=================================
#define BOUNDS_CHECK(x, MIN, MAX) x = (x < MIN || MAX < x) ? MAX : x
+#ifndef UNUSED
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+ #define UNUSED __attribute__((unused))
+#else
+ #define UNUSED
+#endif
+#endif
/* _Py_DEC_MINALLOC >= MPD_MINALLOC */
#define _Py_DEC_MINALLOC 4
}
if (!PyType_Check(cls)) {
- Py_DECREF(kwargs);
- Py_DECREF(args);
PyErr_Format(st->UnpicklingError,
"NEWOBJ_EX class argument must be a type, not %.200s",
Py_TYPE(cls)->tp_name);
- Py_DECREF(cls);
- return -1;
+ goto error;
}
if (((PyTypeObject *)cls)->tp_new == NULL) {
- Py_DECREF(kwargs);
- Py_DECREF(args);
- Py_DECREF(cls);
PyErr_SetString(st->UnpicklingError,
"NEWOBJ_EX class argument doesn't have __new__");
- return -1;
+ goto error;
+ }
+ if (!PyTuple_Check(args)) {
+ PyErr_Format(st->UnpicklingError,
+ "NEWOBJ_EX args argument must be a tuple, not %.200s",
+ Py_TYPE(args)->tp_name);
+ goto error;
+ }
+ if (!PyDict_Check(kwargs)) {
+ PyErr_Format(st->UnpicklingError,
+ "NEWOBJ_EX kwargs argument must be a dict, not %.200s",
+ Py_TYPE(kwargs)->tp_name);
+ goto error;
}
+
obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
Py_DECREF(kwargs);
Py_DECREF(args);
}
PDATA_PUSH(self->stack, obj, -1);
return 0;
+
+error:
+ Py_DECREF(kwargs);
+ Py_DECREF(args);
+ Py_DECREF(cls);
+ return -1;
}
static int
};
static VOID CALLBACK
-PostToQueueCallback(PVOID lpParameter, BOOL TimerOrWaitFired)
+PostToQueueCallback(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
struct PostCallbackData *p = (struct PostCallbackData*) lpParameter;
*pdata = data;
if (!RegisterWaitForSingleObject(
- &NewWaitObject, Object, (WAITORTIMERCALLBACK)PostToQueueCallback,
- pdata, Milliseconds,
+ &NewWaitObject, Object, PostToQueueCallback, pdata, Milliseconds,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE))
{
PyMem_RawFree(pdata);
return 1;
}
assert(PyTuple_Check(mro));
- Py_ssize_t i, n;
- n = PyTuple_GET_SIZE(mro);
- for (i = 0; i < n; i++) {
+
+ /* Find the (base) type that defined the type's slot function. */
+ PyTypeObject *defining_type = type;
+ Py_ssize_t i;
+ for (i = PyTuple_GET_SIZE(mro) - 1; i >= 0; i--) {
PyTypeObject *base = (PyTypeObject*) PyTuple_GET_ITEM(mro, i);
+ if (base->tp_setattro == slot_tp_setattro) {
+ /* Ignore Python classes:
+ they never define their own C-level setattro. */
+ }
+ else if (base->tp_setattro == type->tp_setattro) {
+ defining_type = base;
+ break;
+ }
+ }
+
+ /* Reject calls that jump over intermediate C-level overrides. */
+ for (PyTypeObject *base = defining_type; base; base = base->tp_base) {
if (base->tp_setattro == func) {
- /* 'func' is the earliest non-Python implementation in the MRO. */
+ /* 'func' is the right slot function to call. */
break;
- } else if (base->tp_setattro != slot_tp_setattro) {
+ }
+ else if (base->tp_setattro != slot_tp_setattro) {
/* 'base' is not a Python class and overrides 'func'.
Its tp_setattro should be called instead. */
PyErr_Format(PyExc_TypeError,
return 0;
}
}
- /* Either 'func' is not in the mro (which should fail when checking 'self'),
- or it's the right slot function to call. */
return 1;
}
get_pth_filename(PyCalculatePath *calculate, wchar_t *filename,
const _PyPathConfig *pathconfig)
{
- if (get_dllpath(filename) &&
+ if (!get_dllpath(filename) &&
!change_ext(filename, filename, L"._pth") &&
exists(filename))
{
static pthread_condattr_t *condattr_monotonic = NULL;
static void
-init_condattr()
+init_condattr(void)
{
#ifdef CONDATTR_MONOTONIC
static pthread_condattr_t ca;
-This is Python version 3.8.4
+This is Python version 3.8.5
============================
.. image:: https://travis-ci.org/python/cpython.svg?branch=3.8