diff -Nru python3.10-3.10.3/configure python3.10-3.10.4/configure --- python3.10-3.10.3/configure 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/configure 2022-03-23 20:12:04.000000000 +0000 @@ -8101,7 +8101,7 @@ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \ -sys/endian.h sys/sysmacros.h linux/auxvec.h linux/memfd.h linux/wait.h sys/memfd.h \ +sys/endian.h sys/sysmacros.h linux/auxvec.h sys/auxv.h linux/memfd.h linux/wait.h sys/memfd.h \ sys/mman.h sys/eventfd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` diff -Nru python3.10-3.10.3/configure.ac python3.10-3.10.4/configure.ac --- python3.10-3.10.3/configure.ac 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/configure.ac 2022-03-23 20:12:04.000000000 +0000 @@ -2225,7 +2225,7 @@ sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \ -sys/endian.h sys/sysmacros.h linux/auxvec.h linux/memfd.h linux/wait.h sys/memfd.h \ +sys/endian.h sys/sysmacros.h linux/auxvec.h sys/auxv.h linux/memfd.h linux/wait.h sys/memfd.h \ sys/mman.h sys/eventfd.h) AC_HEADER_DIRENT AC_HEADER_MAJOR diff -Nru python3.10-3.10.3/debian/changelog python3.10-3.10.4/debian/changelog --- python3.10-3.10.3/debian/changelog 2022-03-16 17:19:40.000000000 +0000 +++ python3.10-3.10.4/debian/changelog 2022-04-02 09:04:19.000000000 +0000 @@ -1,3 +1,42 @@ +python3.10 (3.10.4-3) unstable; urgency=medium + + * Build a python3.10-nopie package, diverting the python3.10 + executable. + * Build the python3.10 interpreter with PIE enabled. Closes: ##919134. + LP: #1452115. + * Fix build on ia64 (Adrian Glaubitz). Closes: #1008576. + + -- Matthias Klose Sat, 02 Apr 2022 11:04:19 +0200 + +python3.10 (3.10.4-2) unstable; urgency=medium + + [ Stefano Rivera ] + * Avoid infinite recursion in _distutils_system_mod when + SETUPTOOLS_USE_DISTUTILS=local. + * Avoid crashing in `_distutils_system_mod` if we find an older version of + distutils (from before `_distutils_system_mod` was implemented). + + -- Matthias Klose Fri, 01 Apr 2022 17:03:31 +0200 + +python3.10 (3.10.4-1) unstable; urgency=medium + + * Python 3.10.4 release. + + -- Matthias Klose Thu, 24 Mar 2022 14:07:27 +0100 + +python3.10 (3.10.3-2) unstable; urgency=medium + + [ Stefano Rivera ] + * Change the "include" and "platinclude" paths in the "posix_local" + scheme to refer to the location of Python's headers, not the install + location for modules' C headers. Closes: #1007966 + + [ Matthias Klose ] + * Allow to build with PIE enabled by default, and build a separate + python3.10-nopie package. Not yet enabled for Debian. + + -- Matthias Klose Thu, 24 Mar 2022 12:42:32 +0100 + python3.10 (3.10.3-1) unstable; urgency=medium * Python 3.10.3 release. diff -Nru python3.10-3.10.3/debian/control python3.10-3.10.4/debian/control --- python3.10-3.10.3/debian/control 2022-02-22 14:05:53.000000000 +0000 +++ python3.10-3.10.4/debian/control 2022-04-02 09:04:19.000000000 +0000 @@ -91,6 +91,17 @@ contained in this package. XB-Cnf-Visible-Pkgname: python3.10 +Package: python3.10-nopie +Architecture: any +Multi-Arch: allowed +Priority: optional +Depends: python3.10-minimal (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Python interpreter linked without PIE (version 3.10) + This package contains the interpreter not built as position independent + executable. This interpreter is diverting the python3.10 executable, and making + the interpreter built with PIE available as python3.10-pie. +XB-Cnf-Visible-Pkgname: python3.10 + Package: libpython3.10-minimal Architecture: any Multi-Arch: same diff -Nru python3.10-3.10.3/debian/control.in python3.10-3.10.4/debian/control.in --- python3.10-3.10.3/debian/control.in 2022-02-22 14:05:01.000000000 +0000 +++ python3.10-3.10.4/debian/control.in 2022-04-02 09:04:19.000000000 +0000 @@ -91,6 +91,17 @@ contained in this package. XB-Cnf-Visible-Pkgname: @PVER@ +Package: @PVER@-nopie +Architecture: any +Multi-Arch: allowed +Priority: @MINPRIO@ +Depends: @PVER@-minimal (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} +Description: Python interpreter linked without PIE (version @VER@) + This package contains the interpreter not built as position independent + executable. This interpreter is diverting the @PVER@ executable, and making + the interpreter built with PIE available as @PVER@-pie. +XB-Cnf-Visible-Pkgname: @PVER@ + Package: lib@PVER@-minimal Architecture: any Multi-Arch: same diff -Nru python3.10-3.10.3/debian/patches/distutils-install-layout.diff python3.10-3.10.4/debian/patches/distutils-install-layout.diff --- python3.10-3.10.3/debian/patches/distutils-install-layout.diff 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/patches/distutils-install-layout.diff 2022-04-01 15:05:03.000000000 +0000 @@ -79,9 +79,9 @@ + 'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}', + 'purelib': '{base}/local/lib/python{py_version_short}/dist-packages', + 'platlib': '{platbase}/local/{platlibdir}/python{py_version_short}/dist-packages', -+ 'include': '{installed_base}/local/include/python{py_version_short}{abiflags}', -+ 'headers': '{installed_base}/local/include/python{py_version_short}{abiflags}', -+ 'platinclude': '{installed_platbase}/local/include/python{py_version_short}{abiflags}', ++ 'include': '{installed_base}/include/python{py_version_short}{abiflags}', ++ 'headers': '{base}/local/include/python{py_version_short}{abiflags}', ++ 'platinclude': '{installed_platbase}/include/python{py_version_short}{abiflags}', + 'scripts': '{base}/local/bin', + 'data': '{base}/local', +} @@ -302,7 +302,7 @@ def test_debug_mode(self): --- a/Lib/pydoc.py +++ b/Lib/pydoc.py -@@ -505,6 +505,7 @@ +@@ -509,6 +509,7 @@ 'marshal', 'posix', 'signal', 'sys', '_thread', 'zipimport') or (file.startswith(basedir) and @@ -312,7 +312,7 @@ if docloc.startswith(("http://", "https://")): --- /dev/null +++ b/Lib/_distutils_system_mod.py -@@ -0,0 +1,154 @@ +@@ -0,0 +1,180 @@ +""" +Apply Debian-specific patches to distutils commands. + @@ -325,6 +325,7 @@ + +import os +import sys ++import sysconfig + +import distutils.sysconfig +import distutils.command.install as orig_install @@ -423,21 +424,30 @@ + if standard_lib: + return libpython + elif is_default_prefix and not is_virtual_environment(): -+ return os.path.join(prefix, "lib", "python3", "dist-packages") ++ return os.path.join(prefix, "lib", "python3", "dist-packages") + else: + return os.path.join(libpython, "site-packages") + + +def _inject_headers(name, scheme): + """ -+ Default headers to the include path in sysconfig. -+ See: pypa/distutils#88 ++ Given a scheme name and the resolved scheme, ++ if the scheme does not include headers, resolve ++ the fallback scheme for the name and use headers ++ from it. pypa/distutils#88 ++ ++ headers: module headers install location (posix_local is /local/ prefixed) ++ include: cpython headers (Python.h) ++ See also: bpo-44445 + """ + if 'headers' not in scheme: -+ if 'include' in scheme: -+ scheme['headers'] = scheme['include'] ++ if name == 'posix_prefix': ++ headers = scheme['include'] + else: -+ scheme['headers'] = orig_install._load_schemes()['posix_prefix']['headers'] ++ headers = orig_install.INSTALL_SCHEMES['posix_prefix']['headers'] ++ if name == 'posix_local' and '/local/' not in headers: ++ headers = headers.replace('/include/', '/local/include/') ++ scheme['headers'] = headers + return scheme + + @@ -454,16 +464,32 @@ + return wrapped_load_schemes + + ++def add_debian_schemes(schemes): ++ """ ++ Ensure that the custom schemes we refer to above are present in schemes. ++ """ ++ for name in ('posix_prefix', 'posix_local', 'deb_system'): ++ if name not in schemes: ++ scheme = sysconfig.get_paths(name, expand=False) ++ schemes[name] = _inject_headers(name, scheme) ++ ++ +def apply_customizations(): + orig_install.install = install ++ orig_install_egg_info.install_egg_info = install_egg_info ++ distutils.sysconfig._posix_lib = _posix_lib ++ + if hasattr(orig_install, '_inject_headers'): + # setuptools-bundled distutils >= 60.0.5 + orig_install._inject_headers = _inject_headers -+ else: -+ # Py 3.10 and older ++ elif hasattr(orig_install, '_load_schemes'): ++ # setuptools-bundled distutils >= 59.2.0 + orig_install._load_schemes = load_schemes_wrapper(orig_install._load_schemes) -+ orig_install_egg_info.install_egg_info = install_egg_info -+ distutils.sysconfig._posix_lib = _posix_lib ++ else: ++ # older version with only statically defined schemes ++ # this includes the version bundled with Python 3.10 that has our ++ # schemes already included ++ add_debian_schemes(orig_install.INSTALL_SCHEMES) + + +apply_customizations() diff -Nru python3.10-3.10.3/debian/patches/fix-ia64.diff python3.10-3.10.4/debian/patches/fix-ia64.diff --- python3.10-3.10.3/debian/patches/fix-ia64.diff 1970-01-01 00:00:00.000000000 +0000 +++ python3.10-3.10.4/debian/patches/fix-ia64.diff 2022-04-02 09:04:19.000000000 +0000 @@ -0,0 +1,134 @@ +From 0224b7180b280794b9fba62057b278ffb536c86f Mon Sep 17 00:00:00 2001 +From: Neil Schemenauer +Date: Thu, 21 Oct 2021 14:05:46 -0700 +Subject: [PATCH] bpo-45526: obmalloc radix use 64 addr bits (GH-29062) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Co-authored-by: Łukasz Langa +--- + .../2021-10-19-10-29-47.bpo-45526.WQnvW9.rst | 3 + + Objects/obmalloc.c | 55 ++++++++++++------- + 2 files changed, 38 insertions(+), 20 deletions(-) + create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-10-19-10-29-47.bpo-45526.WQnvW9.rst + +diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c +index 2eddb2cafd..4e17bf44b4 100644 +--- a/Objects/obmalloc.c ++++ b/Objects/obmalloc.c +@@ -1280,21 +1280,30 @@ _Py_GetAllocatedBlocks(void) + + #if WITH_PYMALLOC_RADIX_TREE + /*==========================================================================*/ +-/* radix tree for tracking arena usage ++/* radix tree for tracking arena usage. If enabled, used to implement ++ address_in_range(). + +- bit allocation for keys ++ memory address bit allocation for keys + +- 64-bit pointers and 2^20 arena size: +- 16 -> ignored (POINTER_BITS - ADDRESS_BITS) +- 10 -> MAP_TOP +- 10 -> MAP_MID +- 8 -> MAP_BOT ++ 64-bit pointers, IGNORE_BITS=0 and 2^20 arena size: ++ 15 -> MAP_TOP_BITS ++ 15 -> MAP_MID_BITS ++ 14 -> MAP_BOT_BITS ++ 20 -> ideal aligned arena ++ ---- ++ 64 ++ ++ 64-bit pointers, IGNORE_BITS=16, and 2^20 arena size: ++ 16 -> IGNORE_BITS ++ 10 -> MAP_TOP_BITS ++ 10 -> MAP_MID_BITS ++ 8 -> MAP_BOT_BITS + 20 -> ideal aligned arena + ---- + 64 + + 32-bit pointers and 2^18 arena size: +- 14 -> MAP_BOT ++ 14 -> MAP_BOT_BITS + 18 -> ideal aligned arena + ---- + 32 +@@ -1306,11 +1315,16 @@ _Py_GetAllocatedBlocks(void) + /* number of bits in a pointer */ + #define POINTER_BITS 64 + +-/* Current 64-bit processors are limited to 48-bit physical addresses. For +- * now, the top 17 bits of addresses will all be equal to bit 2**47. If that +- * changes in the future, this must be adjusted upwards. ++/* High bits of memory addresses that will be ignored when indexing into the ++ * radix tree. Setting this to zero is the safe default. For most 64-bit ++ * machines, setting this to 16 would be safe. The kernel would not give ++ * user-space virtual memory addresses that have significant information in ++ * those high bits. The main advantage to setting IGNORE_BITS > 0 is that less ++ * virtual memory will be used for the top and middle radix tree arrays. Those ++ * arrays are allocated in the BSS segment and so will typically consume real ++ * memory only if actually accessed. + */ +-#define ADDRESS_BITS 48 ++#define IGNORE_BITS 0 + + /* use the top and mid layers of the radix tree */ + #define USE_INTERIOR_NODES +@@ -1318,7 +1332,7 @@ _Py_GetAllocatedBlocks(void) + #elif SIZEOF_VOID_P == 4 + + #define POINTER_BITS 32 +-#define ADDRESS_BITS 32 ++#define IGNORE_BITS 0 + + #else + +@@ -1332,6 +1346,9 @@ _Py_GetAllocatedBlocks(void) + # error "arena size must be < 2^32" + #endif + ++/* the lower bits of the address that are not ignored */ ++#define ADDRESS_BITS (POINTER_BITS - IGNORE_BITS) ++ + #ifdef USE_INTERIOR_NODES + /* number of bits used for MAP_TOP and MAP_MID nodes */ + #define INTERIOR_BITS ((ADDRESS_BITS - ARENA_BITS + 2) / 3) +@@ -1360,11 +1377,9 @@ _Py_GetAllocatedBlocks(void) + #define MAP_MID_INDEX(p) ((AS_UINT(p) >> MAP_MID_SHIFT) & MAP_MID_MASK) + #define MAP_TOP_INDEX(p) ((AS_UINT(p) >> MAP_TOP_SHIFT) & MAP_TOP_MASK) + +-#if ADDRESS_BITS > POINTER_BITS +-/* Return non-physical address bits of a pointer. Those bits should be same +- * for all valid pointers if ADDRESS_BITS set correctly. Linux has support for +- * 57-bit address space (Intel 5-level paging) but will not currently give +- * those addresses to user space. ++#if IGNORE_BITS > 0 ++/* Return the ignored part of the pointer address. Those bits should be same ++ * for all valid pointers if IGNORE_BITS is set correctly. + */ + #define HIGH_BITS(p) (AS_UINT(p) >> ADDRESS_BITS) + #else +@@ -1416,7 +1431,7 @@ static arena_map_bot_t * + arena_map_get(block *p, int create) + { + #ifdef USE_INTERIOR_NODES +- /* sanity check that ADDRESS_BITS is correct */ ++ /* sanity check that IGNORE_BITS is correct */ + assert(HIGH_BITS(p) == HIGH_BITS(&arena_map_root)); + int i1 = MAP_TOP_INDEX(p); + if (arena_map_root.ptrs[i1] == NULL) { +@@ -1476,7 +1491,7 @@ arena_map_get(block *p, int create) + static int + arena_map_mark_used(uintptr_t arena_base, int is_used) + { +- /* sanity check that ADDRESS_BITS is correct */ ++ /* sanity check that IGNORE_BITS is correct */ + assert(HIGH_BITS(arena_base) == HIGH_BITS(&arena_map_root)); + arena_map_bot_t *n_hi = arena_map_get((block *)arena_base, is_used); + if (n_hi == NULL) { +-- +2.34.1 + diff -Nru python3.10-3.10.3/debian/patches/series python3.10-3.10.4/debian/patches/series --- python3.10-3.10.3/debian/patches/series 2022-03-16 17:19:40.000000000 +0000 +++ python3.10-3.10.4/debian/patches/series 2022-04-02 09:04:19.000000000 +0000 @@ -38,3 +38,4 @@ destshared-location.diff fix-py_compile.diff reproducible-pyc.diff +fix-ia64.diff diff -Nru python3.10-3.10.3/debian/patches/sysconfig-debian-schemes.diff python3.10-3.10.4/debian/patches/sysconfig-debian-schemes.diff --- python3.10-3.10.3/debian/patches/sysconfig-debian-schemes.diff 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/patches/sysconfig-debian-schemes.diff 2022-03-24 09:38:58.000000000 +0000 @@ -22,9 +22,9 @@ + 'purelib': '{base}/local/lib/python{py_version_short}/dist-packages', + 'platlib': '{platbase}/local/lib/python{py_version_short}/dist-packages', + 'include': -+ '{installed_base}/local/include/python{py_version_short}{abiflags}', ++ '{installed_base}/include/python{py_version_short}{abiflags}', + 'platinclude': -+ '{installed_platbase}/local/include/python{py_version_short}{abiflags}', ++ '{installed_platbase}/include/python{py_version_short}{abiflags}', + 'scripts': '{base}/local/bin', + 'data': '{base}/local', + }, diff -Nru python3.10-3.10.3/debian/PVER-nopie.postrm.in python3.10-3.10.4/debian/PVER-nopie.postrm.in --- python3.10-3.10.3/debian/PVER-nopie.postrm.in 1970-01-01 00:00:00.000000000 +0000 +++ python3.10-3.10.4/debian/PVER-nopie.postrm.in 2022-03-24 10:34:55.000000000 +0000 @@ -0,0 +1,13 @@ +#! /bin/sh + +set -e + +if [ "$1" = "remove" ]; then + dpkg-divert --package @PVER@-nopie \ + --remove --rename \ + --divert /usr/bin/@PVER@-pie /usr/bin/@PVER@ +fi + +#DEBHELPER# + +exit 0 diff -Nru python3.10-3.10.3/debian/PVER-nopie.preinst.in python3.10-3.10.4/debian/PVER-nopie.preinst.in --- python3.10-3.10.3/debian/PVER-nopie.preinst.in 1970-01-01 00:00:00.000000000 +0000 +++ python3.10-3.10.4/debian/PVER-nopie.preinst.in 2022-03-24 10:33:08.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +case "$1" in + install|upgrade) + dpkg-divert --package @PVER@-nopie \ + --add --rename \ + --divert /usr/bin/@PVER@-pie /usr/bin/@PVER@ + ;; + upgrade) + : + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 diff -Nru python3.10-3.10.3/debian/rules python3.10-3.10.4/debian/rules --- python3.10-3.10.3/debian/rules 2022-03-13 06:07:07.000000000 +0000 +++ python3.10-3.10.4/debian/rules 2022-04-02 09:04:19.000000000 +0000 @@ -3,9 +3,6 @@ unexport LANG LC_ALL LC_CTYPE LC_COLLATE LC_TIME LC_NUMERIC LC_MESSAGES unexport CFLAGS CXXFLAGS LDFLAGS CPPFLAGS -export DEB_BUILD_MAINT_OPTIONS=hardening=-pie -dpkg_buildflags = DEB_BUILD_MAINT_OPTIONS=$(DEB_BUILD_MAINT_OPTIONS) dpkg-buildflags - export SHELL = /bin/bash # Uncomment this to turn on verbose mode. @@ -81,6 +78,13 @@ elif dpkg-vendor --derives-from Debian; then echo Debian; \ else echo Unknown; fi) +dpkg_buildflags = DEB_BUILD_MAINT_OPTIONS=hardening=-pie dpkg-buildflags +dpkg_pieflags = DEB_BUILD_MAINT_OPTIONS=hardening=-pie dpkg-buildflags +ifeq (,$(filter $(distrelease),stretch buster bullseye trusty xenial bionic focal impish)) + with_nopie := yes + dpkg_pieflags = dpkg-buildflags +endif + # FIXME: remove sid when uploading to unstable, after bookworm is released #ifneq (,$(filter $(distrelase), jessie stretch buster bullseye bookworm sid precise trusty xenial bionic focal groovy hirsute)) with_dbmmodule = yes @@ -176,6 +180,12 @@ OPT_CFLAGS := $(filter-out -O%,$(DPKG_CFLAGS)) # default is -O3 DEBUG_CFLAGS := $(patsubst -O%,-Og,$(DPKG_CFLAGS)) +DPKG_PIE_CPPFLAGS= $(shell $(dpkg_pieflags) --get CPPFLAGS) +DPKG_PIE_CFLAGS := $(shell $(dpkg_pieflags) --get CFLAGS) +DPKG_PIE_CFLAGS := $(subst -fstack-protector-strong,-fstack-protector,$(DPKG_PIE_CFLAGS)) +DPKG_PIE_LDFLAGS = $(shell $(dpkg_pieflags) --get LDFLAGS) +OPT_PIE_CFLAGS := $(filter-out -O%,$(DPKG_PIE_CFLAGS)) # default is -O3 + ifeq ($(DEB_HOST_ARCH),ia64) DPKG_CPPFLAGS += -DWITH_PYMALLOC_RADIX_TREE=0 endif @@ -251,6 +261,7 @@ make_build_target = $(if $(filter yes, $(with_pgo)),profile-opt) buildd_static := $(CURDIR)/build-static +buildd_nopie := $(CURDIR)/build-nopie buildd_shared := $(CURDIR)/build-shared buildd_debug := $(CURDIR)/build-debug buildd_shdebug := $(CURDIR)/build-shdebug @@ -262,6 +273,7 @@ # package names and directories p_base := $(PVER) +p_npie := $(PVER)-nopie p_min := $(PVER)-minimal p_lib := lib$(PVER) p_tk := $(PVER)-tk @@ -282,6 +294,7 @@ d_base := debian/$(p_base) d_min := debian/$(p_min) +d_npie := debian/$(p_npie) d_lib := debian/$(p_lib) d_tk := debian/$(p_tk) d_dev := debian/$(p_dev) @@ -302,7 +315,9 @@ build-arch: stamps/stamp-build build-indep: stamps/stamp-build-doc build: build-arch -stamps/stamp-build: stamps/stamp-build-static stamps/stamp-mincheck \ +stamps/stamp-build: stamps/stamp-build-static \ + $(if $(filter yes, $(with_nopie)),stamps/stamp-build-nopie) \ + stamps/stamp-mincheck \ stamps/stamp-build-shared stamps/stamp-build-debug \ stamps/stamp-build-shared-debug \ stamps/stamp-check stamps/stamp-pybench @@ -339,7 +354,7 @@ dh_testdir $(MAKE) $(NJOBS) -C $(buildd_static) \ EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" \ - CONFIGURE_LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ + CONFIGURE_LDFLAGS="$(DPKG_PIE_LDFLAGS) $(LTO_CFLAGS)" \ PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) @@ -353,6 +368,24 @@ touch stamps/stamp-build-static +stamps/stamp-build-nopie: stamps/stamp-configure-nopie + dh_testdir + $(MAKE) $(NJOBS) -C $(buildd_nopie) \ + EXTRA_CFLAGS="$(EXTRA_OPT_CFLAGS)" \ + CONFIGURE_LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ + PROFILE_TASK='$(PROFILE_TASK)' $(make_build_target) + +ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) + : # check that things are correctly built + ifneq (,$(filter $(DEB_HOST_ARCH_OS), linux)) + cd $(buildd_nopie) && ./python -c 'from _multiprocessing import SemLock' + endif + cd $(buildd_nopie) && ./python -c 'import _decimal' + cd $(buildd_nopie) && ./python -c 'import math, cmath' +endif + + touch stamps/stamp-build-nopie + run-profile-task: $(MAKE) -C $(buildd_static) \ PROFILE_TASK='$(PROFILE_TASK)' run_profile_task @@ -440,13 +473,26 @@ rm -rf $(buildd_static) mkdir -p $(buildd_static) cd $(buildd_static) && \ + AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(OPT_PIE_CFLAGS)" \ + CPPFLAGS="$(DPKG_PIE_CPPFLAGS)" LDFLAGS="$(DPKG_PIE_LDFLAGS) $(LTO_CFLAGS)" \ + $(config_site) \ + ../configure \ + $(common_configure_args) + + $(call __post_configure,$(buildd_static)) + touch $@ + +stamps/stamp-configure-nopie: stamps/stamp-patch + rm -rf $(buildd_nopie) + mkdir -p $(buildd_nopie) + cd $(buildd_nopie) && \ AR="$(AR)" RANLIB="$(RANLIB)" CFLAGS="$(OPT_CFLAGS)" \ CPPFLAGS="$(DPKG_CPPFLAGS)" LDFLAGS="$(DPKG_LDFLAGS) $(LTO_CFLAGS)" \ $(config_site) \ ../configure \ $(common_configure_args) - $(call __post_configure,$(buildd_static)) + $(call __post_configure,$(buildd_nopie)) touch $@ stamps/stamp-configure-debug: stamps/stamp-patch @@ -785,7 +831,7 @@ $(MAKE) -C Doc clean sed 's/^@/#/' Makefile.pre.in | $(MAKE) -f - srcdir=. distclean - rm -rf $(buildd_static) $(buildd_shared) $(buildd_debug) $(buildd_shdebug) + rm -rf $(buildd_static) $(buildd_shared) $(buildd_debug) $(buildd_shdebug) $(buildd_nopie) find -name '*.py[co]' | xargs -r rm -f rm -f Lib/lib2to3/*.pickle rm -f Lib/dist-packages @@ -1360,6 +1406,12 @@ /$(scriptdir)/sitecustomize.py endif +ifeq ($(with_nopie),yes) + dh_installdirs -p$(p_npie) \ + usr/bin + cp -p $(buildd_nopie)/python $(d_npie)/usr/bin/$(PVER) +endif + for i in debian/*.overrides; do \ b=$$(basename $$i .overrides); \ install -D -m 644 $$i debian/$$b/usr/share/lintian/overrides/$$b; \ diff -Nru python3.10-3.10.3/debian/tests/module-install-local python3.10-3.10.4/debian/tests/module-install-local --- python3.10-3.10.3/debian/tests/module-install-local 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/tests/module-install-local 2022-04-01 15:05:03.000000000 +0000 @@ -64,4 +64,15 @@ assertEquals 'Correct result' 8 "$stdout" } +testFibPyDistutilsLocal() { + cd "$AUTOPKGTEST_TMP/packages/fibpy" + SETUPTOOLS_USE_DISTUTILS=local python3.10 setup.py install + assertTrue 'Install fibpy in /usr/local' $? + assertTrue 'fibpy was installed to /usr/local' "[ -e $dist_packages/fibpy-*.egg ]" + cd "$AUTOPKGTEST_TMP" + stdout=$(python3.10 -m fibpy 5) + assertTrue 'Execute fibpy from /usr/local' $? + assertEquals 'Correct result' 8 "$stdout" +} + . shunit2 diff -Nru python3.10-3.10.3/debian/tests/module-install-user python3.10-3.10.4/debian/tests/module-install-user --- python3.10-3.10.3/debian/tests/module-install-user 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/tests/module-install-user 2022-04-01 15:05:03.000000000 +0000 @@ -66,4 +66,15 @@ assertEquals 'Correct result' 8 "$stdout" } +testFibPyDistutilsLocal() { + cd "$AUTOPKGTEST_TMP/packages/fibpy" + SETUPTOOLS_USE_DISTUTILS=local python3.10 setup.py install --user + assertTrue 'Install fibpy in --user' $? + assertTrue 'fibpy was installed to ~/.local' "[ -e $site_packages/fibpy-*.egg ]" + cd "$AUTOPKGTEST_TMP" + stdout=$(python3.10 -m fibpy 5) + assertTrue 'Execute fibpy from ~/.local' $? + assertEquals 'Correct result' 8 "$stdout" +} + . shunit2 diff -Nru python3.10-3.10.3/debian/tests/module-install-venv python3.10-3.10.4/debian/tests/module-install-venv --- python3.10-3.10.3/debian/tests/module-install-venv 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/tests/module-install-venv 2022-04-01 15:05:03.000000000 +0000 @@ -74,4 +74,15 @@ assertEquals 'Correct result' 8 "$stdout" } +testFibPyDistutilsLocal() { + cd "$AUTOPKGTEST_TMP/packages/fibpy" + SETUPTOOLS_USE_DISTUTILS=local $VP setup.py install + assertTrue 'Install fibpy in a virtualenv' $? + assertTrue 'fibpy was installed to virtualenv' "[ -e $site_packages/fibpy-*.egg ]" + cd "$AUTOPKGTEST_TMP" + stdout=$($VP -m fibpy 5) + assertTrue 'Execute fibpy from a virtualenv' $? + assertEquals 'Correct result' 8 "$stdout" +} + . shunit2 diff -Nru python3.10-3.10.3/debian/tests/module-install-virtualenv python3.10-3.10.4/debian/tests/module-install-virtualenv --- python3.10-3.10.3/debian/tests/module-install-virtualenv 2022-03-14 03:41:27.000000000 +0000 +++ python3.10-3.10.4/debian/tests/module-install-virtualenv 2022-04-01 15:05:03.000000000 +0000 @@ -72,4 +72,15 @@ assertEquals 'Correct result' 8 "$stdout" } +testFibPyDistutilsLocal() { + cd "$AUTOPKGTEST_TMP/packages/fibpy" + SETUPTOOLS_USE_DISTUTILS=local $VP setup.py install + assertTrue 'Install fibpy in a virtualenv' $? + assertTrue 'fibpy was installed to virtualenv' "[ -e $site_packages/fibpy-*.egg ]" + cd "$AUTOPKGTEST_TMP" + stdout=$($VP -m fibpy 5) + assertTrue 'Execute fibpy from a virtualenv' $? + assertEquals 'Correct result' 8 "$stdout" +} + . shunit2 diff -Nru python3.10-3.10.3/Doc/library/aifc.rst python3.10-3.10.4/Doc/library/aifc.rst --- python3.10-3.10.3/Doc/library/aifc.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/aifc.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: aifc :synopsis: Read and write audio files in AIFF or AIFC format. + :deprecated: **Source code:** :source:`Lib/aifc.py` @@ -11,6 +12,10 @@ single: AIFF single: AIFF-C + +.. deprecated:: 3.11 + The :mod:`aifc` module is deprecated (see :pep:`594` for details). + -------------- This module provides support for reading and writing AIFF and AIFF-C files. diff -Nru python3.10-3.10.3/Doc/library/asynchat.rst python3.10-3.10.4/Doc/library/asynchat.rst --- python3.10-3.10.3/Doc/library/asynchat.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/asynchat.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: asynchat :synopsis: Support for asynchronous command/response protocols. + :deprecated: .. moduleauthor:: Sam Rushing .. sectionauthor:: Steve Holden @@ -10,6 +11,7 @@ **Source code:** :source:`Lib/asynchat.py` .. deprecated:: 3.6 + :mod:`asynchat` will be removed in Python 3.12 (:pep:`594`). Please use :mod:`asyncio` instead. -------------- diff -Nru python3.10-3.10.3/Doc/library/asyncore.rst python3.10-3.10.4/Doc/library/asyncore.rst --- python3.10-3.10.3/Doc/library/asyncore.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/asyncore.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,6 +4,7 @@ .. module:: asyncore :synopsis: A base class for developing asynchronous socket handling services. + :deprecated: .. moduleauthor:: Sam Rushing .. sectionauthor:: Christopher Petrilli @@ -13,6 +14,7 @@ **Source code:** :source:`Lib/asyncore.py` .. deprecated:: 3.6 + :mod:`asyncore` will be removed in Python 3.12 (:pep:`594`). Please use :mod:`asyncio` instead. -------------- diff -Nru python3.10-3.10.3/Doc/library/audioop.rst python3.10-3.10.4/Doc/library/audioop.rst --- python3.10-3.10.3/Doc/library/audioop.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/audioop.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,10 @@ .. module:: audioop :synopsis: Manipulate raw audio data. + :deprecated: + +.. deprecated:: 3.11 + The :mod:`audioop` module is deprecated (see :pep:`594` for details). -------------- diff -Nru python3.10-3.10.3/Doc/library/binascii.rst python3.10-3.10.4/Doc/library/binascii.rst --- python3.10-3.10.3/Doc/library/binascii.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/binascii.rst 2022-03-23 20:12:04.000000000 +0000 @@ -135,7 +135,7 @@ .. function:: crc32(data[, value]) - Compute CRC-32, the 32-bit checksum of *data*, starting with an + Compute CRC-32, the unsigned 32-bit checksum of *data*, starting with an initial CRC of *value*. The default initial CRC is zero. The algorithm is consistent with the ZIP file checksum. Since the algorithm is designed for use as a checksum algorithm, it is not suitable for use as a general hash @@ -149,9 +149,8 @@ .. versionchanged:: 3.0 The result is always unsigned. - To generate the same numeric value across all Python versions and - platforms, use ``crc32(data) & 0xffffffff``. - + To generate the same numeric value when using Python 2 or earlier, + use ``crc32(data) & 0xffffffff``. .. function:: b2a_hex(data[, sep[, bytes_per_sep=1]]) hexlify(data[, sep[, bytes_per_sep=1]]) diff -Nru python3.10-3.10.3/Doc/library/cgi.rst python3.10-3.10.4/Doc/library/cgi.rst --- python3.10-3.10.3/Doc/library/cgi.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/cgi.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: cgi :synopsis: Helpers for running Python scripts via the Common Gateway Interface. + :deprecated: **Source code:** :source:`Lib/cgi.py` @@ -14,6 +15,9 @@ single: URL single: Common Gateway Interface +.. deprecated:: 3.11 + The :mod:`cgi` module is deprecated (see :pep:`594` for details). + -------------- Support module for Common Gateway Interface (CGI) scripts. diff -Nru python3.10-3.10.3/Doc/library/cgitb.rst python3.10-3.10.4/Doc/library/cgitb.rst --- python3.10-3.10.3/Doc/library/cgitb.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/cgitb.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: cgitb :synopsis: Configurable traceback handler for CGI scripts. + :deprecated: .. moduleauthor:: Ka-Ping Yee .. sectionauthor:: Fred L. Drake, Jr. @@ -15,6 +16,9 @@ single: exceptions; in CGI scripts single: tracebacks; in CGI scripts +.. deprecated:: 3.11 + The :mod:`cgitb` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`cgitb` module provides a special exception handler for Python scripts. diff -Nru python3.10-3.10.3/Doc/library/chunk.rst python3.10-3.10.4/Doc/library/chunk.rst --- python3.10-3.10.3/Doc/library/chunk.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/chunk.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: chunk :synopsis: Module to read IFF chunks. + :deprecated: .. moduleauthor:: Sjoerd Mullender .. sectionauthor:: Sjoerd Mullender @@ -16,6 +17,9 @@ single: Real Media File Format single: RMFF +.. deprecated:: 3.11 + The :mod:`chunk` module is deprecated (see :pep:`594` for details). + -------------- This module provides an interface for reading files that use EA IFF 85 chunks. diff -Nru python3.10-3.10.3/Doc/library/configparser.rst python3.10-3.10.4/Doc/library/configparser.rst --- python3.10-3.10.3/Doc/library/configparser.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/configparser.rst 2022-03-23 20:12:04.000000000 +0000 @@ -347,7 +347,8 @@ my_pictures: %(my_dir)s/Pictures [Escape] - gain: 80%% # use a %% to escape the % sign (% is the only character that needs to be escaped) + # use a %% to escape the % sign (% is the only character that needs to be escaped): + gain: 80%% In the example above, :class:`ConfigParser` with *interpolation* set to ``BasicInterpolation()`` would resolve ``%(home_dir)s`` to the value of @@ -382,7 +383,8 @@ my_pictures: ${my_dir}/Pictures [Escape] - cost: $$80 # use a $$ to escape the $ sign ($ is the only character that needs to be escaped) + # use a $$ to escape the $ sign ($ is the only character that needs to be escaped): + cost: $$80 Values from other sections can be fetched as well: diff -Nru python3.10-3.10.3/Doc/library/crypt.rst python3.10-3.10.4/Doc/library/crypt.rst --- python3.10-3.10.3/Doc/library/crypt.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/crypt.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,6 +4,7 @@ .. module:: crypt :platform: Unix :synopsis: The crypt() function used to check Unix passwords. + :deprecated: .. moduleauthor:: Steven D. Majewski .. sectionauthor:: Steven D. Majewski @@ -15,6 +16,9 @@ single: crypt(3) pair: cipher; DES +.. deprecated:: 3.11 + The :mod:`crypt` module is deprecated (see :pep:`594` for details). + -------------- This module implements an interface to the :manpage:`crypt(3)` routine, which is diff -Nru python3.10-3.10.3/Doc/library/fileformats.rst python3.10-3.10.4/Doc/library/fileformats.rst --- python3.10-3.10.3/Doc/library/fileformats.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/fileformats.rst 2022-03-23 20:12:04.000000000 +0000 @@ -13,5 +13,4 @@ csv.rst configparser.rst netrc.rst - xdrlib.rst plistlib.rst diff -Nru python3.10-3.10.3/Doc/library/imghdr.rst python3.10-3.10.4/Doc/library/imghdr.rst --- python3.10-3.10.3/Doc/library/imghdr.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/imghdr.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,9 +3,13 @@ .. module:: imghdr :synopsis: Determine the type of image contained in a file or byte stream. + :deprecated: **Source code:** :source:`Lib/imghdr.py` +.. deprecated:: 3.11 + The :mod:`imghdr` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`imghdr` module determines the type of image contained in a file or diff -Nru python3.10-3.10.3/Doc/library/internet.rst python3.10-3.10.4/Doc/library/internet.rst --- python3.10-3.10.3/Doc/library/internet.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/internet.rst 2022-03-23 20:12:04.000000000 +0000 @@ -20,8 +20,6 @@ .. toctree:: webbrowser.rst - cgi.rst - cgitb.rst wsgiref.rst urllib.rst urllib.request.rst @@ -33,10 +31,7 @@ ftplib.rst poplib.rst imaplib.rst - nntplib.rst smtplib.rst - smtpd.rst - telnetlib.rst uuid.rst socketserver.rst http.server.rst diff -Nru python3.10-3.10.3/Doc/library/ipc.rst python3.10-3.10.4/Doc/library/ipc.rst --- python3.10-3.10.3/Doc/library/ipc.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/ipc.rst 2022-03-23 20:12:04.000000000 +0000 @@ -22,7 +22,5 @@ ssl.rst select.rst selectors.rst - asyncore.rst - asynchat.rst signal.rst mmap.rst diff -Nru python3.10-3.10.3/Doc/library/mm.rst python3.10-3.10.4/Doc/library/mm.rst --- python3.10-3.10.3/Doc/library/mm.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/mm.rst 2022-03-23 20:12:04.000000000 +0000 @@ -11,12 +11,5 @@ .. toctree:: - audioop.rst - aifc.rst - sunau.rst wave.rst - chunk.rst colorsys.rst - imghdr.rst - sndhdr.rst - ossaudiodev.rst diff -Nru python3.10-3.10.3/Doc/library/msilib.rst python3.10-3.10.4/Doc/library/msilib.rst --- python3.10-3.10.3/Doc/library/msilib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/msilib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,6 +4,7 @@ .. module:: msilib :platform: Windows :synopsis: Creation of Microsoft Installer files, and CAB files. + :deprecated: .. moduleauthor:: Martin v. Löwis .. sectionauthor:: Martin v. Löwis @@ -12,6 +13,9 @@ .. index:: single: msi +.. deprecated:: 3.11 + The :mod:`msilib` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`msilib` supports the creation of Microsoft Installer (``.msi``) files. diff -Nru python3.10-3.10.3/Doc/library/netdata.rst python3.10-3.10.4/Doc/library/netdata.rst --- python3.10-3.10.3/Doc/library/netdata.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/netdata.rst 2022-03-23 20:12:04.000000000 +0000 @@ -20,4 +20,3 @@ binhex.rst binascii.rst quopri.rst - uu.rst diff -Nru python3.10-3.10.3/Doc/library/nis.rst python3.10-3.10.4/Doc/library/nis.rst --- python3.10-3.10.3/Doc/library/nis.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/nis.rst 2022-03-23 20:12:04.000000000 +0000 @@ -5,10 +5,14 @@ .. module:: nis :platform: Unix :synopsis: Interface to Sun's NIS (Yellow Pages) library. + :deprecated: .. moduleauthor:: Fred Gansevles .. sectionauthor:: Moshe Zadka +.. deprecated:: 3.11 + The :mod:`nis` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`nis` module gives a thin wrapper around the NIS library, useful for diff -Nru python3.10-3.10.3/Doc/library/nntplib.rst python3.10-3.10.4/Doc/library/nntplib.rst --- python3.10-3.10.3/Doc/library/nntplib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/nntplib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: nntplib :synopsis: NNTP protocol client (requires sockets). + :deprecated: **Source code:** :source:`Lib/nntplib.py` @@ -10,6 +11,9 @@ pair: NNTP; protocol single: Network News Transfer Protocol +.. deprecated:: 3.11 + The :mod:`nntplib` module is deprecated (see :pep:`594` for details). + -------------- This module defines the class :class:`NNTP` which implements the client side of diff -Nru python3.10-3.10.3/Doc/library/ossaudiodev.rst python3.10-3.10.4/Doc/library/ossaudiodev.rst --- python3.10-3.10.3/Doc/library/ossaudiodev.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/ossaudiodev.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,6 +4,10 @@ .. module:: ossaudiodev :platform: Linux, FreeBSD :synopsis: Access to OSS-compatible audio devices. + :deprecated: + +.. deprecated:: 3.11 + The :mod:`ossaudiodev` module is deprecated (see :pep:`594` for details). -------------- diff -Nru python3.10-3.10.3/Doc/library/pathlib.rst python3.10-3.10.4/Doc/library/pathlib.rst --- python3.10-3.10.3/Doc/library/pathlib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/pathlib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -914,7 +914,7 @@ The children are yielded in arbitrary order, and the special entries ``'.'`` and ``'..'`` are not included. If a file is removed from or added - to the directory after creating the iterator, whether an path object for + to the directory after creating the iterator, whether a path object for that file be included is unspecified. .. method:: Path.lchmod(mode) diff -Nru python3.10-3.10.3/Doc/library/pipes.rst python3.10-3.10.4/Doc/library/pipes.rst --- python3.10-3.10.3/Doc/library/pipes.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/pipes.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,11 +4,15 @@ .. module:: pipes :platform: Unix :synopsis: A Python interface to Unix shell pipelines. + :deprecated: .. sectionauthor:: Moshe Zadka **Source code:** :source:`Lib/pipes.py` +.. deprecated:: 3.11 + The :mod:`pipes` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`pipes` module defines a class to abstract the concept of a *pipeline* diff -Nru python3.10-3.10.3/Doc/library/smtpd.rst python3.10-3.10.4/Doc/library/smtpd.rst --- python3.10-3.10.3/Doc/library/smtpd.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/smtpd.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: smtpd :synopsis: A SMTP server implementation in Python. + :deprecated: .. moduleauthor:: Barry Warsaw .. sectionauthor:: Moshe Zadka @@ -14,6 +15,7 @@ This module offers several classes to implement SMTP (email) servers. .. deprecated:: 3.6 + :mod:`smtpd` will be removed in Python 3.12 (:pep:`594`). The `aiosmtpd `_ package is a recommended replacement for this module. It is based on :mod:`asyncio` and provides a more straightforward API. diff -Nru python3.10-3.10.3/Doc/library/sndhdr.rst python3.10-3.10.4/Doc/library/sndhdr.rst --- python3.10-3.10.3/Doc/library/sndhdr.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/sndhdr.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: sndhdr :synopsis: Determine type of a sound file. + :deprecated: .. sectionauthor:: Fred L. Drake, Jr. .. Based on comments in the module source file. @@ -13,6 +14,9 @@ single: A-LAW single: u-LAW +.. deprecated:: 3.11 + The :mod:`sndhdr` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`sndhdr` provides utility functions which attempt to determine the type diff -Nru python3.10-3.10.3/Doc/library/spwd.rst python3.10-3.10.4/Doc/library/spwd.rst --- python3.10-3.10.3/Doc/library/spwd.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/spwd.rst 2022-03-23 20:12:04.000000000 +0000 @@ -4,6 +4,10 @@ .. module:: spwd :platform: Unix :synopsis: The shadow password database (getspnam() and friends). + :deprecated: + +.. deprecated:: 3.11 + The :mod:`spwd` module is deprecated (see :pep:`594` for details). -------------- diff -Nru python3.10-3.10.3/Doc/library/sunau.rst python3.10-3.10.4/Doc/library/sunau.rst --- python3.10-3.10.3/Doc/library/sunau.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/sunau.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,11 +3,15 @@ .. module:: sunau :synopsis: Provide an interface to the Sun AU sound format. + :deprecated: .. sectionauthor:: Moshe Zadka **Source code:** :source:`Lib/sunau.py` +.. deprecated:: 3.11 + The :mod:`sunau` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`sunau` module provides a convenient interface to the Sun AU sound diff -Nru python3.10-3.10.3/Doc/library/superseded.rst python3.10-3.10.4/Doc/library/superseded.rst --- python3.10-3.10.3/Doc/library/superseded.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/superseded.rst 2022-03-23 20:12:04.000000000 +0000 @@ -10,5 +10,26 @@ .. toctree:: - optparse.rst + aifc.rst + asynchat.rst + asyncore.rst + audioop.rst + cgi.rst + cgitb.rst + chunk.rst + crypt.rst + imghdr.rst imp.rst + msilib.rst + nntplib.rst + nis.rst + optparse.rst + ossaudiodev.rst + pipes.rst + smtpd.rst + sndhdr.rst + spwd.rst + sunau.rst + telnetlib.rst + uu.rst + xdrlib.rst diff -Nru python3.10-3.10.3/Doc/library/telnetlib.rst python3.10-3.10.4/Doc/library/telnetlib.rst --- python3.10-3.10.3/Doc/library/telnetlib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/telnetlib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: telnetlib :synopsis: Telnet client class. + :deprecated: .. sectionauthor:: Skip Montanaro @@ -10,6 +11,9 @@ .. index:: single: protocol; Telnet +.. deprecated:: 3.11 + The :mod:`telnetlib` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`telnetlib` module provides a :class:`Telnet` class that implements the diff -Nru python3.10-3.10.3/Doc/library/tempfile.rst python3.10-3.10.4/Doc/library/tempfile.rst --- python3.10-3.10.3/Doc/library/tempfile.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/tempfile.rst 2022-03-23 20:12:04.000000000 +0000 @@ -96,9 +96,9 @@ Added *errors* parameter. -.. function:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None) +.. class:: SpooledTemporaryFile(max_size=0, mode='w+b', buffering=-1, encoding=None, newline=None, suffix=None, prefix=None, dir=None, *, errors=None) - This function operates exactly as :func:`TemporaryFile` does, except that + This class operates exactly as :func:`TemporaryFile` does, except that data is spooled in memory until the file size exceeds *max_size*, or until the file's :func:`fileno` method is called, at which point the contents are written to disk and operation proceeds as with @@ -121,9 +121,9 @@ Added *errors* parameter. -.. function:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False) +.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False) - This function securely creates a temporary directory using the same rules as :func:`mkdtemp`. + This class securely creates a temporary directory using the same rules as :func:`mkdtemp`. The resulting object can be used as a context manager (see :ref:`tempfile-examples`). On completion of the context or destruction of the temporary directory object, the newly created temporary directory diff -Nru python3.10-3.10.3/Doc/library/textwrap.rst python3.10-3.10.4/Doc/library/textwrap.rst --- python3.10-3.10.3/Doc/library/textwrap.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/textwrap.rst 2022-03-23 20:12:04.000000000 +0000 @@ -21,7 +21,8 @@ subsequent_indent="", expand_tabs=True, \ replace_whitespace=True, fix_sentence_endings=False, \ break_long_words=True, drop_whitespace=True, \ - break_on_hyphens=True, tabsize=8, max_lines=None) + break_on_hyphens=True, tabsize=8, max_lines=None, \ + placeholder=' [...]') Wraps the single paragraph in *text* (a string) so every line is at most *width* characters long. Returns a list of output lines, without final @@ -39,7 +40,7 @@ replace_whitespace=True, fix_sentence_endings=False, \ break_long_words=True, drop_whitespace=True, \ break_on_hyphens=True, tabsize=8, \ - max_lines=None) + max_lines=None, placeholder=' [...]') Wraps the single paragraph in *text*, and returns a single string containing the wrapped paragraph. :func:`fill` is shorthand for :: diff -Nru python3.10-3.10.3/Doc/library/typing.rst python3.10-3.10.4/Doc/library/typing.rst --- python3.10-3.10.3/Doc/library/typing.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/typing.rst 2022-03-23 20:12:04.000000000 +0000 @@ -247,7 +247,7 @@ def notify_by_email(employees: Sequence[Employee], overrides: Mapping[str, str]) -> None: ... -Generics can be parameterized by using a new factory available in typing +Generics can be parameterized by using a factory available in typing called :class:`TypeVar`. :: @@ -304,16 +304,16 @@ for var in vars: var.set(0) -A generic type can have any number of type variables, and type variables may -be constrained:: +A generic type can have any number of type variables. All varieties of +:class:`TypeVar` are permissible as parameters for a generic type:: - from typing import TypeVar, Generic - ... + from typing import TypeVar, Generic, Sequence - T = TypeVar('T') + T = TypeVar('T', contravariant=True) + B = TypeVar('B', bound=Sequence[bytes], covariant=True) S = TypeVar('S', int, str) - class StrangePair(Generic[T, S]): + class WeirdTrio(Generic[T, B, S]): ... Each type variable argument to :class:`Generic` must be distinct. @@ -1084,7 +1084,8 @@ Usage:: T = TypeVar('T') # Can be anything - A = TypeVar('A', str, bytes) # Must be str or bytes + S = TypeVar('S', bound=str) # Can be any subtype of str + A = TypeVar('A', str, bytes) # Must be exactly str or bytes Type variables exist primarily for the benefit of static type checkers. They serve as the parameters for generic types as well @@ -1095,25 +1096,91 @@ """Return a list containing n references to x.""" return [x]*n - def longest(x: A, y: A) -> A: - """Return the longest of two strings.""" - return x if len(x) >= len(y) else y - - The latter example's signature is essentially the overloading - of ``(str, str) -> str`` and ``(bytes, bytes) -> bytes``. Also note - that if the arguments are instances of some subclass of :class:`str`, - the return type is still plain :class:`str`. + + def print_capitalized(x: S) -> S: + """Print x capitalized, and return x.""" + print(x.capitalize()) + return x + + + def concatenate(x: A, y: A) -> A: + """Add two strings or bytes objects together.""" + return x + y + + Note that type variables can be *bound*, *constrained*, or neither, but + cannot be both bound *and* constrained. + + Constrained type variables and bound type variables have different + semantics in several important ways. Using a *constrained* type variable + means that the ``TypeVar`` can only ever be solved as being exactly one of + the constraints given:: + + a = concatenate('one', 'two') # Ok, variable 'a' has type 'str' + b = concatenate(StringSubclass('one'), StringSubclass('two')) # Inferred type of variable 'b' is 'str', + # despite 'StringSubclass' being passed in + c = concatenate('one', b'two') # error: type variable 'A' can be either 'str' or 'bytes' in a function call, but not both + + Using a *bound* type variable, however, means that the ``TypeVar`` will be + solved using the most specific type possible:: + + print_capitalized('a string') # Ok, output has type 'str' + + class StringSubclass(str): + pass + + print_capitalized(StringSubclass('another string')) # Ok, output has type 'StringSubclass' + print_capitalized(45) # error: int is not a subtype of str + + Type variables can be bound to concrete types, abstract types (ABCs or + protocols), and even unions of types:: + + U = TypeVar('U', bound=str|bytes) # Can be any subtype of the union str|bytes + V = TypeVar('V', bound=SupportsAbs) # Can be anything with an __abs__ method + + Bound type variables are particularly useful for annotating + :func:`classmethods ` that serve as alternative constructors. + In the following example (© + `Raymond Hettinger `_), the + type variable ``C`` is bound to the ``Circle`` class through the use of a + forward reference. Using this type variable to annotate the + ``with_circumference`` classmethod, rather than hardcoding the return type + as ``Circle``, means that a type checker can correctly infer the return + type even if the method is called on a subclass:: + + import math + + C = TypeVar('C', bound='Circle') + + class Circle: + """An abstract circle""" + + def __init__(self, radius: float) -> None: + self.radius = radius + + # Use a type variable to show that the return type + # will always be an instance of whatever `cls` is + @classmethod + def with_circumference(cls: type[C], circumference: float) -> C: + """Create a circle with the specified circumference""" + radius = circumference / (math.pi * 2) + return cls(radius) + + + class Tire(Circle): + """A specialised circle (made out of rubber)""" + + MATERIAL = 'rubber' + + + c = Circle.with_circumference(3) # Ok, variable 'c' has type 'Circle' + t = Tire.with_circumference(4) # Ok, variable 't' has type 'Tire' (not 'Circle') At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`. In general, :func:`isinstance` and :func:`issubclass` should not be used with types. Type variables may be marked covariant or contravariant by passing ``covariant=True`` or ``contravariant=True``. See :pep:`484` for more - details. By default type variables are invariant. Alternatively, - a type variable may specify an upper bound using ``bound=``. - This means that an actual type substituted (explicitly or implicitly) - for the type variable must be a subclass of the boundary type, - see :pep:`484`. + details. By default, type variables are invariant. .. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False) @@ -1215,7 +1282,7 @@ .. data:: AnyStr - ``AnyStr`` is a type variable defined as + ``AnyStr`` is a :class:`constrained type variable ` defined as ``AnyStr = TypeVar('AnyStr', str, bytes)``. It is meant to be used for functions that may accept any kind of string diff -Nru python3.10-3.10.3/Doc/library/unix.rst python3.10-3.10.4/Doc/library/unix.rst --- python3.10-3.10.3/Doc/library/unix.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/unix.rst 2022-03-23 20:12:04.000000000 +0000 @@ -13,14 +13,10 @@ posix.rst pwd.rst - spwd.rst grp.rst - crypt.rst termios.rst tty.rst pty.rst fcntl.rst - pipes.rst resource.rst - nis.rst syslog.rst diff -Nru python3.10-3.10.3/Doc/library/uu.rst python3.10-3.10.4/Doc/library/uu.rst --- python3.10-3.10.3/Doc/library/uu.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/uu.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,11 +3,15 @@ .. module:: uu :synopsis: Encode and decode files in uuencode format. + :deprecated: .. moduleauthor:: Lance Ellinghouse **Source code:** :source:`Lib/uu.py` +.. deprecated:: 3.11 + The :mod:`uu` module is deprecated (see :pep:`594` for details). + -------------- This module encodes and decodes files in uuencode format, allowing arbitrary diff -Nru python3.10-3.10.3/Doc/library/windows.rst python3.10-3.10.4/Doc/library/windows.rst --- python3.10-3.10.3/Doc/library/windows.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/windows.rst 2022-03-23 20:12:04.000000000 +0000 @@ -9,7 +9,6 @@ .. toctree:: - msilib.rst msvcrt.rst winreg.rst winsound.rst diff -Nru python3.10-3.10.3/Doc/library/xdrlib.rst python3.10-3.10.4/Doc/library/xdrlib.rst --- python3.10-3.10.3/Doc/library/xdrlib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/xdrlib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -3,6 +3,7 @@ .. module:: xdrlib :synopsis: Encoders and decoders for the External Data Representation (XDR). + :deprecated: **Source code:** :source:`Lib/xdrlib.py` @@ -10,6 +11,9 @@ single: XDR single: External Data Representation +.. deprecated:: 3.11 + The :mod:`xdrlib` module is deprecated (see :pep:`594` for details). + -------------- The :mod:`xdrlib` module supports the External Data Representation Standard as diff -Nru python3.10-3.10.3/Doc/library/zlib.rst python3.10-3.10.4/Doc/library/zlib.rst --- python3.10-3.10.3/Doc/library/zlib.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/library/zlib.rst 2022-03-23 20:12:04.000000000 +0000 @@ -42,10 +42,9 @@ for use as a general hash algorithm. .. versionchanged:: 3.0 - Always returns an unsigned value. - To generate the same numeric value across all Python versions and - platforms, use ``adler32(data) & 0xffffffff``. - + The result is always unsigned. + To generate the same numeric value when using Python 2 or earlier, + use ``adler32(data) & 0xffffffff``. .. function:: compress(data, /, level=-1) @@ -127,10 +126,9 @@ for use as a general hash algorithm. .. versionchanged:: 3.0 - Always returns an unsigned value. - To generate the same numeric value across all Python versions and - platforms, use ``crc32(data) & 0xffffffff``. - + The result is always unsigned. + To generate the same numeric value when using Python 2 or earlier, + use ``crc32(data) & 0xffffffff``. .. function:: decompress(data, /, wbits=MAX_WBITS, bufsize=DEF_BUF_SIZE) diff -Nru python3.10-3.10.3/Doc/reference/compound_stmts.rst python3.10-3.10.4/Doc/reference/compound_stmts.rst --- python3.10-3.10.3/Doc/reference/compound_stmts.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/reference/compound_stmts.rst 2022-03-23 20:12:04.000000000 +0000 @@ -233,9 +233,10 @@ present, must be last; it matches any exception. For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is "compatible" with the exception. An object is -compatible with an exception if it is the class or a base class of the exception -object, or a tuple containing an item that is the class or a base class of -the exception object. +compatible with an exception if the object is the class or a +:term:`non-virtual base class ` of the exception object, +or a tuple containing an item that is the class or a non-virtual base class +of the exception object. If no except clause matches the exception, the search for an exception handler continues in the surrounding code and on the invocation stack. [#]_ diff -Nru python3.10-3.10.3/Doc/reference/datamodel.rst python3.10-3.10.4/Doc/reference/datamodel.rst --- python3.10-3.10.3/Doc/reference/datamodel.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/reference/datamodel.rst 2022-03-23 20:12:04.000000000 +0000 @@ -1466,7 +1466,7 @@ Called by built-in function :func:`hash` and for operations on members of hashed collections including :class:`set`, :class:`frozenset`, and - :class:`dict`. :meth:`__hash__` should return an integer. The only required + :class:`dict`. The ``__hash__()`` method should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to mix together the hash values of the components of the object that also play a part in comparison of objects by packing them into a tuple and diff -Nru python3.10-3.10.3/Doc/reference/executionmodel.rst python3.10-3.10.4/Doc/reference/executionmodel.rst --- python3.10-3.10.3/Doc/reference/executionmodel.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/reference/executionmodel.rst 2022-03-23 20:12:04.000000000 +0000 @@ -259,8 +259,9 @@ Exceptions are identified by class instances. The :keyword:`except` clause is selected depending on the class of the instance: it must reference the class of -the instance or a base class thereof. The instance can be received by the -handler and can carry additional information about the exceptional condition. +the instance or a :term:`non-virtual base class ` thereof. +The instance can be received by the handler and can carry additional information +about the exceptional condition. .. note:: diff -Nru python3.10-3.10.3/Doc/tools/susp-ignored.csv python3.10-3.10.4/Doc/tools/susp-ignored.csv --- python3.10-3.10.3/Doc/tools/susp-ignored.csv 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Doc/tools/susp-ignored.csv 2022-03-23 20:12:04.000000000 +0000 @@ -384,3 +384,4 @@ library/typing,,`,"# Else, type of ``val`` is narrowed to ``float``." library/typing,,`,# Type of ``val`` is narrowed to ``List[str]``. library/typing,,`,# Type of ``val`` remains as ``List[object]``. +library/typing,,`, # will always be an instance of whatever `cls` is diff -Nru python3.10-3.10.3/Include/patchlevel.h python3.10-3.10.4/Include/patchlevel.h --- python3.10-3.10.3/Include/patchlevel.h 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Include/patchlevel.h 2022-03-23 20:12:04.000000000 +0000 @@ -18,12 +18,12 @@ /*--start constants--*/ #define PY_MAJOR_VERSION 3 #define PY_MINOR_VERSION 10 -#define PY_MICRO_VERSION 3 +#define PY_MICRO_VERSION 4 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "3.10.3" +#define PY_VERSION "3.10.4" /*--end constants--*/ /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. diff -Nru python3.10-3.10.3/Lib/asynchat.py python3.10-3.10.4/Lib/asynchat.py --- python3.10-3.10.3/Lib/asynchat.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/asynchat.py 2022-03-23 20:12:04.000000000 +0000 @@ -50,7 +50,7 @@ from warnings import warn warn( - 'The asynchat module is deprecated. ' + 'The asynchat module is deprecated and will be removed in Python 3.12. ' 'The recommended replacement is asyncio', DeprecationWarning, stacklevel=2) diff -Nru python3.10-3.10.3/Lib/asyncio/locks.py python3.10-3.10.4/Lib/asyncio/locks.py --- python3.10-3.10.3/Lib/asyncio/locks.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/asyncio/locks.py 2022-03-23 20:12:04.000000000 +0000 @@ -6,6 +6,7 @@ from . import exceptions from . import mixins +from . import tasks class _ContextManagerMixin: @@ -350,6 +351,7 @@ raise ValueError("Semaphore initial value must be >= 0") self._value = value self._waiters = collections.deque() + self._wakeup_scheduled = False def __repr__(self): res = super().__repr__() @@ -363,6 +365,7 @@ waiter = self._waiters.popleft() if not waiter.done(): waiter.set_result(None) + self._wakeup_scheduled = True return def locked(self): @@ -378,16 +381,17 @@ called release() to make it larger than 0, and then return True. """ - while self._value <= 0: + # _wakeup_scheduled is set if *another* task is scheduled to wakeup + # but its acquire() is not resumed yet + while self._wakeup_scheduled or self._value <= 0: fut = self._get_loop().create_future() self._waiters.append(fut) try: await fut - except: - # See the similar code in Queue.get. - fut.cancel() - if self._value > 0 and not fut.cancelled(): - self._wake_up_next() + # reset _wakeup_scheduled *after* waiting for a future + self._wakeup_scheduled = False + except exceptions.CancelledError: + self._wake_up_next() raise self._value -= 1 return True diff -Nru python3.10-3.10.3/Lib/asyncore.py python3.10-3.10.4/Lib/asyncore.py --- python3.10-3.10.3/Lib/asyncore.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/asyncore.py 2022-03-23 20:12:04.000000000 +0000 @@ -58,7 +58,7 @@ errorcode warnings.warn( - 'The asyncore module is deprecated. ' + 'The asyncore module is deprecated and will be removed in Python 3.12. ' 'The recommended replacement is asyncio', DeprecationWarning, stacklevel=2) diff -Nru python3.10-3.10.3/Lib/doctest.py python3.10-3.10.4/Lib/doctest.py --- python3.10-3.10.3/Lib/doctest.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/doctest.py 2022-03-23 20:12:04.000000000 +0000 @@ -2171,6 +2171,7 @@ unittest.TestCase.__init__(self) self._dt_optionflags = optionflags self._dt_checker = checker + self._dt_globs = test.globs.copy() self._dt_test = test self._dt_setUp = setUp self._dt_tearDown = tearDown @@ -2187,7 +2188,9 @@ if self._dt_tearDown is not None: self._dt_tearDown(test) + # restore the original globs test.globs.clear() + test.globs.update(self._dt_globs) def runTest(self): test = self._dt_test diff -Nru python3.10-3.10.3/Lib/pydoc_data/topics.py python3.10-3.10.4/Lib/pydoc_data/topics.py --- python3.10-3.10.3/Lib/pydoc_data/topics.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/pydoc_data/topics.py 2022-03-23 20:12:04.000000000 +0000 @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Autogenerated by Sphinx on Wed Mar 16 11:26:55 2022 +# Autogenerated by Sphinx on Wed Mar 23 20:11:40 2022 topics = {'assert': 'The "assert" statement\n' '**********************\n' '\n' @@ -2418,11 +2418,11 @@ 'resulting\n' 'object is “compatible” with the exception. An object is ' 'compatible\n' - 'with an exception if it is the class or a base class of the ' - 'exception\n' - 'object, or a tuple containing an item that is the class or a ' + 'with an exception if the object is the class or a *non-virtual ' 'base\n' - 'class of the exception object.\n' + 'class* of the exception object, or a tuple containing an item ' + 'that is\n' + 'the class or a non-virtual base class of the exception object.\n' '\n' 'If no except clause matches the exception, the search for an ' 'exception\n' @@ -4399,15 +4399,17 @@ 'on members\n' ' of hashed collections including "set", "frozenset", and ' '"dict".\n' - ' "__hash__()" should return an integer. The only required ' - 'property\n' - ' is that objects which compare equal have the same hash ' - 'value; it is\n' - ' advised to mix together the hash values of the ' - 'components of the\n' - ' object that also play a part in comparison of objects by ' - 'packing\n' - ' them into a tuple and hashing the tuple. Example:\n' + ' The "__hash__()" method should return an integer. The ' + 'only required\n' + ' property is that objects which compare equal have the ' + 'same hash\n' + ' value; it is advised to mix together the hash values of ' + 'the\n' + ' components of the object that also play a part in ' + 'comparison of\n' + ' objects by packing them into a tuple and hashing the ' + 'tuple.\n' + ' Example:\n' '\n' ' def __hash__(self):\n' ' return hash((self.name, self.nick, self.color))\n' @@ -5391,11 +5393,11 @@ 'clause is\n' 'selected depending on the class of the instance: it must ' 'reference the\n' - 'class of the instance or a base class thereof. The instance ' - 'can be\n' - 'received by the handler and can carry additional information ' - 'about the\n' - 'exceptional condition.\n' + 'class of the instance or a *non-virtual base class* thereof. ' + 'The\n' + 'instance can be received by the handler and can carry ' + 'additional\n' + 'information about the exceptional condition.\n' '\n' 'Note:\n' '\n' @@ -5730,11 +5732,11 @@ 'clause is\n' 'selected depending on the class of the instance: it must ' 'reference the\n' - 'class of the instance or a base class thereof. The instance ' - 'can be\n' - 'received by the handler and can carry additional information ' - 'about the\n' - 'exceptional condition.\n' + 'class of the instance or a *non-virtual base class* thereof. ' + 'The\n' + 'instance can be received by the handler and can carry ' + 'additional\n' + 'information about the exceptional condition.\n' '\n' 'Note:\n' '\n' @@ -9303,15 +9305,17 @@ 'on members\n' ' of hashed collections including "set", "frozenset", and ' '"dict".\n' - ' "__hash__()" should return an integer. The only required ' - 'property\n' - ' is that objects which compare equal have the same hash ' - 'value; it is\n' - ' advised to mix together the hash values of the components ' - 'of the\n' - ' object that also play a part in comparison of objects by ' - 'packing\n' - ' them into a tuple and hashing the tuple. Example:\n' + ' The "__hash__()" method should return an integer. The ' + 'only required\n' + ' property is that objects which compare equal have the ' + 'same hash\n' + ' value; it is advised to mix together the hash values of ' + 'the\n' + ' components of the object that also play a part in ' + 'comparison of\n' + ' objects by packing them into a tuple and hashing the ' + 'tuple.\n' + ' Example:\n' '\n' ' def __hash__(self):\n' ' return hash((self.name, self.nick, self.color))\n' @@ -12428,10 +12432,10 @@ 'exception. For an except clause with an expression, that expression\n' 'is evaluated, and the clause matches the exception if the resulting\n' 'object is “compatible” with the exception. An object is compatible\n' - 'with an exception if it is the class or a base class of the ' - 'exception\n' - 'object, or a tuple containing an item that is the class or a base\n' - 'class of the exception object.\n' + 'with an exception if the object is the class or a *non-virtual base\n' + 'class* of the exception object, or a tuple containing an item that ' + 'is\n' + 'the class or a non-virtual base class of the exception object.\n' '\n' 'If no except clause matches the exception, the search for an ' 'exception\n' diff -Nru python3.10-3.10.3/Lib/pydoc.py python3.10-3.10.4/Lib/pydoc.py --- python3.10-3.10.3/Lib/pydoc.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/pydoc.py 2022-03-23 20:12:04.000000000 +0000 @@ -69,6 +69,7 @@ import sysconfig import time import tokenize +import types import urllib.parse import warnings from collections import deque @@ -90,13 +91,16 @@ normdirs.append(normdir) return dirs +def _isclass(object): + return inspect.isclass(object) and not isinstance(object, types.GenericAlias) + def _findclass(func): cls = sys.modules.get(func.__module__) if cls is None: return None for name in func.__qualname__.split('.')[:-1]: cls = getattr(cls, name) - if not inspect.isclass(cls): + if not _isclass(cls): return None return cls @@ -104,7 +108,7 @@ if inspect.ismethod(obj): name = obj.__func__.__name__ self = obj.__self__ - if (inspect.isclass(self) and + if (_isclass(self) and getattr(getattr(self, name, None), '__func__') is obj.__func__): # classmethod cls = self @@ -118,7 +122,7 @@ elif inspect.isbuiltin(obj): name = obj.__name__ self = obj.__self__ - if (inspect.isclass(self) and + if (_isclass(self) and self.__qualname__ + '.' + name == obj.__qualname__): # classmethod cls = self @@ -205,7 +209,7 @@ def isdata(object): """Check if an object is of a type that probably means it's data.""" - return not (inspect.ismodule(object) or inspect.isclass(object) or + return not (inspect.ismodule(object) or _isclass(object) or inspect.isroutine(object) or inspect.isframe(object) or inspect.istraceback(object) or inspect.iscode(object)) @@ -470,7 +474,7 @@ # by lacking a __name__ attribute) and an instance. try: if inspect.ismodule(object): return self.docmodule(*args) - if inspect.isclass(object): return self.docclass(*args) + if _isclass(object): return self.docclass(*args) if inspect.isroutine(object): return self.docroutine(*args) except AttributeError: pass @@ -775,7 +779,7 @@ modules = inspect.getmembers(object, inspect.ismodule) classes, cdict = [], {} - for key, value in inspect.getmembers(object, inspect.isclass): + for key, value in inspect.getmembers(object, _isclass): # if __all__ exists, believe it. Otherwise use old heuristic. if (all is not None or (inspect.getmodule(value) or object) is object): @@ -1217,7 +1221,7 @@ result = result + self.section('DESCRIPTION', desc) classes = [] - for key, value in inspect.getmembers(object, inspect.isclass): + for key, value in inspect.getmembers(object, _isclass): # if __all__ exists, believe it. Otherwise use old heuristic. if (all is not None or (inspect.getmodule(value) or object) is object): @@ -1699,7 +1703,7 @@ return 'member descriptor %s.%s.%s' % ( thing.__objclass__.__module__, thing.__objclass__.__name__, thing.__name__) - if inspect.isclass(thing): + if _isclass(thing): return 'class ' + thing.__name__ if inspect.isfunction(thing): return 'function ' + thing.__name__ @@ -1760,7 +1764,7 @@ desc += ' in module ' + module.__name__ if not (inspect.ismodule(object) or - inspect.isclass(object) or + _isclass(object) or inspect.isroutine(object) or inspect.isdatadescriptor(object) or _getdoc(object)): diff -Nru python3.10-3.10.3/Lib/smtpd.py python3.10-3.10.4/Lib/smtpd.py --- python3.10-3.10.3/Lib/smtpd.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/smtpd.py 2022-03-23 20:12:04.000000000 +0000 @@ -93,7 +93,8 @@ ] warn( - 'The smtpd module is deprecated and unmaintained. Please see aiosmtpd ' + 'The smtpd module is deprecated and unmaintained and will be removed ' + 'in Python 3.12. Please see aiosmtpd ' '(https://aiosmtpd.readthedocs.io/) for the recommended replacement.', DeprecationWarning, stacklevel=2) diff -Nru python3.10-3.10.3/Lib/sre_parse.py python3.10-3.10.4/Lib/sre_parse.py --- python3.10-3.10.3/Lib/sre_parse.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/sre_parse.py 2022-03-23 20:12:04.000000000 +0000 @@ -807,9 +807,11 @@ if not first or subpattern: import warnings warnings.warn( - 'Flags not at the start of the expression %r%s' % ( + 'Flags not at the start of the expression %r%s' + ' but at position %d' % ( source.string[:20], # truncate long regexes ' (truncated)' if len(source.string) > 20 else '', + start, ), DeprecationWarning, stacklevel=nested + 6 ) diff -Nru python3.10-3.10.3/Lib/test/libregrtest/main.py python3.10-3.10.4/Lib/test/libregrtest/main.py --- python3.10-3.10.3/Lib/test/libregrtest/main.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/libregrtest/main.py 2022-03-23 20:12:04.000000000 +0000 @@ -533,7 +533,24 @@ if self.ns.use_mp: from test.libregrtest.runtest_mp import run_tests_multiprocess - run_tests_multiprocess(self) + # If we're on windows and this is the parent runner (not a worker), + # track the load average. + if sys.platform == 'win32' and self.worker_test_name is None: + from test.libregrtest.win_utils import WindowsLoadTracker + + try: + self.win_load_tracker = WindowsLoadTracker() + except PermissionError as error: + # Standard accounts may not have access to the performance + # counters. + print(f'Failed to create WindowsLoadTracker: {error}') + + try: + run_tests_multiprocess(self) + finally: + if self.win_load_tracker is not None: + self.win_load_tracker.close() + self.win_load_tracker = None else: self.run_tests_sequential() @@ -695,28 +712,11 @@ self.list_cases() sys.exit(0) - # If we're on windows and this is the parent runner (not a worker), - # track the load average. - if sys.platform == 'win32' and self.worker_test_name is None: - from test.libregrtest.win_utils import WindowsLoadTracker - - try: - self.win_load_tracker = WindowsLoadTracker() - except FileNotFoundError as error: - # Windows IoT Core and Windows Nano Server do not provide - # typeperf.exe for x64, x86 or ARM - print(f'Failed to create WindowsLoadTracker: {error}') - - try: - self.run_tests() - self.display_result() + self.run_tests() + self.display_result() - if self.ns.verbose2 and self.bad: - self.rerun_failed_tests() - finally: - if self.win_load_tracker is not None: - self.win_load_tracker.close() - self.win_load_tracker = None + if self.ns.verbose2 and self.bad: + self.rerun_failed_tests() self.finalize() diff -Nru python3.10-3.10.3/Lib/test/libregrtest/win_utils.py python3.10-3.10.4/Lib/test/libregrtest/win_utils.py --- python3.10-3.10.3/Lib/test/libregrtest/win_utils.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/libregrtest/win_utils.py 2022-03-23 20:12:04.000000000 +0000 @@ -1,16 +1,11 @@ +import _overlapped +import _thread import _winapi import math -import msvcrt -import os -import subprocess -import uuid +import struct import winreg -from test.support import os_helper -from test.libregrtest.utils import print_warning -# Max size of asynchronous reads -BUFSIZE = 8192 # Seconds per measurement SAMPLING_INTERVAL = 1 # Exponential damping factor to compute exponentially weighted moving average @@ -19,174 +14,111 @@ # Initialize the load using the arithmetic mean of the first NVALUE values # of the Processor Queue Length NVALUE = 5 -# Windows registry subkey of HKEY_LOCAL_MACHINE where the counter names -# of typeperf are registered -COUNTER_REGISTRY_KEY = (r"SOFTWARE\Microsoft\Windows NT\CurrentVersion" - r"\Perflib\CurrentLanguage") class WindowsLoadTracker(): """ - This class asynchronously interacts with the `typeperf` command to read - the system load on Windows. Multiprocessing and threads can't be used - here because they interfere with the test suite's cases for those - modules. + This class asynchronously reads the performance counters to calculate + the system load on Windows. A "raw" thread is used here to prevent + interference with the test suite's cases for the threading module. """ def __init__(self): + # Pre-flight test for access to the performance data; + # `PermissionError` will be raised if not allowed + winreg.QueryInfoKey(winreg.HKEY_PERFORMANCE_DATA) + self._values = [] self._load = None - self._buffer = '' - self._popen = None - self.start() - - def start(self): - # Create a named pipe which allows for asynchronous IO in Windows - pipe_name = r'\\.\pipe\typeperf_output_' + str(uuid.uuid4()) - - open_mode = _winapi.PIPE_ACCESS_INBOUND - open_mode |= _winapi.FILE_FLAG_FIRST_PIPE_INSTANCE - open_mode |= _winapi.FILE_FLAG_OVERLAPPED - - # This is the read end of the pipe, where we will be grabbing output - self.pipe = _winapi.CreateNamedPipe( - pipe_name, open_mode, _winapi.PIPE_WAIT, - 1, BUFSIZE, BUFSIZE, _winapi.NMPWAIT_WAIT_FOREVER, _winapi.NULL - ) - # The write end of the pipe which is passed to the created process - pipe_write_end = _winapi.CreateFile( - pipe_name, _winapi.GENERIC_WRITE, 0, _winapi.NULL, - _winapi.OPEN_EXISTING, 0, _winapi.NULL - ) - # Open up the handle as a python file object so we can pass it to - # subprocess - command_stdout = msvcrt.open_osfhandle(pipe_write_end, 0) - - # Connect to the read end of the pipe in overlap/async mode - overlap = _winapi.ConnectNamedPipe(self.pipe, overlapped=True) - overlap.GetOverlappedResult(True) - - # Spawn off the load monitor - counter_name = self._get_counter_name() - command = ['typeperf', counter_name, '-si', str(SAMPLING_INTERVAL)] - self._popen = subprocess.Popen(' '.join(command), - stdout=command_stdout, - cwd=os_helper.SAVEDCWD) - - # Close our copy of the write end of the pipe - os.close(command_stdout) - - def _get_counter_name(self): - # accessing the registry to get the counter localization name - with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, COUNTER_REGISTRY_KEY) as perfkey: - counters = winreg.QueryValueEx(perfkey, 'Counter')[0] - - # Convert [key1, value1, key2, value2, ...] list - # to {key1: value1, key2: value2, ...} dict - counters = iter(counters) - counters_dict = dict(zip(counters, counters)) - - # System counter has key '2' and Processor Queue Length has key '44' - system = counters_dict['2'] - process_queue_length = counters_dict['44'] - return f'"\\{system}\\{process_queue_length}"' + self._running = _overlapped.CreateEvent(None, True, False, None) + self._stopped = _overlapped.CreateEvent(None, True, False, None) - def close(self, kill=True): - if self._popen is None: - return - - self._load = None + _thread.start_new_thread(self._update_load, (), {}) - if kill: - self._popen.kill() - self._popen.wait() - self._popen = None - - def __del__(self): - self.close() - - def _parse_line(self, line): - # typeperf outputs in a CSV format like this: - # "07/19/2018 01:32:26.605","3.000000" - # (date, process queue length) - tokens = line.split(',') - if len(tokens) != 2: - raise ValueError - - value = tokens[1] - if not value.startswith('"') or not value.endswith('"'): - raise ValueError - value = value[1:-1] - return float(value) - - def _read_lines(self): - overlapped, _ = _winapi.ReadFile(self.pipe, BUFSIZE, True) - bytes_read, res = overlapped.GetOverlappedResult(False) - if res != 0: - return () - - output = overlapped.getbuffer() - output = output.decode('oem', 'replace') - output = self._buffer + output - lines = output.splitlines(True) - - # bpo-36670: typeperf only writes a newline *before* writing a value, - # not after. Sometimes, the written line in incomplete (ex: only - # timestamp, without the process queue length). Only pass the last line - # to the parser if it's a valid value, otherwise store it in - # self._buffer. - try: - self._parse_line(lines[-1]) - except ValueError: - self._buffer = lines.pop(-1) + def _update_load(self, + # localize module access to prevent shutdown errors + _wait=_winapi.WaitForSingleObject, + _signal=_overlapped.SetEvent): + # run until signaled to stop + while _wait(self._running, 1000): + self._calculate_load() + # notify stopped + _signal(self._stopped) + + def _calculate_load(self, + # localize module access to prevent shutdown errors + _query=winreg.QueryValueEx, + _hkey=winreg.HKEY_PERFORMANCE_DATA, + _unpack=struct.unpack_from): + # get the 'System' object + data, _ = _query(_hkey, '2') + # PERF_DATA_BLOCK { + # WCHAR Signature[4] 8 + + # DWOWD LittleEndian 4 + + # DWORD Version 4 + + # DWORD Revision 4 + + # DWORD TotalByteLength 4 + + # DWORD HeaderLength = 24 byte offset + # ... + # } + obj_start, = _unpack('L', data, 24) + # PERF_OBJECT_TYPE { + # DWORD TotalByteLength + # DWORD DefinitionLength + # DWORD HeaderLength + # ... + # } + data_start, defn_start = _unpack('4xLL', data, obj_start) + data_base = obj_start + data_start + defn_base = obj_start + defn_start + # find the 'Processor Queue Length' counter (index=44) + while defn_base < data_base: + # PERF_COUNTER_DEFINITION { + # DWORD ByteLength + # DWORD CounterNameTitleIndex + # ... [7 DWORDs/28 bytes] + # DWORD CounterOffset + # } + size, idx, offset = _unpack('LL28xL', data, defn_base) + defn_base += size + if idx == 44: + counter_offset = data_base + offset + # the counter is known to be PERF_COUNTER_RAWCOUNT (DWORD) + processor_queue_length, = _unpack('L', data, counter_offset) + break else: - self._buffer = '' + return - return lines + # We use an exponentially weighted moving average, imitating the + # load calculation on Unix systems. + # https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation + # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + if self._load is not None: + self._load = (self._load * LOAD_FACTOR_1 + + processor_queue_length * (1.0 - LOAD_FACTOR_1)) + elif len(self._values) < NVALUE: + self._values.append(processor_queue_length) + else: + self._load = sum(self._values) / len(self._values) - def getloadavg(self): - if self._popen is None: - return None + def close(self, kill=True): + self.__del__() + return - returncode = self._popen.poll() - if returncode is not None: - self.close(kill=False) - return None - - try: - lines = self._read_lines() - except BrokenPipeError: - self.close() - return None - - for line in lines: - line = line.rstrip() - - # Ignore the initial header: - # "(PDH-CSV 4.0)","\\\\WIN\\System\\Processor Queue Length" - if 'PDH-CSV' in line: - continue - - # Ignore blank lines - if not line: - continue - - try: - processor_queue_length = self._parse_line(line) - except ValueError: - print_warning("Failed to parse typeperf output: %a" % line) - continue - - # We use an exponentially weighted moving average, imitating the - # load calculation on Unix systems. - # https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation - # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average - if self._load is not None: - self._load = (self._load * LOAD_FACTOR_1 - + processor_queue_length * (1.0 - LOAD_FACTOR_1)) - elif len(self._values) < NVALUE: - self._values.append(processor_queue_length) - else: - self._load = sum(self._values) / len(self._values) + def __del__(self, + # localize module access to prevent shutdown errors + _wait=_winapi.WaitForSingleObject, + _close=_winapi.CloseHandle, + _signal=_overlapped.SetEvent): + if self._running is not None: + # tell the update thread to quit + _signal(self._running) + # wait for the update thread to signal done + _wait(self._stopped, -1) + # cleanup events + _close(self._running) + _close(self._stopped) + self._running = self._stopped = None + def getloadavg(self): return self._load diff -Nru python3.10-3.10.3/Lib/test/pydoc_mod.py python3.10-3.10.4/Lib/test/pydoc_mod.py --- python3.10-3.10.3/Lib/test/pydoc_mod.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/pydoc_mod.py 2022-03-23 20:12:04.000000000 +0000 @@ -1,5 +1,8 @@ """This is a test module for test_pydoc""" +import types +import typing + __author__ = "Benjamin Peterson" __credits__ = "Nobody" __version__ = "1.2.3.4" @@ -24,6 +27,8 @@ def is_it_true(self): """ Return self.get_answer() """ return self.get_answer() + def __class_getitem__(self, item): + return types.GenericAlias(self, item) def doc_func(): """ @@ -35,3 +40,10 @@ def nodoc_func(): pass + + +list_alias1 = typing.List[int] +list_alias2 = list[int] +c_alias = C[int] +type_union1 = typing.Union[int, str] +type_union2 = int | str diff -Nru python3.10-3.10.3/Lib/test/test_asyncio/test_asyncio_waitfor.py python3.10-3.10.4/Lib/test/test_asyncio/test_asyncio_waitfor.py --- python3.10-3.10.3/Lib/test/test_asyncio/test_asyncio_waitfor.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_asyncio/test_asyncio_waitfor.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,61 +0,0 @@ -import asyncio -import unittest -import time - -def tearDownModule(): - asyncio.set_event_loop_policy(None) - - -class SlowTask: - """ Task will run for this defined time, ignoring cancel requests """ - TASK_TIMEOUT = 0.2 - - def __init__(self): - self.exited = False - - async def run(self): - exitat = time.monotonic() + self.TASK_TIMEOUT - - while True: - tosleep = exitat - time.monotonic() - if tosleep <= 0: - break - - try: - await asyncio.sleep(tosleep) - except asyncio.CancelledError: - pass - - self.exited = True - -class AsyncioWaitForTest(unittest.TestCase): - - async def atest_asyncio_wait_for_cancelled(self): - t = SlowTask() - - waitfortask = asyncio.create_task(asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2)) - await asyncio.sleep(0) - waitfortask.cancel() - await asyncio.wait({waitfortask}) - - self.assertTrue(t.exited) - - def test_asyncio_wait_for_cancelled(self): - asyncio.run(self.atest_asyncio_wait_for_cancelled()) - - async def atest_asyncio_wait_for_timeout(self): - t = SlowTask() - - try: - await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2) - except asyncio.TimeoutError: - pass - - self.assertTrue(t.exited) - - def test_asyncio_wait_for_timeout(self): - asyncio.run(self.atest_asyncio_wait_for_timeout()) - - -if __name__ == '__main__': - unittest.main() diff -Nru python3.10-3.10.3/Lib/test/test_asyncio/test_locks.py python3.10-3.10.4/Lib/test/test_asyncio/test_locks.py --- python3.10-3.10.3/Lib/test/test_asyncio/test_locks.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_asyncio/test_locks.py 2022-03-23 20:12:04.000000000 +0000 @@ -933,6 +933,32 @@ sem.release() self.assertFalse(sem.locked()) + async def test_acquire_fifo_order(self): + sem = asyncio.Semaphore(1) + result = [] + + async def coro(tag): + await sem.acquire() + result.append(f'{tag}_1') + await asyncio.sleep(0.01) + sem.release() + + await sem.acquire() + result.append(f'{tag}_2') + await asyncio.sleep(0.01) + sem.release() + + t1 = asyncio.create_task(coro('c1')) + t2 = asyncio.create_task(coro('c2')) + t3 = asyncio.create_task(coro('c3')) + + await asyncio.gather(t1, t2, t3) + + self.assertEqual( + ['c1_1', 'c2_1', 'c3_1', 'c1_2', 'c2_2', 'c3_2'], + result + ) + if __name__ == '__main__': unittest.main() diff -Nru python3.10-3.10.3/Lib/test/test_asyncio/test_tasks.py python3.10-3.10.4/Lib/test/test_asyncio/test_tasks.py --- python3.10-3.10.3/Lib/test/test_asyncio/test_tasks.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_asyncio/test_tasks.py 2022-03-23 20:12:04.000000000 +0000 @@ -98,12 +98,6 @@ return self -# The following value can be used as a very small timeout: -# it passes check "timeout > 0", but has almost -# no effect on the test performance -_EPSILON = 0.0001 - - class BaseTaskTests: Task = None @@ -121,7 +115,6 @@ self.loop.set_task_factory(self.new_task) self.loop.create_future = lambda: self.new_future(self.loop) - def test_generic_alias(self): task = self.__class__.Task[str] self.assertEqual(task.__args__, (str,)) @@ -1031,251 +1024,6 @@ task._log_traceback = True self.loop.run_until_complete(task) - def test_wait_for_timeout_less_then_0_or_0_future_done(self): - def gen(): - when = yield - self.assertAlmostEqual(0, when) - - loop = self.new_test_loop(gen) - - fut = self.new_future(loop) - fut.set_result('done') - - ret = loop.run_until_complete(asyncio.wait_for(fut, 0)) - - self.assertEqual(ret, 'done') - self.assertTrue(fut.done()) - self.assertAlmostEqual(0, loop.time()) - - def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self): - def gen(): - when = yield - self.assertAlmostEqual(0, when) - - loop = self.new_test_loop(gen) - - foo_started = False - - async def foo(): - nonlocal foo_started - foo_started = True - - with self.assertRaises(asyncio.TimeoutError): - loop.run_until_complete(asyncio.wait_for(foo(), 0)) - - self.assertAlmostEqual(0, loop.time()) - self.assertEqual(foo_started, False) - - def test_wait_for_timeout_less_then_0_or_0(self): - def gen(): - when = yield - self.assertAlmostEqual(0.2, when) - when = yield 0 - self.assertAlmostEqual(0, when) - - for timeout in [0, -1]: - with self.subTest(timeout=timeout): - loop = self.new_test_loop(gen) - - foo_running = None - - async def foo(): - nonlocal foo_running - foo_running = True - try: - await asyncio.sleep(0.2) - finally: - foo_running = False - return 'done' - - fut = self.new_task(loop, foo()) - - with self.assertRaises(asyncio.TimeoutError): - loop.run_until_complete(asyncio.wait_for(fut, timeout)) - self.assertTrue(fut.done()) - # it should have been cancelled due to the timeout - self.assertTrue(fut.cancelled()) - self.assertAlmostEqual(0, loop.time()) - self.assertEqual(foo_running, False) - - def test_wait_for(self): - - def gen(): - when = yield - self.assertAlmostEqual(0.2, when) - when = yield 0 - self.assertAlmostEqual(0.1, when) - when = yield 0.1 - - loop = self.new_test_loop(gen) - - foo_running = None - - async def foo(): - nonlocal foo_running - foo_running = True - try: - await asyncio.sleep(0.2) - finally: - foo_running = False - return 'done' - - fut = self.new_task(loop, foo()) - - with self.assertRaises(asyncio.TimeoutError): - loop.run_until_complete(asyncio.wait_for(fut, 0.1)) - self.assertTrue(fut.done()) - # it should have been cancelled due to the timeout - self.assertTrue(fut.cancelled()) - self.assertAlmostEqual(0.1, loop.time()) - self.assertEqual(foo_running, False) - - def test_wait_for_blocking(self): - loop = self.new_test_loop() - - async def coro(): - return 'done' - - res = loop.run_until_complete(asyncio.wait_for(coro(), timeout=None)) - self.assertEqual(res, 'done') - - def test_wait_for_race_condition(self): - - def gen(): - yield 0.1 - yield 0.1 - yield 0.1 - - loop = self.new_test_loop(gen) - - fut = self.new_future(loop) - task = asyncio.wait_for(fut, timeout=0.2) - loop.call_later(0.1, fut.set_result, "ok") - res = loop.run_until_complete(task) - self.assertEqual(res, "ok") - - def test_wait_for_cancellation_race_condition(self): - async def inner(): - with contextlib.suppress(asyncio.CancelledError): - await asyncio.sleep(1) - return 1 - - async def main(): - result = await asyncio.wait_for(inner(), timeout=.01) - self.assertEqual(result, 1) - - asyncio.run(main()) - - def test_wait_for_waits_for_task_cancellation(self): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - task_done = False - - async def foo(): - async def inner(): - nonlocal task_done - try: - await asyncio.sleep(0.2) - except asyncio.CancelledError: - await asyncio.sleep(_EPSILON) - raise - finally: - task_done = True - - inner_task = self.new_task(loop, inner()) - - await asyncio.wait_for(inner_task, timeout=_EPSILON) - - with self.assertRaises(asyncio.TimeoutError) as cm: - loop.run_until_complete(foo()) - - self.assertTrue(task_done) - chained = cm.exception.__context__ - self.assertEqual(type(chained), asyncio.CancelledError) - - def test_wait_for_waits_for_task_cancellation_w_timeout_0(self): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - task_done = False - - async def foo(): - async def inner(): - nonlocal task_done - try: - await asyncio.sleep(10) - except asyncio.CancelledError: - await asyncio.sleep(_EPSILON) - raise - finally: - task_done = True - - inner_task = self.new_task(loop, inner()) - await asyncio.sleep(_EPSILON) - await asyncio.wait_for(inner_task, timeout=0) - - with self.assertRaises(asyncio.TimeoutError) as cm: - loop.run_until_complete(foo()) - - self.assertTrue(task_done) - chained = cm.exception.__context__ - self.assertEqual(type(chained), asyncio.CancelledError) - - def test_wait_for_reraises_exception_during_cancellation(self): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - class FooException(Exception): - pass - - async def foo(): - async def inner(): - try: - await asyncio.sleep(0.2) - finally: - raise FooException - - inner_task = self.new_task(loop, inner()) - - await asyncio.wait_for(inner_task, timeout=_EPSILON) - - with self.assertRaises(FooException): - loop.run_until_complete(foo()) - - def test_wait_for_self_cancellation(self): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - async def foo(): - async def inner(): - try: - await asyncio.sleep(0.3) - except asyncio.CancelledError: - try: - await asyncio.sleep(0.3) - except asyncio.CancelledError: - await asyncio.sleep(0.3) - - return 42 - - inner_task = self.new_task(loop, inner()) - - wait = asyncio.wait_for(inner_task, timeout=0.1) - - # Test that wait_for itself is properly cancellable - # even when the initial task holds up the initial cancellation. - task = self.new_task(loop, wait) - await asyncio.sleep(0.2) - task.cancel() - - with self.assertRaises(asyncio.CancelledError): - await task - - self.assertEqual(await inner_task, 42) - - loop.run_until_complete(foo()) - def test_wait(self): def gen(): @@ -2544,32 +2292,6 @@ 'test_task_source_traceback')) self.loop.run_until_complete(task) - def _test_cancel_wait_for(self, timeout): - loop = asyncio.new_event_loop() - self.addCleanup(loop.close) - - async def blocking_coroutine(): - fut = self.new_future(loop) - # Block: fut result is never set - await fut - - task = loop.create_task(blocking_coroutine()) - - wait = loop.create_task(asyncio.wait_for(task, timeout)) - loop.call_soon(wait.cancel) - - self.assertRaises(asyncio.CancelledError, - loop.run_until_complete, wait) - - # Python issue #23219: cancelling the wait must also cancel the task - self.assertTrue(task.cancelled()) - - def test_cancel_blocking_wait_for(self): - self._test_cancel_wait_for(None) - - def test_cancel_wait_for(self): - self._test_cancel_wait_for(60.0) - def test_cancel_gather_1(self): """Ensure that a gathering future refuses to be cancelled once all children are done""" diff -Nru python3.10-3.10.3/Lib/test/test_asyncio/test_waitfor.py python3.10-3.10.4/Lib/test/test_asyncio/test_waitfor.py --- python3.10-3.10.3/Lib/test/test_asyncio/test_waitfor.py 1970-01-01 00:00:00.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_asyncio/test_waitfor.py 2022-03-23 20:12:04.000000000 +0000 @@ -0,0 +1,294 @@ +import asyncio +import unittest +import time + + +def tearDownModule(): + asyncio.set_event_loop_policy(None) + + +# The following value can be used as a very small timeout: +# it passes check "timeout > 0", but has almost +# no effect on the test performance +_EPSILON = 0.0001 + + +class SlowTask: + """ Task will run for this defined time, ignoring cancel requests """ + TASK_TIMEOUT = 0.2 + + def __init__(self): + self.exited = False + + async def run(self): + exitat = time.monotonic() + self.TASK_TIMEOUT + + while True: + tosleep = exitat - time.monotonic() + if tosleep <= 0: + break + + try: + await asyncio.sleep(tosleep) + except asyncio.CancelledError: + pass + + self.exited = True + + +class AsyncioWaitForTest(unittest.IsolatedAsyncioTestCase): + + async def test_asyncio_wait_for_cancelled(self): + t = SlowTask() + + waitfortask = asyncio.create_task( + asyncio.wait_for(t.run(), t.TASK_TIMEOUT * 2)) + await asyncio.sleep(0) + waitfortask.cancel() + await asyncio.wait({waitfortask}) + + self.assertTrue(t.exited) + + async def test_asyncio_wait_for_timeout(self): + t = SlowTask() + + try: + await asyncio.wait_for(t.run(), t.TASK_TIMEOUT / 2) + except asyncio.TimeoutError: + pass + + self.assertTrue(t.exited) + + async def test_wait_for_timeout_less_then_0_or_0_future_done(self): + loop = asyncio.get_running_loop() + + fut = loop.create_future() + fut.set_result('done') + + t0 = loop.time() + ret = await asyncio.wait_for(fut, 0) + t1 = loop.time() + + self.assertEqual(ret, 'done') + self.assertTrue(fut.done()) + self.assertLess(t1 - t0, 0.1) + + async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self): + loop = asyncio.get_running_loop() + + foo_started = False + + async def foo(): + nonlocal foo_started + foo_started = True + + with self.assertRaises(asyncio.TimeoutError): + t0 = loop.time() + await asyncio.wait_for(foo(), 0) + t1 = loop.time() + + self.assertEqual(foo_started, False) + self.assertLess(t1 - t0, 0.1) + + async def test_wait_for_timeout_less_then_0_or_0(self): + loop = asyncio.get_running_loop() + + for timeout in [0, -1]: + with self.subTest(timeout=timeout): + foo_running = None + started = loop.create_future() + + async def foo(): + nonlocal foo_running + foo_running = True + started.set_result(None) + try: + await asyncio.sleep(10) + finally: + foo_running = False + return 'done' + + fut = asyncio.create_task(foo()) + await started + + with self.assertRaises(asyncio.TimeoutError): + t0 = loop.time() + await asyncio.wait_for(fut, timeout) + t1 = loop.time() + + self.assertTrue(fut.done()) + # it should have been cancelled due to the timeout + self.assertTrue(fut.cancelled()) + self.assertEqual(foo_running, False) + self.assertLess(t1 - t0, 0.1) + + async def test_wait_for(self): + loop = asyncio.get_running_loop() + foo_running = None + + async def foo(): + nonlocal foo_running + foo_running = True + try: + await asyncio.sleep(10) + finally: + foo_running = False + return 'done' + + fut = asyncio.create_task(foo()) + + with self.assertRaises(asyncio.TimeoutError): + t0 = loop.time() + await asyncio.wait_for(fut, 0.1) + t1 = loop.time() + self.assertTrue(fut.done()) + # it should have been cancelled due to the timeout + self.assertTrue(fut.cancelled()) + self.assertLess(t1 - t0, 0.5) + self.assertEqual(foo_running, False) + + async def test_wait_for_blocking(self): + async def coro(): + return 'done' + + res = await asyncio.wait_for(coro(), timeout=None) + self.assertEqual(res, 'done') + + async def test_wait_for_race_condition(self): + loop = asyncio.get_running_loop() + + fut = loop.create_future() + task = asyncio.wait_for(fut, timeout=0.2) + loop.call_later(0.1, fut.set_result, "ok") + res = await task + self.assertEqual(res, "ok") + + async def test_wait_for_cancellation_race_condition(self): + async def inner(): + with self.assertRaises(asyncio.CancelledError): + await asyncio.sleep(1) + return 1 + + result = await asyncio.wait_for(inner(), timeout=.01) + self.assertEqual(result, 1) + + async def test_wait_for_waits_for_task_cancellation(self): + task_done = False + + async def inner(): + nonlocal task_done + try: + await asyncio.sleep(10) + except asyncio.CancelledError: + await asyncio.sleep(_EPSILON) + raise + finally: + task_done = True + + inner_task = asyncio.create_task(inner()) + + with self.assertRaises(asyncio.TimeoutError) as cm: + await asyncio.wait_for(inner_task, timeout=_EPSILON) + + self.assertTrue(task_done) + chained = cm.exception.__context__ + self.assertEqual(type(chained), asyncio.CancelledError) + + async def test_wait_for_waits_for_task_cancellation_w_timeout_0(self): + task_done = False + + async def foo(): + async def inner(): + nonlocal task_done + try: + await asyncio.sleep(10) + except asyncio.CancelledError: + await asyncio.sleep(_EPSILON) + raise + finally: + task_done = True + + inner_task = asyncio.create_task(inner()) + await asyncio.sleep(_EPSILON) + await asyncio.wait_for(inner_task, timeout=0) + + with self.assertRaises(asyncio.TimeoutError) as cm: + await foo() + + self.assertTrue(task_done) + chained = cm.exception.__context__ + self.assertEqual(type(chained), asyncio.CancelledError) + + async def test_wait_for_reraises_exception_during_cancellation(self): + class FooException(Exception): + pass + + async def foo(): + async def inner(): + try: + await asyncio.sleep(0.2) + finally: + raise FooException + + inner_task = asyncio.create_task(inner()) + + await asyncio.wait_for(inner_task, timeout=_EPSILON) + + with self.assertRaises(FooException): + await foo() + + async def test_wait_for_self_cancellation(self): + async def inner(): + try: + await asyncio.sleep(0.3) + except asyncio.CancelledError: + try: + await asyncio.sleep(0.3) + except asyncio.CancelledError: + await asyncio.sleep(0.3) + + return 42 + + inner_task = asyncio.create_task(inner()) + + wait = asyncio.wait_for(inner_task, timeout=0.1) + + # Test that wait_for itself is properly cancellable + # even when the initial task holds up the initial cancellation. + task = asyncio.create_task(wait) + await asyncio.sleep(0.2) + task.cancel() + + with self.assertRaises(asyncio.CancelledError): + await task + + self.assertEqual(await inner_task, 42) + + async def _test_cancel_wait_for(self, timeout): + loop = asyncio.get_running_loop() + + async def blocking_coroutine(): + fut = loop.create_future() + # Block: fut result is never set + await fut + + task = asyncio.create_task(blocking_coroutine()) + + wait = asyncio.create_task(asyncio.wait_for(task, timeout)) + loop.call_soon(wait.cancel) + + with self.assertRaises(asyncio.CancelledError): + await wait + + # Python issue #23219: cancelling the wait must also cancel the task + self.assertTrue(task.cancelled()) + + async def test_cancel_blocking_wait_for(self): + await self._test_cancel_wait_for(None) + + async def test_cancel_wait_for(self): + await self._test_cancel_wait_for(60.0) + + +if __name__ == '__main__': + unittest.main() diff -Nru python3.10-3.10.3/Lib/test/test_binascii.py python3.10-3.10.4/Lib/test/test_binascii.py --- python3.10-3.10.3/Lib/test/test_binascii.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_binascii.py 2022-03-23 20:12:04.000000000 +0000 @@ -4,7 +4,7 @@ import binascii import array import re -from test.support import warnings_helper +from test.support import bigmemtest, _1G, _4G, warnings_helper # Note: "*_hex" functions are aliases for "(un)hexlify" @@ -449,6 +449,14 @@ class MemoryviewBinASCIITest(BinASCIITest): type2test = memoryview +class ChecksumBigBufferTestCase(unittest.TestCase): + """bpo-38256 - check that inputs >=4 GiB are handled correctly.""" + + @bigmemtest(size=_4G + 4, memuse=1, dry_run=False) + def test_big_buffer(self, size): + data = b"nyan" * (_1G + 1) + self.assertEqual(binascii.crc32(data), 1044521549) + if __name__ == "__main__": unittest.main() diff -Nru python3.10-3.10.3/Lib/test/test_cmd_line.py python3.10-3.10.4/Lib/test/test_cmd_line.py --- python3.10-3.10.3/Lib/test/test_cmd_line.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_cmd_line.py 2022-03-23 20:12:04.000000000 +0000 @@ -137,6 +137,17 @@ self.assertTrue(data.find(b'1 loop') != -1) self.assertTrue(data.find(b'__main__.Timer') != -1) + def test_relativedir_bug46421(self): + # Test `python -m unittest` with a relative directory beginning with ./ + # Note: We have to switch to the project's top module's directory, as per + # the python unittest wiki. We will switch back when we are done. + defaultwd = os.getcwd() + projectlibpath = os.path.dirname(__file__).removesuffix("test") + with os_helper.change_cwd(projectlibpath): + # Testing with and without ./ + assert_python_ok('-m', 'unittest', "test/test_longexp.py") + assert_python_ok('-m', 'unittest', "./test/test_longexp.py") + def test_run_code(self): # Test expected operation of the '-c' switch # Switch needs an argument diff -Nru python3.10-3.10.3/Lib/test/test_doctest.py python3.10-3.10.4/Lib/test/test_doctest.py --- python3.10-3.10.3/Lib/test/test_doctest.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_doctest.py 2022-03-23 20:12:04.000000000 +0000 @@ -3126,6 +3126,22 @@ """ +def test_run_doctestsuite_multiple_times(): + """ + It was not possible to run the same DocTestSuite multiple times + http://bugs.python.org/issue2604 + http://bugs.python.org/issue9736 + + >>> import unittest + >>> import test.sample_doctest + >>> suite = doctest.DocTestSuite(test.sample_doctest) + >>> suite.run(unittest.TestResult()) + + >>> suite.run(unittest.TestResult()) + + """ + + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(doctest)) tests.addTest(doctest.DocTestSuite()) diff -Nru python3.10-3.10.3/Lib/test/test_pydoc.py python3.10-3.10.4/Lib/test/test_pydoc.py --- python3.10-3.10.3/Lib/test/test_pydoc.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_pydoc.py 2022-03-23 20:12:04.000000000 +0000 @@ -95,6 +95,11 @@ | say_no(self) |\x20\x20 | ---------------------------------------------------------------------- + | Class methods defined here: + |\x20\x20 + | __class_getitem__(item) from builtins.type + |\x20\x20 + | ---------------------------------------------------------------------- | Data descriptors defined here: |\x20\x20 | __dict__ @@ -114,6 +119,11 @@ DATA __xyz__ = 'X, Y and Z' + c_alias = test.pydoc_mod.C[int] + list_alias1 = typing.List[int] + list_alias2 = list[int] + type_union1 = typing.Union[int, str] + type_union2 = int | str VERSION 1.2.3.4 @@ -141,6 +151,15 @@

This is a test module for test_pydoc

+ + +\x20\x20\x20\x20 + +
 
+Modules
       
types
+
typing
+

+ @@ -211,6 +230,10 @@
say_no(self)

+Class methods defined here:
+
__class_getitem__(item) from builtins.type
+ +
Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
@@ -237,7 +260,12 @@ Data \x20\x20\x20\x20
-
 
Classes
       __xyz__ = 'X, Y and Z'

+__xyz__ = 'X, Y and Z'
+c_alias = test.pydoc_mod.C[int]
+list_alias1 = typing.List[int]
+list_alias2 = list[int]
+type_union1 = typing.Union[int, str]
+type_union2 = int | str

 
@@ -1048,6 +1076,43 @@ expected = 'C in module %s object' % __name__ self.assertIn(expected, pydoc.render_doc(c)) + def test_generic_alias(self): + self.assertEqual(pydoc.describe(typing.List[int]), '_GenericAlias') + doc = pydoc.render_doc(typing.List[int], renderer=pydoc.plaintext) + self.assertIn('_GenericAlias in module typing', doc) + self.assertIn('List = class list(object)', doc) + self.assertIn(list.__doc__.strip().splitlines()[0], doc) + + self.assertEqual(pydoc.describe(list[int]), 'GenericAlias') + doc = pydoc.render_doc(list[int], renderer=pydoc.plaintext) + self.assertIn('GenericAlias in module builtins', doc) + self.assertIn('\nclass list(object)', doc) + self.assertIn(list.__doc__.strip().splitlines()[0], doc) + + def test_union_type(self): + self.assertEqual(pydoc.describe(typing.Union[int, str]), '_UnionGenericAlias') + doc = pydoc.render_doc(typing.Union[int, str], renderer=pydoc.plaintext) + self.assertIn('_UnionGenericAlias in module typing', doc) + self.assertIn('Union = typing.Union', doc) + if typing.Union.__doc__: + self.assertIn(typing.Union.__doc__.strip().splitlines()[0], doc) + + self.assertEqual(pydoc.describe(int | str), 'UnionType') + doc = pydoc.render_doc(int | str, renderer=pydoc.plaintext) + self.assertIn('UnionType in module types object', doc) + self.assertIn('\nclass UnionType(builtins.object)', doc) + self.assertIn(types.UnionType.__doc__.strip().splitlines()[0], doc) + + def test_special_form(self): + self.assertEqual(pydoc.describe(typing.Any), '_SpecialForm') + doc = pydoc.render_doc(typing.Any, renderer=pydoc.plaintext) + self.assertIn('_SpecialForm in module typing', doc) + if typing.Any.__doc__: + self.assertIn('Any = typing.Any', doc) + self.assertIn(typing.Any.__doc__.strip().splitlines()[0], doc) + else: + self.assertIn('Any = class _SpecialForm(_Final)', doc) + def test_typing_pydoc(self): def foo(data: typing.List[typing.Any], x: int) -> typing.Iterator[typing.Tuple[int, typing.Any]]: diff -Nru python3.10-3.10.3/Lib/test/test_re.py python3.10-3.10.4/Lib/test/test_re.py --- python3.10-3.10.3/Lib/test/test_re.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/test/test_re.py 2022-03-23 20:12:04.000000000 +0000 @@ -1444,7 +1444,8 @@ self.assertTrue(re.match(p, lower_char)) self.assertEqual( str(warns.warnings[0].message), - 'Flags not at the start of the expression %r' % p + 'Flags not at the start of the expression %r' + ' but at position 1' % p ) self.assertEqual(warns.warnings[0].filename, __file__) @@ -1453,7 +1454,8 @@ self.assertTrue(re.match(p, lower_char)) self.assertEqual( str(warns.warnings[0].message), - 'Flags not at the start of the expression %r (truncated)' % p[:20] + 'Flags not at the start of the expression %r (truncated)' + ' but at position 1' % p[:20] ) self.assertEqual(warns.warnings[0].filename, __file__) @@ -1465,7 +1467,8 @@ self.assertTrue(re.match(p, b'a')) self.assertEqual( str(warns.warnings[0].message), - 'Flags not at the start of the expression %r' % p + 'Flags not at the start of the expression %r' + ' but at position 1' % p ) self.assertEqual(warns.warnings[0].filename, __file__) diff -Nru python3.10-3.10.3/Lib/tkinter/test/test_tkinter/test_widgets.py python3.10-3.10.4/Lib/tkinter/test/test_tkinter/test_widgets.py --- python3.10-3.10.3/Lib/tkinter/test/test_tkinter/test_widgets.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/tkinter/test/test_tkinter/test_widgets.py 2022-03-23 20:12:04.000000000 +0000 @@ -800,7 +800,7 @@ self.checkEnumParam(widget, 'activestyle', 'dotbox', 'none', 'underline') - test_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) + test_configure_justify = requires_tcl(8, 6, 5)(StandardOptionsTests.test_configure_justify) def test_configure_listvariable(self): widget = self.create() @@ -939,7 +939,7 @@ def test_configure_from(self): widget = self.create() - conv = False if get_tk_patchlevel() >= (8, 6, 10) else float_round + conv = float if get_tk_patchlevel() >= (8, 6, 10) else float_round self.checkFloatParam(widget, 'from', 100, 14.9, 15.1, conv=conv) def test_configure_label(self): diff -Nru python3.10-3.10.3/Lib/tkinter/test/test_ttk/test_style.py python3.10-3.10.4/Lib/tkinter/test/test_ttk/test_style.py --- python3.10-3.10.3/Lib/tkinter/test/test_ttk/test_style.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/tkinter/test/test_ttk/test_style.py 2022-03-23 20:12:04.000000000 +0000 @@ -4,7 +4,7 @@ from tkinter import ttk from test import support from test.support import requires -from tkinter.test.support import AbstractTkTest +from tkinter.test.support import AbstractTkTest, get_tk_patchlevel requires('gui') @@ -170,6 +170,8 @@ newname = f'C.{name}' self.assertEqual(style.map(newname), {}) style.map(newname, **default) + if theme == 'alt' and name == '.' and get_tk_patchlevel() < (8, 6, 1): + default['embossed'] = [('disabled', '1')] self.assertEqual(style.map(newname), default) for key, value in default.items(): self.assertEqual(style.map(newname, key), value) diff -Nru python3.10-3.10.3/Lib/unittest/main.py python3.10-3.10.4/Lib/unittest/main.py --- python3.10-3.10.3/Lib/unittest/main.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/unittest/main.py 2022-03-23 20:12:04.000000000 +0000 @@ -39,7 +39,7 @@ name = rel_path # on Windows both '\' and '/' are used as path # separators. Better to replace both than rely on os.path.sep - return name[:-3].replace('\\', '.').replace('/', '.') + return os.path.normpath(name)[:-3].replace('\\', '.').replace('/', '.') return name def _convert_names(names): diff -Nru python3.10-3.10.3/Lib/zipfile.py python3.10-3.10.4/Lib/zipfile.py --- python3.10-3.10.3/Lib/zipfile.py 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Lib/zipfile.py 2022-03-23 20:12:04.000000000 +0000 @@ -721,7 +721,9 @@ self._lock = lock self._writing = writing self.seekable = file.seekable - self.tell = file.tell + + def tell(self): + return self._pos def seek(self, offset, whence=0): with self._lock: diff -Nru python3.10-3.10.3/Misc/ACKS python3.10-3.10.4/Misc/ACKS --- python3.10-3.10.3/Misc/ACKS 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Misc/ACKS 2022-03-23 20:12:04.000000000 +0000 @@ -1983,6 +1983,7 @@ Arnaud Ysmal Bernard Yue Moshe Zadka +Bader Zaidan Elias Zamaria Milan Zamazal Artur Zaprzala diff -Nru python3.10-3.10.3/Misc/NEWS python3.10-3.10.4/Misc/NEWS --- python3.10-3.10.3/Misc/NEWS 2022-03-16 11:40:29.000000000 +0000 +++ python3.10-3.10.4/Misc/NEWS 2022-03-23 20:25:24.000000000 +0000 @@ -2,6 +2,59 @@ Python News +++++++++++ +What's New in Python 3.10.4 final? +================================== + +*Release date: 2022-03-23* + +Core and Builtins +----------------- + +- bpo-46968: Check for the existence of the "sys/auxv.h" header in + :mod:`faulthandler` to avoid compilation problems in systems where this + header doesn't exist. Patch by Pablo Galindo + +Library +------- + +- bpo-23691: Protect the :func:`re.finditer` iterator from re-entering. + +- bpo-42369: Fix thread safety of :meth:`zipfile._SharedFile.tell` to avoid + a "zipfile.BadZipFile: Bad CRC-32 for file" exception when reading a + :class:`ZipFile` from multiple threads. + +- bpo-38256: Fix :func:`binascii.crc32` when it is compiled to use zlib'c + crc32 to work properly on inputs 4+GiB in length instead of returning the + wrong result. The workaround prior to this was to always feed the function + data in increments smaller than 4GiB or to just call the zlib module + function. + +- bpo-39394: A warning about inline flags not at the start of the regular + expression now contains the position of the flag. + +- bpo-47061: Deprecate the various modules listed by :pep:`594`: + + aifc, asynchat, asyncore, audioop, cgi, cgitb, chunk, crypt, imghdr, + msilib, nntplib, nis, ossaudiodev, pipes, smtpd, sndhdr, spwd, sunau, + telnetlib, uu, xdrlib + +- bpo-2604: Fix bug where doctests using globals would fail when run + multiple times. + +- bpo-45997: Fix :class:`asyncio.Semaphore` re-aquiring FIFO order. + +- bpo-47022: The :mod:`asynchat`, :mod:`asyncore` and :mod:`smtpd` modules + have been deprecated since at least Python 3.6. Their documentation and + deprecation warnings and have now been updated to note they will removed + in Python 3.12 (:pep:`594`). + +- bpo-46421: Fix a unittest issue where if the command was invoked as + ``python -m unittest`` and the filename(s) began with a dot (.), a + ``ValueError`` is returned. + +- bpo-40296: Fix supporting generic aliases in :mod:`pydoc`. + + What's New in Python 3.10.3 final? ================================== diff -Nru python3.10-3.10.3/Modules/binascii.c python3.10-3.10.4/Modules/binascii.c --- python3.10-3.10.3/Modules/binascii.c 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Modules/binascii.c 2022-03-23 20:12:04.000000000 +0000 @@ -1120,16 +1120,20 @@ /*[clinic end generated code: output=52cf59056a78593b input=bbe340bc99d25aa8]*/ #ifdef USE_ZLIB_CRC32 -/* This was taken from zlibmodule.c PyZlib_crc32 (but is PY_SSIZE_T_CLEAN) */ +/* The same core as zlibmodule.c zlib_crc32_impl. */ { - const Byte *buf; - Py_ssize_t len; - int signed_val; + unsigned char *buf = data->buf; + Py_ssize_t len = data->len; - buf = (Byte*)data->buf; - len = data->len; - signed_val = crc32(crc, buf, len); - return (unsigned int)signed_val & 0xffffffffU; + /* Avoid truncation of length for very large buffers. crc32() takes + length as an unsigned int, which may be narrower than Py_ssize_t. */ + while ((size_t)len > UINT_MAX) { + crc = crc32(crc, buf, UINT_MAX); + buf += (size_t) UINT_MAX; + len -= (size_t) UINT_MAX; + } + crc = crc32(crc, buf, (unsigned int)len); + return crc & 0xffffffff; } #else /* USE_ZLIB_CRC32 */ { /* By Jim Ahlstrom; All rights transferred to CNRI */ diff -Nru python3.10-3.10.3/Modules/faulthandler.c python3.10-3.10.4/Modules/faulthandler.c --- python3.10-3.10.3/Modules/faulthandler.c 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Modules/faulthandler.c 2022-03-23 20:12:04.000000000 +0000 @@ -23,9 +23,9 @@ # define FAULTHANDLER_USE_ALT_STACK #endif -#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) -# include -# include +#if defined(FAULTHANDLER_USE_ALT_STACK) && defined(HAVE_LINUX_AUXVEC_H) && defined(HAVE_SYS_AUXV_H) +# include // AT_MINSIGSTKSZ +# include // getauxval() #endif /* Allocate at maximum 100 MiB of the stack to raise the stack overflow */ diff -Nru python3.10-3.10.3/Modules/_sre.c python3.10-3.10.4/Modules/_sre.c --- python3.10-3.10.3/Modules/_sre.c 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Modules/_sre.c 2022-03-23 20:12:04.000000000 +0000 @@ -2510,6 +2510,25 @@ Py_DECREF(tp); } +static int +scanner_begin(ScannerObject* self) +{ + if (self->executing) { + PyErr_SetString(PyExc_ValueError, + "regular expression scanner already executing"); + return 0; + } + self->executing = 1; + return 1; +} + +static void +scanner_end(ScannerObject* self) +{ + assert(self->executing); + self->executing = 0; +} + /*[clinic input] _sre.SRE_Scanner.match @@ -2527,16 +2546,23 @@ PyObject* match; Py_ssize_t status; - if (state->start == NULL) + if (!scanner_begin(self)) { + return NULL; + } + if (state->start == NULL) { + scanner_end(self); Py_RETURN_NONE; + } state_reset(state); state->ptr = state->start; status = sre_match(state, PatternObject_GetCode(self->pattern)); - if (PyErr_Occurred()) + if (PyErr_Occurred()) { + scanner_end(self); return NULL; + } match = pattern_new_match(module_state, (PatternObject*) self->pattern, state, status); @@ -2548,6 +2574,7 @@ state->start = state->ptr; } + scanner_end(self); return match; } @@ -2569,16 +2596,23 @@ PyObject* match; Py_ssize_t status; - if (state->start == NULL) + if (!scanner_begin(self)) { + return NULL; + } + if (state->start == NULL) { + scanner_end(self); Py_RETURN_NONE; + } state_reset(state); state->ptr = state->start; status = sre_search(state, PatternObject_GetCode(self->pattern)); - if (PyErr_Occurred()) + if (PyErr_Occurred()) { + scanner_end(self); return NULL; + } match = pattern_new_match(module_state, (PatternObject*) self->pattern, state, status); @@ -2590,6 +2624,7 @@ state->start = state->ptr; } + scanner_end(self); return match; } @@ -2607,6 +2642,7 @@ if (!scanner) return NULL; scanner->pattern = NULL; + scanner->executing = 0; /* create search state object */ if (!state_init(&scanner->state, self, string, pos, endpos)) { diff -Nru python3.10-3.10.3/Modules/sre.h python3.10-3.10.4/Modules/sre.h --- python3.10-3.10.3/Modules/sre.h 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/Modules/sre.h 2022-03-23 20:12:04.000000000 +0000 @@ -89,6 +89,7 @@ PyObject_HEAD PyObject* pattern; SRE_STATE state; + int executing; } ScannerObject; #endif diff -Nru python3.10-3.10.3/pyconfig.h.in python3.10-3.10.4/pyconfig.h.in --- python3.10-3.10.3/pyconfig.h.in 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/pyconfig.h.in 2022-03-23 20:12:04.000000000 +0000 @@ -1128,6 +1128,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_AUDIOIO_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_AUXV_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_BSDTTY_H diff -Nru python3.10-3.10.3/README.rst python3.10-3.10.4/README.rst --- python3.10-3.10.3/README.rst 2022-03-16 11:27:11.000000000 +0000 +++ python3.10-3.10.4/README.rst 2022-03-23 20:12:04.000000000 +0000 @@ -1,4 +1,4 @@ -This is Python version 3.10.3 +This is Python version 3.10.4 ============================= .. image:: https://travis-ci.com/python/cpython.svg?branch=master