From 0812d632d59d3b96164576a3e3f67f473b777cce Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee
Date: Sat, 14 Oct 2023 09:43:41 +0200
Subject: [PATCH 01/10] Rework naming of frameworks.
---
patch/Python/Python.patch | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch
index 58eed4a6..8565d734 100644
--- a/patch/Python/Python.patch
+++ b/patch/Python/Python.patch
@@ -70,7 +70,7 @@ index 0c2510e161..5567080ba5 100644
def find_library(name):
possible = ['lib%s.dylib' % name,
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
-index 73ac4405cb..5abec62047 100644
+index 73ac4405cb..0d830eed7b 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -52,7 +52,7 @@
@@ -82,7 +82,7 @@ index 73ac4405cb..5abec62047 100644
_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
-@@ -1690,6 +1690,60 @@
+@@ -1690,6 +1690,59 @@
return f'FileFinder({self.path!r})'
@@ -129,10 +129,9 @@ index 73ac4405cb..5abec62047 100644
+
+ def find_spec(self, fullname, path, target=None):
+ name = fullname.split(".")[-1]
-+ framework_name = "_".join(fullname.split("."))
+
+ for extension in EXTENSION_SUFFIXES:
-+ dylib_file = _path_join(self.frameworks_path, f"{framework_name}.framework", f"{name}{extension}")
++ dylib_file = _path_join(self.frameworks_path, f"{fullname}.framework", f"{name}{extension}")
+ _bootstrap._verbose_message('Looking for Apple Framework dylib {}', dylib_file)
+ if _path_isfile(dylib_file):
+ loader = AppleFrameworkLoader(fullname, dylib_file, path)
@@ -143,7 +142,7 @@ index 73ac4405cb..5abec62047 100644
# Import setup ###############################################################
def _fix_up_module(ns, name, pathname, cpathname=None):
-@@ -1739,3 +1793,7 @@
+@@ -1739,3 +1792,7 @@
supported_loaders = _get_supported_file_loaders()
sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
sys.meta_path.append(PathFinder)
From d92ed41d6556795ef25508cdc1450cefbbbc52b5 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee
Date: Mon, 5 Aug 2024 14:33:15 +0800
Subject: [PATCH 02/10] Update to Python 3.12.4.
---
Makefile | 8 +-
patch/Python/Python.patch | 11377 +++++++++++++++++++++++++++++-------
2 files changed, 9288 insertions(+), 2097 deletions(-)
diff --git a/Makefile b/Makefile
index f1cca4e9..27ec788b 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ BUILD_NUMBER=custom
# PYTHON_VERSION is the full version number (e.g., 3.10.0b3)
# PYTHON_MICRO_VERSION is the full version number, without any alpha/beta/rc suffix. (e.g., 3.10.0)
# PYTHON_VER is the major/minor version (e.g., 3.10)
-PYTHON_VERSION=3.12.0
+PYTHON_VERSION=3.12.4
PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+")
PYTHON_VER=$(basename $(PYTHON_VERSION))
@@ -124,10 +124,8 @@ ARCH-$(target)=$$(subst .,,$$(suffix $(target)))
ifneq ($(os),macOS)
ifeq ($$(findstring simulator,$$(SDK-$(target))),)
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os))
-TARGET_TOOL_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))
else
TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os))-simulator
-TARGET_TOOL_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))-simulator
endif
endif
@@ -280,10 +278,6 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \
cd $$(PYTHON_SRCDIR-$(target)) && \
PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \
./configure \
- AR=$$(TARGET_TOOL_TRIPLE-$(target))-ar \
- CC=$$(TARGET_TOOL_TRIPLE-$(target))-clang \
- CPP=$$(TARGET_TOOL_TRIPLE-$(target))-cpp \
- CXX=$$(TARGET_TOOL_TRIPLE-$(target))-clang \
LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \
LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \
BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \
diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch
index 8565d734..1e02a539 100644
--- a/patch/Python/Python.patch
+++ b/patch/Python/Python.patch
@@ -1,2232 +1,7450 @@
-diff --git a/Include/internal/pycore_faulthandler.h b/Include/internal/pycore_faulthandler.h
-index e6aec7745a..55a09a1970 100644
---- a/Include/internal/pycore_faulthandler.h
-+++ b/Include/internal/pycore_faulthandler.h
-@@ -12,6 +12,14 @@
- # include
- #endif
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
+--- /dev/null
++++ b/Doc/includes/wasm-ios-notavail.rst
+@@ -0,0 +1,8 @@
++.. include for modules that don't work on WASM or iOS
++
++.. availability:: not WASI, not iOS.
++
++ This module does not work or is not available on WebAssembly platforms, or
++ on iOS. See :ref:`wasm-availability` for more information on WASM
++ availability; see :ref:`iOS-availability` for more information on iOS
++ availability.
+diff --git a/Doc/includes/wasm-notavail.rst b/Doc/includes/wasm-notavail.rst
+index e680e1f9b43..c1b79d2a4a0 100644
+--- a/Doc/includes/wasm-notavail.rst
++++ b/Doc/includes/wasm-notavail.rst
+@@ -1,7 +1,6 @@
+ .. include for modules that don't work on WASM
+
+-.. availability:: not Emscripten, not WASI.
++.. availability:: not WASI.
+
+- This module does not work or is not available on WebAssembly platforms
+- ``wasm32-emscripten`` and ``wasm32-wasi``. See
++ This module does not work or is not available on WebAssembly. See
+ :ref:`wasm-availability` for more information.
+diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
+index 2ebda3d3396..91ea6150fb1 100644
+--- a/Doc/library/curses.rst
++++ b/Doc/library/curses.rst
+@@ -21,6 +21,8 @@
+ designed to match the API of ncurses, an open-source curses library hosted on
+ Linux and the BSD variants of Unix.
+
++.. include:: ../includes/wasm-ios-notavail.rst
+
-+// tvOS and watchOS don't provide a number of important POSIX functions.
-+#if TARGET_OS_TV || TARGET_OS_WATCH
-+# undef HAVE_SIGALTSTACK
-+#endif /* TVOS || WATCHOS */
+ .. note::
- #ifndef MS_WINDOWS
- /* register() is useless on Windows, because only SIGSEGV, SIGABRT and
---- /dev/null
-+++ b/Lib/_ios_support.py
-@@ -0,0 +1,36 @@
-+from ctypes import cdll, c_void_p, c_char_p
-+from ctypes import util
+ Whenever the documentation mentions a *character* it can be specified
+diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst
+index 500e831908f..7f7d650bf5d 100644
+--- a/Doc/library/dbm.rst
++++ b/Doc/library/dbm.rst
+@@ -14,6 +14,7 @@
+ is a `third party interface `_ to
+ the Oracle Berkeley DB.
+
++.. include:: ../includes/wasm-ios-notavail.rst
+
+ .. exception:: error
+
+@@ -398,4 +399,3 @@
+ .. method:: dumbdbm.close()
+
+ Close the database.
+-
+diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst
+index 3726028492a..518a2940edc 100644
+--- a/Doc/library/ensurepip.rst
++++ b/Doc/library/ensurepip.rst
+@@ -38,7 +38,7 @@
+ :pep:`453`: Explicit bootstrapping of pip in Python installations
+ The original rationale and specification for this module.
+
+-.. include:: ../includes/wasm-notavail.rst
++.. include:: ../includes/wasm-ios-notavail.rst
+
+ Command line interface
+ ----------------------
+diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst
+index d23a105cd5b..1faef54c116 100644
+--- a/Doc/library/fcntl.rst
++++ b/Doc/library/fcntl.rst
+@@ -18,7 +18,7 @@
+ See the :manpage:`fcntl(2)` and :manpage:`ioctl(2)` Unix manual pages
+ for full details.
+
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI.
+
+ All functions in this module take a file descriptor *fd* as their first
+ argument. This can be an integer file descriptor, such as returned by
+diff --git a/Doc/library/grp.rst b/Doc/library/grp.rst
+index 57a77d51a02..f1157e189a3 100644
+--- a/Doc/library/grp.rst
++++ b/Doc/library/grp.rst
+@@ -10,7 +10,7 @@
+ This module provides access to the Unix group database. It is available on all
+ Unix versions.
+
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI, not iOS.
+
+ Group database entries are reported as a tuple-like object, whose attributes
+ correspond to the members of the ``group`` structure (Attribute field below, see
+diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
+index d92bb2f8e5c..b58ef359378 100644
+--- a/Doc/library/importlib.rst
++++ b/Doc/library/importlib.rst
+@@ -1241,6 +1241,69 @@
+ and how the module's :attr:`__file__` is populated.
+
+
++.. class:: AppleFrameworkLoader(name, path)
+
++ A specialization of :class:`importlib.machinery.ExtensionFileLoader` that
++ is able to load extension modules in Framework format.
+
-+def get_platform_ios():
-+ objc = cdll.LoadLibrary(util.find_library(b'objc'))
++ For compatibility with the iOS App Store, *all* binary modules in an iOS app
++ must be dynamic libraries, contained in a framework with appropriate
++ metadata, stored in the ``Frameworks`` folder of the packaged app. There can
++ be only a single binary per framework, and there can be no executable binary
++ material outside the Frameworks folder.
+
-+ objc.objc_getClass.restype = c_void_p
-+ objc.objc_getClass.argtypes = [c_char_p]
-+ objc.objc_msgSend.restype = c_void_p
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
-+ objc.sel_registerName.restype = c_void_p
-+ objc.sel_registerName.argtypes = [c_char_p]
++ To accomodate this requirement, when running on iOS, extension module
++ binaries are *not* packaged as ``.so`` files on ``sys.path``, but as
++ individual standalone frameworks. To discover those frameworks, this loader
++ is be registered against the ``.fwork`` file extension, with a ``.fwork``
++ file acting as a placeholder in the original location of the binary on
++ ``sys.path``. The ``.fwork`` file contains the path of the actual binary in
++ the ``Frameworks`` folder, relative to the app bundle. To allow for
++ resolving a framework-packaged binary back to the original location, the
++ framework is expected to contain a ``.origin`` file that contains the
++ location of the ``.fwork`` file, relative to the app bundle.
+
-+ UIDevice = c_void_p(objc.objc_getClass(b'UIDevice'))
-+ SEL_currentDevice = c_void_p(objc.sel_registerName(b'currentDevice'))
-+ device = c_void_p(objc.objc_msgSend(UIDevice, SEL_currentDevice))
++ For example, consider the case of an import ``from foo.bar import _whiz``,
++ where ``_whiz`` is implemented with the binary module
++ ``sources/foo/bar/_whiz.abi3.so``, with ``sources`` being the location
++ registered on ``sys.path``, relative to the application bundle. This module
++ *must* be distributed as
++ ``Frameworks/foo.bar._whiz.framework/foo.bar._whiz`` (creating the framework
++ name from the full import path of the module), with an ``Info.plist`` file
++ in the ``.framework`` directory identifying the binary as a framework. The
++ ``foo.bar._whiz`` module would be represented in the original location with
++ a ``sources/foo/bar/_whiz.abi3.fwork`` marker file, containing the path
++ ``Frameworks/foo.bar._whiz/foo.bar._whiz``. The framework would also contain
++ ``Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin``, containing the
++ path to the ``.fwork`` file.
+
-+ SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion'))
-+ systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion))
++ When a module is loaded with this loader, the ``__file__`` for the module
++ will report as the location of the ``.fwork`` file. This allows code to use
++ the ``__file__`` of a module as an anchor for file system traveral.
++ However, the spec origin will reference the location of the *actual* binary
++ in the ``.framework`` folder.
+
-+ SEL_systemName = c_void_p(objc.sel_registerName(b'systemName'))
-+ systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName))
++ The Xcode project building the app is responsible for converting any ``.so``
++ files from wherever they exist in the ``PYTHONPATH`` into frameworks in the
++ ``Frameworks`` folder (including stripping extensions from the module file,
++ the addition of framework metadata, and signing the resulting framework),
++ and creating the ``.fwork`` and ``.origin`` files. This will usually be done
++ with a build step in the Xcode project; see the iOS documentation for
++ details on how to construct this build step.
+
-+ SEL_model = c_void_p(objc.sel_registerName(b'model'))
-+ systemModel = c_void_p(objc.objc_msgSend(device, SEL_model))
++ .. versionadded:: 3.13
+
-+ # UTF8String returns a const char*;
-+ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String'))
-+ objc.objc_msgSend.restype = c_char_p
++ .. availability:: iOS.
+
-+ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode()
-+ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode()
-+ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode()
++ .. attribute:: name
+
-+ return system, release, model
-diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
-index 0c2510e161..5567080ba5 100644
---- a/Lib/ctypes/util.py
-+++ b/Lib/ctypes/util.py
-@@ -67,7 +67,7 @@
- return fname
- return None
-
--elif os.name == "posix" and sys.platform == "darwin":
-+elif os.name == "posix" and sys.platform in {'darwin', 'ios', 'tvos', 'watchos'}:
- from ctypes.macholib.dyld import dyld_find as _dyld_find
- def find_library(name):
- possible = ['lib%s.dylib' % name,
-diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
-index 73ac4405cb..0d830eed7b 100644
---- a/Lib/importlib/_bootstrap_external.py
-+++ b/Lib/importlib/_bootstrap_external.py
-@@ -52,7 +52,7 @@
-
- # Bootstrap-related code ######################################################
- _CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
--_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
-+_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
- _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
- + _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
-
-@@ -1690,6 +1690,59 @@
- return f'FileFinder({self.path!r})'
-
-
-+class AppleFrameworkLoader(ExtensionFileLoader):
-+ """A loader for modules that have been packaged as Apple Frameworks for
-+ compatibility with Apple's App Store policies.
-+
-+ For compatibility with the App Store, *all* binary modules must be in .dylibs,
-+ contained in a Framework, in the ``Frameworks`` folder of the packaged app. If
-+ you're trying to run "from foo import _bar", and _bar is implemented with the binary
-+ module "foo/_bar.abi3.dylib" (or any other .dylib extension), this loader will look
-+ for "{sys.executable}/Frameworks/foo__bar.framework/_bar.abi3.dylib" (forming the
-+ package name by taking the full path of the library, and replacing ``/`` with
-+ ``_``). The app packaging tool is responsible for putting the library in this
-+ location.
-+
-+ However, the ``__file__`` attribute of the _bar module will report as the original
-+ location inside the ``foo`` directory. This so that code that depends on walking
-+ directory trees will continue to work as expected based on the *original* file
-+ location.
-+ """
-+ def __init__(self, fullname, dylib_file, path):
-+ super().__init__(fullname, dylib_file)
-+ self.parent_paths = path
++ Name of the module the loader supports.
+
-+ def create_module(self, spec):
-+ mod = super().create_module(spec)
-+ if self.parent_paths:
-+ for parent_path in self.parent_paths:
-+ if _path_isdir(parent_path):
-+ mod.__file__ = _path_join(parent_path, _path_split(self.path)[-1])
-+ continue
-+ return mod
++ .. attribute:: path
+
++ Path to the ``.fwork`` file for the extension module.
+
-+class AppleFrameworkFinder:
-+ """A finder for modules that have been packaged as Apple Frameworks
-+ for compatibility with Apple's App Store policies.
+
-+ See AppleFrameworkLoader for details.
-+ """
-+ def __init__(self, path):
-+ self.frameworks_path = path
+ :mod:`importlib.util` -- Utility code for importers
+ ---------------------------------------------------
+
+diff --git a/Doc/library/intro.rst b/Doc/library/intro.rst
+index 5a4c9b8b16a..ffc8939d211 100644
+--- a/Doc/library/intro.rst
++++ b/Doc/library/intro.rst
+@@ -58,7 +58,7 @@
+ operating system.
+
+ * If not separately noted, all functions that claim "Availability: Unix" are
+- supported on macOS, which builds on a Unix core.
++ supported on macOS and iOS, both of which build on a Unix core.
+
+ * If an availability note contains both a minimum Kernel version and a minimum
+ libc version, then both conditions must hold. For example a feature with note
+@@ -119,3 +119,44 @@
+ .. _wasmtime: https://wasmtime.dev/
+ .. _Pyodide: https://pyodide.org/
+ .. _PyScript: https://pyscript.net/
+
-+ def find_spec(self, fullname, path, target=None):
-+ name = fullname.split(".")[-1]
++.. _iOS-availability:
+
-+ for extension in EXTENSION_SUFFIXES:
-+ dylib_file = _path_join(self.frameworks_path, f"{fullname}.framework", f"{name}{extension}")
-+ _bootstrap._verbose_message('Looking for Apple Framework dylib {}', dylib_file)
-+ if _path_isfile(dylib_file):
-+ loader = AppleFrameworkLoader(fullname, dylib_file, path)
-+ return _bootstrap.spec_from_loader(fullname, loader)
++iOS
++---
+
-+ return None
++iOS is, in most respects, a POSIX operating system. File I/O, socket handling,
++and threading all behave as they would on any POSIX operating system. However,
++there are several major differences between iOS and other POSIX systems.
+
- # Import setup ###############################################################
-
- def _fix_up_module(ns, name, pathname, cpathname=None):
-@@ -1739,3 +1792,7 @@
- supported_loaders = _get_supported_file_loaders()
- sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
- sys.meta_path.append(PathFinder)
-+ if sys.platform in {"ios", "tvos", "watchos"}:
-+ frameworks_folder = _path_join(_path_split(sys.executable)[0], "Frameworks")
-+ _bootstrap._verbose_message('Adding Apple Framework dylib finder at {}', frameworks_folder)
-+ sys.meta_path.append(AppleFrameworkFinder(frameworks_folder))
-diff --git a/Lib/platform.py b/Lib/platform.py
-index 7bb222088d..0a5ed0361e 100755
---- a/Lib/platform.py
-+++ b/Lib/platform.py
-@@ -496,6 +496,26 @@
- # If that also doesn't work return the default values
- return release, versioninfo, machine
-
-+def iOS_ver():
-+ """Get iOS/tvOS version information, and return it as a
-+ tuple (system, release, model). All tuple entries are strings.
-+ """
-+ import _ios_support
-+ return _ios_support.get_platform_ios()
++* iOS can only use Python in "embedded" mode. There is no Python REPL, and no
++ ability to execute binaries that are part of the normal Python developer
++ experience, such as :program:`pip`. To add Python code to your iOS app, you must use
++ the :ref:`Python embedding API ` to add a Python interpreter to an
++ iOS app created with Xcode. See the :ref:`iOS usage guide ` for
++ more details.
+
-+def is_simulator():
-+ """Determine if the current platform is a device simulator.
++* An iOS app cannot use any form of subprocessing, background processing, or
++ inter-process communication. If an iOS app attempts to create a subprocess,
++ the process creating the subprocess will either lock up, or crash. An iOS app
++ has no visibility of other applications that are running, nor any ability to
++ communicate with other running applications, outside of the iOS-specific APIs
++ that exist for this purpose.
+
-+ Only useful when working with iOS, tvOS or watchOS, because
-+ Apple provides simulator platforms for those devices.
++* iOS apps have limited access to modify system resources (such as the system
++ clock). These resources will often be *readable*, but attempts to modify
++ those resources will usually fail.
+
-+ If the platform is actual hardware, returns False. Will also
-+ return False for device *emulators*, which are indistinguishable
-+ from actual devices because they are reproducing actual device
-+ properties.
-+ """
-+ return getattr(sys.implementation, "_simulator", False)
++* iOS apps have a limited concept of console input and output. ``stdout`` and
++ ``stderr`` *exist*, and content written to ``stdout`` and ``stderr`` will be
++ visible in logs when running in Xcode, but this content *won't* be recorded
++ in the system log. If a user who has installed your app provides their app
++ logs as a diagnostic aid, they will not include any detail written to
++ ``stdout`` or ``stderr``.
+
- def _java_getprop(name, default):
++ iOS apps have no concept of ``stdin`` at all. While iOS apps can have a
++ keyboard, this is a software feature, not something that is attached to
++ ``stdin``.
++
++ As a result, Python library that involve console manipulation (such as
++ :mod:`curses` and :mod:`readline`) are not available on iOS.
+diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
+index d6474ef975b..d53d0103a5c 100644
+--- a/Doc/library/multiprocessing.rst
++++ b/Doc/library/multiprocessing.rst
+@@ -8,7 +8,7 @@
- from java.lang import System
-@@ -652,7 +672,7 @@
- default in case the command should fail.
+ --------------
+
+-.. include:: ../includes/wasm-notavail.rst
++.. include:: ../includes/wasm-ios-notavail.rst
+
+ Introduction
+ ------------
+diff --git a/Doc/library/os.rst b/Doc/library/os.rst
+index a793d244de9..968024fd5cf 100644
+--- a/Doc/library/os.rst
++++ b/Doc/library/os.rst
+@@ -34,12 +34,13 @@
+
+ * On VxWorks, os.popen, os.fork, os.execv and os.spawn*p* are not supported.
+
+-* On WebAssembly platforms ``wasm32-emscripten`` and ``wasm32-wasi``, large
+- parts of the :mod:`os` module are not available or behave differently. API
+- related to processes (e.g. :func:`~os.fork`, :func:`~os.execve`), signals
+- (e.g. :func:`~os.kill`, :func:`~os.wait`), and resources
+- (e.g. :func:`~os.nice`) are not available. Others like :func:`~os.getuid`
+- and :func:`~os.getpid` are emulated or stubs.
++* On WebAssembly platforms ``wasm32-emscripten`` and ``wasm32-wasi``, and on
++ iOS, large parts of the :mod:`os` module are not available or behave
++ differently. API related to processes (e.g. :func:`~os.fork`,
++ :func:`~os.execve`) and resources (e.g. :func:`~os.nice`) are not available.
++ Others like :func:`~os.getuid` and :func:`~os.getpid` are emulated or stubs.
++ WebAssembly platforms also lack support for signals (e.g. :func:`~os.kill`,
++ :func:`~os.wait`).
+
+
+ .. note::
+@@ -784,6 +785,11 @@
+ :func:`socket.gethostname` or even
+ ``socket.gethostbyaddr(socket.gethostname())``.
+
++ On macOS, iOS and Android, this returns the *kernel* name and version (i.e.,
++ ``'Darwin'`` on macOS and iOS; ``'Linux'`` on Android). :func:`platform.uname()`
++ can be used to get the user-facing operating system name and version on iOS and
++ Android.
++
+ .. availability:: Unix.
- """
-- if sys.platform in ('dos', 'win32', 'win16'):
-+ if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'}:
- # XXX Others too ?
- return default
+ .. versionchanged:: 3.3
+@@ -3997,7 +4003,7 @@
-@@ -814,6 +834,24 @@
- csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
- return 'Alpha' if cpu_number >= 128 else 'VAX'
+ .. audit-event:: os.exec path,args,env os.execl
-+ # On iOS, tvOS and watchOS, os.uname returns the architecture
-+ # as uname.machine. On device it doesn't; but there's only
-+ # on CPU architecture on device
-+ def get_ios():
-+ if getattr(sys.implementation, "_simulator", False):
-+ return os.uname().machine
-+ return 'arm64'
-+
-+ def get_tvos():
-+ if getattr(sys.implementation, "_simulator", False):
-+ return os.uname().machine
-+ return 'arm64'
-+
-+ def get_watchos():
-+ if getattr(sys.implementation, "_simulator", False):
-+ return os.uname().machine
-+ return 'arm64_32'
-+
- def from_subprocess():
- """
- Fall back to `uname -p`
-@@ -968,6 +1006,15 @@
- system = 'Windows'
- release = 'Vista'
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
-+ # Normalize responses on Apple mobile platforms
-+ if sys.platform in {'ios', 'tvos'}:
-+ system, release, model = iOS_ver()
-+
-+ # On iOS/tvOS simulators, os.uname() reports the machine as something
-+ # like "arm64" or "x86_64".
-+ if getattr(sys.implementation, "_simulator", False):
-+ machine = f'{model}Simulator'
-+
- vals = system, node, release, version, machine
- # Replace 'unknown' values with the more portable ''
- _uname_cache = uname_result(*map(_unknown_as_blank, vals))
-@@ -1247,11 +1294,13 @@
- system, release, version = system_alias(system, release, version)
+ .. versionchanged:: 3.3
+ Added support for specifying *path* as an open file descriptor
+@@ -4200,7 +4206,7 @@
+ for technical details of why we're surfacing this longstanding
+ platform compatibility problem to developers.
- if system == 'Darwin':
-- # macOS (darwin kernel)
-- macos_release = mac_ver()[0]
-- if macos_release:
-- system = 'macOS'
-- release = macos_release
-+ if sys.platform in {'ios', 'tvos'}:
-+ system, release, _ = iOS_ver()
-+ else:
-+ macos_release = mac_ver()[0]
-+ if macos_release:
-+ system = 'macOS'
-+ release = macos_release
+- .. availability:: POSIX, not Emscripten, not WASI.
++ .. availability:: POSIX, not Emscripten, not WASI, not iOS.
- if system == 'Windows':
- # MS platforms
-diff --git a/Lib/site.py b/Lib/site.py
-index 672fa7b000..9fd399e990 100644
---- a/Lib/site.py
-+++ b/Lib/site.py
-@@ -294,6 +294,9 @@
- if sys.platform == 'darwin' and sys._framework:
- return f'{userbase}/lib/python/site-packages'
-+ elif sys.platform in ('ios', 'tvos', 'watchos'):
-+ from sysconfig import get_path
-+ return get_path('purelib', sys.platform)
+ .. function:: forkpty()
+@@ -4227,7 +4233,7 @@
+ threads, this now raises a :exc:`DeprecationWarning`. See the
+ longer explanation on :func:`os.fork`.
- return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages'
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-diff --git a/Lib/subprocess.py b/Lib/subprocess.py
-index 6df5dd551e..597da09643 100644
---- a/Lib/subprocess.py
-+++ b/Lib/subprocess.py
-@@ -74,8 +74,8 @@
- else:
- _mswindows = True
--# wasm32-emscripten and wasm32-wasi do not support processes
--_can_fork_exec = sys.platform not in {"emscripten", "wasi"}
-+# some platforms do not support processes
-+_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
+ .. function:: kill(pid, sig, /)
+@@ -4251,7 +4257,7 @@
- if _mswindows:
- import _winapi
-@@ -103,18 +103,22 @@
- if _can_fork_exec:
- from _posixsubprocess import fork_exec as _fork_exec
- # used in methods that are called by __del__
-- _waitpid = os.waitpid
-- _waitstatus_to_exitcode = os.waitstatus_to_exitcode
-- _WIFSTOPPED = os.WIFSTOPPED
-- _WSTOPSIG = os.WSTOPSIG
-- _WNOHANG = os.WNOHANG
-+ class _del_safe:
-+ waitpid = os.waitpid
-+ waitstatus_to_exitcode = os.waitstatus_to_exitcode
-+ WIFSTOPPED = os.WIFSTOPPED
-+ WSTOPSIG = os.WSTOPSIG
-+ WNOHANG = os.WNOHANG
-+ ECHILD = errno.ECHILD
- else:
-- _fork_exec = None
-- _waitpid = None
-- _waitstatus_to_exitcode = None
-- _WIFSTOPPED = None
-- _WSTOPSIG = None
-- _WNOHANG = None
-+ class _del_safe:
-+ waitpid = None
-+ waitstatus_to_exitcode = None
-+ WIFSTOPPED = None
-+ WSTOPSIG = None
-+ WNOHANG = None
-+ ECHILD = errno.ECHILD
-+
- import select
- import selectors
+ .. audit-event:: os.kill pid,sig os.kill
-@@ -1951,20 +1955,16 @@
- raise child_exception_type(err_msg)
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
+ .. versionchanged:: 3.2
+ Added Windows support.
+@@ -4267,7 +4273,7 @@
-- def _handle_exitstatus(self, sts,
-- _waitstatus_to_exitcode=_waitstatus_to_exitcode,
-- _WIFSTOPPED=_WIFSTOPPED,
-- _WSTOPSIG=_WSTOPSIG):
-+ def _handle_exitstatus(self, sts, _del_safe=_del_safe):
- """All callers to this function MUST hold self._waitpid_lock."""
- # This method is called (indirectly) by __del__, so it cannot
- # refer to anything outside of its local scope.
-- if _WIFSTOPPED(sts):
-- self.returncode = -_WSTOPSIG(sts)
-+ if _del_safe.WIFSTOPPED(sts):
-+ self.returncode = -_del_safe.WSTOPSIG(sts)
- else:
-- self.returncode = _waitstatus_to_exitcode(sts)
-+ self.returncode = _del_safe.waitstatus_to_exitcode(sts)
+ .. audit-event:: os.killpg pgid,sig os.killpg
-- def _internal_poll(self, _deadstate=None, _waitpid=_waitpid,
-- _WNOHANG=_WNOHANG, _ECHILD=errno.ECHILD):
-+ def _internal_poll(self, _deadstate=None, _del_safe=_del_safe):
- """Check if child process has terminated. Returns returncode
- attribute.
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-@@ -1980,13 +1980,13 @@
- try:
- if self.returncode is not None:
- return self.returncode # Another thread waited.
-- pid, sts = _waitpid(self.pid, _WNOHANG)
-+ pid, sts = _del_safe.waitpid(self.pid, _del_safe.WNOHANG)
- if pid == self.pid:
- self._handle_exitstatus(sts)
- except OSError as e:
- if _deadstate is not None:
- self.returncode = _deadstate
-- elif e.errno == _ECHILD:
-+ elif e.errno == _del_safe.ECHILD:
- # This happens if SIGCLD is set to be ignored or
- # waiting for child processes has otherwise been
- # disabled for our process. This child is dead, we
-diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py
-index 122d441bd1..fdf2f4e471 100644
---- a/Lib/sysconfig.py
-+++ b/Lib/sysconfig.py
-@@ -96,6 +96,33 @@
- 'scripts': '{base}/Scripts',
- 'data': '{base}',
- },
-+ 'ios': {
-+ 'stdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'platstdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
-+ 'tvos': {
-+ 'stdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'platstdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
-+ 'watchos': {
-+ 'stdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'platstdlib': '{installed_base}/lib/python{py_version_short}',
-+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages',
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
- }
- # For the OS-native venv scheme, we essentially provide an alias:
-@@ -288,12 +315,19 @@
- 'home': 'posix_home',
- 'user': 'nt_user',
- }
-+ if sys.platform in ('ios', 'tvos', 'watchos'):
-+ return {
-+ 'prefix': sys.platform,
-+ 'home': sys.platform,
-+ 'user': sys.platform,
-+ }
- if sys.platform == 'darwin' and sys._framework:
- return {
- 'prefix': 'posix_prefix',
- 'home': 'posix_home',
- 'user': 'osx_framework_user',
- }
-+
- return {
- 'prefix': 'posix_prefix',
- 'home': 'posix_home',
-@@ -813,10 +847,16 @@
- if m:
- release = m.group()
- elif osname[:6] == "darwin":
-- import _osx_support
-- osname, release, machine = _osx_support.get_platform_osx(
-- get_config_vars(),
-- osname, release, machine)
-+ if sys.platform in ("ios", "tvos", "watchos"):
-+ import _ios_support
-+ _, release, _ = _ios_support.get_platform_ios()
-+ osname = sys.platform
-+ machine = sys.implementation._multiarch
-+ else:
-+ import _osx_support
-+ osname, release, machine = _osx_support.get_platform_osx(
-+ get_config_vars(),
-+ osname, release, machine)
+ .. function:: nice(increment, /)
+@@ -4304,7 +4310,7 @@
+ Lock program segments into memory. The value of *op* (defined in
+ ````) determines which segments are locked.
- return f"{osname}-{release}-{machine}"
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
-index b6350e4e52..b45249e014 100644
---- a/Lib/test/support/__init__.py
-+++ b/Lib/test/support/__init__.py
-@@ -46,7 +46,7 @@
- "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
- "requires_limited_api", "requires_specialization",
- # sys
-- "is_jython", "is_android", "is_emscripten", "is_wasi",
-+ "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile",
- "check_impl_detail", "unix_shell", "setswitchinterval",
- # os
- "get_pagesize",
-@@ -520,7 +520,7 @@
- is_android = hasattr(sys, 'getandroidapilevel')
+ .. function:: popen(cmd, mode='r', buffering=-1)
+@@ -4336,7 +4342,7 @@
+ documentation for more powerful ways to manage and communicate with
+ subprocesses.
--if sys.platform not in ('win32', 'vxworks'):
-+if sys.platform not in ('win32', 'vxworks', 'ios', 'tvos', 'watchos'):
- unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
- else:
- unix_shell = None
-@@ -530,12 +530,25 @@
- is_emscripten = sys.platform == "emscripten"
- is_wasi = sys.platform == "wasi"
+- .. availability:: not Emscripten, not WASI.
++ .. availability:: not Emscripten, not WASI, not iOS.
--has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi
-+# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
-+# have subprocess or fork support.
-+is_apple_mobile = sys.platform in ('ios', 'tvos', 'watchos')
-+
-+has_fork_support = (
-+ hasattr(os, "fork")
-+ and not is_emscripten
-+ and not is_wasi
-+ and not is_apple_mobile
-+)
+ .. note::
+ The :ref:`Python UTF-8 Mode ` affects encodings used
+@@ -4431,7 +4437,7 @@
- def requires_fork():
- return unittest.skipUnless(has_fork_support, "requires working os.fork()")
+ .. versionadded:: 3.8
--has_subprocess_support = not is_emscripten and not is_wasi
-+has_subprocess_support = (
-+ not is_emscripten
-+ and not is_wasi
-+ and not is_apple_mobile
-+)
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- def requires_subprocess():
- """Used for subprocess, os.spawn calls, fd inheritance"""
-diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
-index 1647d2308c..9b8b53adb0 100644
---- a/Lib/test/test_asyncio/test_events.py
-+++ b/Lib/test/test_asyncio/test_events.py
-@@ -34,6 +34,7 @@
- from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests
- from test.test_asyncio import utils as test_utils
- from test import support
-+from test.support import is_apple_mobile
- from test.support import socket_helper
- from test.support import threading_helper
- from test.support import ALWAYS_EQ, LARGEST, SMALLEST
-@@ -543,6 +544,7 @@
- self._basetest_create_connection(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_connection(self):
- # Issue #20682: On Mac OS X Tiger, getsockname() returns a
- # zero-length address for UNIX socket.
-@@ -635,6 +637,7 @@
- self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
-
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_ssl_connection(self):
- with test_utils.run_test_server(use_ssl=True) as httpd:
- create_connection = functools.partial(
-@@ -646,6 +649,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_ssl_unix_connection(self):
- # Issue #20682: On Mac OS X Tiger, getsockname() returns a
- # zero-length address for UNIX socket.
-@@ -927,6 +931,7 @@
- return server, path
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_unix_server(lambda: proto)
-@@ -955,6 +960,7 @@
- server.close()
-
- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_path_socket_error(self):
- proto = MyProto(loop=self.loop)
- sock = socket.socket()
-@@ -1020,6 +1026,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-@@ -1050,6 +1057,7 @@
- server.close()
-
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_server_ssl_verify_failed(self):
- proto = MyProto(loop=self.loop)
- server, host, port = self._make_ssl_server(
-@@ -1080,6 +1088,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl_verify_failed(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-@@ -1140,6 +1149,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl_verified(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
-index 7f9dc62180..b79cf66684 100644
---- a/Lib/test/test_asyncio/test_streams.py
-+++ b/Lib/test/test_asyncio/test_streams.py
-@@ -18,6 +18,7 @@
+ .. function:: posix_spawnp(path, argv, env, *, file_actions=None, \
+ setpgroup=None, resetids=False, setsid=False, setsigmask=(), \
+@@ -4447,7 +4453,7 @@
- import asyncio
- from test.test_asyncio import utils as test_utils
-+from test.support import is_apple_mobile
+ .. versionadded:: 3.8
+- .. availability:: POSIX, not Emscripten, not WASI.
++ .. availability:: POSIX, not Emscripten, not WASI, not iOS.
- def tearDownModule():
-@@ -61,6 +62,7 @@
- self._basetest_open_connection(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection(self):
- with test_utils.run_test_unix_server() as httpd:
- conn_fut = asyncio.open_unix_connection(httpd.address)
-@@ -92,6 +94,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection_no_loop_ssl(self):
- with test_utils.run_test_unix_server(use_ssl=True) as httpd:
- conn_fut = asyncio.open_unix_connection(
-@@ -120,6 +123,7 @@
- self._basetest_open_connection_error(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection_error(self):
- with test_utils.run_test_unix_server() as httpd:
- conn_fut = asyncio.open_unix_connection(httpd.address)
-@@ -638,6 +642,7 @@
- self.assertEqual(messages, [])
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_start_unix_server(self):
-
- class MyServer:
-diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
-index cdf3eaac68..f6656b61e6 100644
---- a/Lib/test/test_asyncio/test_unix_events.py
-+++ b/Lib/test/test_asyncio/test_unix_events.py
-@@ -14,6 +14,7 @@
- import unittest
- from unittest import mock
- import warnings
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import wait_process
-@@ -279,6 +280,7 @@
+ See :func:`posix_spawn` documentation.
- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'),
- 'UNIX Sockets are not supported')
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class SelectorEventLoopUnixSocketTests(test_utils.TestCase):
+@@ -4480,7 +4486,7 @@
- def setUp(self):
-diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py
-index 203dd6fe57..8e0999ecd7 100644
---- a/Lib/test/test_fcntl.py
-+++ b/Lib/test/test_fcntl.py
-@@ -6,7 +6,7 @@
- import struct
- import sys
- import unittest
--from test.support import verbose, cpython_only, get_pagesize
-+from test.support import cpython_only, get_pagesize, is_apple_mobile, verbose
- from test.support.import_helper import import_module
- from test.support.os_helper import TESTFN, unlink
+ There is no way to unregister a function.
-@@ -57,7 +57,7 @@
- start_len = "qq"
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
-- or sys.platform == 'darwin'):
-+ or sys.platform == 'darwin' or is_apple_mobile):
- if struct.calcsize('l') == 8:
- off_t = 'l'
- pid_t = 'i'
-diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
-index 15f944734c..0a597bc6bc 100644
---- a/Lib/test/test_httpservers.py
-+++ b/Lib/test/test_httpservers.py
-@@ -31,6 +31,7 @@
+ .. versionadded:: 3.7
- import unittest
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import threading_helper
+@@ -4549,7 +4555,7 @@
-@@ -423,7 +424,7 @@
- with open(os.path.join(self.tempdir, filename), 'wb') as f:
- f.write(os_helper.TESTFN_UNDECODABLE)
- response = self.request(self.base_url + '/')
-- if sys.platform == 'darwin':
-+ if sys.platform == 'darwin' or is_apple_mobile:
- # On Mac OS the HFS+ filesystem replaces bytes that aren't valid
- # UTF-8 into a percent-encoded value.
- for name in os.listdir(self.tempdir):
-diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
-index e032325fbe..e279c3c486 100644
---- a/Lib/test/test_io.py
-+++ b/Lib/test/test_io.py
-@@ -40,6 +40,7 @@
- from test.support.script_helper import (
- assert_python_ok, assert_python_failure, run_python_until_end)
- from test.support import import_helper
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import threading_helper
- from test.support import warnings_helper
-@@ -609,7 +610,7 @@
- # On Windows and Mac OSX this test consumes large resources; It takes
- # a long time to build the >2 GiB file and takes >2 GiB of disk space
- # therefore the resource must be enabled to run this test.
-- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
-+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile:
- support.requires(
- 'largefile',
- 'test requires %s bytes and a long time to run' % self.LARGE)
-diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
-index b7f4c6edf1..d08882adc7 100644
---- a/Lib/test/test_logging.py
-+++ b/Lib/test/test_logging.py
-@@ -43,6 +43,7 @@
- import tempfile
- from test.support.script_helper import assert_python_ok, assert_python_failure
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -1931,6 +1932,7 @@
+ .. audit-event:: os.spawn mode,path,args,env os.spawnl
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixSocketHandlerTest(SocketHandlerTest):
+ :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
+ and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and
+@@ -4673,7 +4679,7 @@
- """Test for SocketHandler with unix sockets."""
-@@ -2011,6 +2013,7 @@
- self.assertEqual(self.log_output, "spam\neggs\n")
+ .. audit-event:: os.system command os.system
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixDatagramHandlerTest(DatagramHandlerTest):
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
- """Test for DatagramHandler using Unix sockets."""
-@@ -2102,6 +2105,7 @@
- self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixSysLogHandlerTest(SysLogHandlerTest):
+ .. function:: times()
+@@ -4717,7 +4723,7 @@
+ :func:`waitstatus_to_exitcode` can be used to convert the exit status into an
+ exit code.
- """Test for SysLogHandler with Unix sockets."""
-diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
-index 3d9d6d5d0a..dfb1d6f84d 100644
---- a/Lib/test/test_marshal.py
-+++ b/Lib/test/test_marshal.py
-@@ -1,5 +1,5 @@
- from test import support
--from test.support import os_helper, requires_debug_ranges
-+from test.support import os_helper, requires_debug_ranges, is_apple_mobile
- from test.support.script_helper import assert_python_ok
- import array
- import io
-@@ -263,7 +263,10 @@
- elif sys.platform == 'wasi':
- MAX_MARSHAL_STACK_DEPTH = 1500
- else:
-- MAX_MARSHAL_STACK_DEPTH = 2000
-+ if is_apple_mobile:
-+ MAX_MARSHAL_STACK_DEPTH = 1500
-+ else:
-+ MAX_MARSHAL_STACK_DEPTH = 2000
- for i in range(MAX_MARSHAL_STACK_DEPTH - 2):
- last.append([0])
- last = last[-1]
-diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
-index dfcf303942..5aabfac885 100644
---- a/Lib/test/test_mmap.py
-+++ b/Lib/test/test_mmap.py
-@@ -1,5 +1,5 @@
- from test.support import (
-- requires, _2G, _4G, gc_collect, cpython_only, is_emscripten
-+ requires, _2G, _4G, gc_collect, cpython_only, is_emscripten, is_apple_mobile
- )
- from test.support.import_helper import import_module
- from test.support.os_helper import TESTFN, unlink
-@@ -245,7 +245,7 @@
- with open(TESTFN, "r+b") as f:
- self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
-
-- if os.name == "posix":
-+ if os.name == "posix" and not is_apple_mobile:
- # Try incompatible flags, prot and access parameters.
- with open(TESTFN, "r+b") as f:
- self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
-@@ -1007,7 +1007,7 @@
- unlink(TESTFN)
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- def _make_test_file(self, num_zeroes, tail):
-- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
-+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile:
- requires('largefile',
- 'test requires %s bytes and a long time to run' % str(0x180000000))
- f = open(TESTFN, 'w+b')
-diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py
-index 2169733503..753a137d66 100644
---- a/Lib/test/test_platform.py
-+++ b/Lib/test/test_platform.py
-@@ -8,7 +8,7 @@
- from unittest import mock
+ .. seealso::
- from test import support
--from test.support import os_helper
-+from test.support import os_helper, is_apple_mobile
+@@ -4751,7 +4757,10 @@
+ Otherwise, if there are no matching children
+ that could be waited for, :exc:`ChildProcessError` is raised.
- FEDORA_OS_RELEASE = """\
- NAME=Fedora
-@@ -328,7 +328,7 @@
- def test_mac_ver(self):
- res = platform.mac_ver()
-
-- if platform.uname().system == 'Darwin':
-+ if platform.uname().system == 'Darwin' and not is_apple_mobile:
- # We are on a macOS system, check that the right version
- # information is returned
- output = subprocess.check_output(['sw_vers'], text=True)
-@@ -360,6 +360,9 @@
- else:
- self.assertEqual(res[2], 'PowerPC')
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
++
++ .. note::
++ This function is not available on macOS.
-+ @unittest.skipUnless(is_apple_mobile, 'iOS/tvOS/watchOS only test')
-+ def test_ios_ver(self):
-+ res = platform.ios_ver()
+ .. note::
+ This function is not available on macOS.
+@@ -4792,7 +4801,7 @@
+ :func:`waitstatus_to_exitcode` can be used to convert the exit status into an
+ exit code.
- @unittest.skipUnless(sys.platform == 'darwin', "OSX only test")
- def test_mac_ver_with_fork(self):
-diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
-index 444f8abe46..e2b61fbdba 100644
---- a/Lib/test/test_posix.py
-+++ b/Lib/test/test_posix.py
-@@ -2,6 +2,7 @@
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
- from test import support
- from test.support import import_helper
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import warnings_helper
- from test.support.script_helper import assert_python_ok
-@@ -69,12 +70,19 @@
- "getpid", "getpgrp", "getppid", "getuid", "sync",
- ]
+ .. versionchanged:: 3.5
+ If the system call is interrupted and the signal handler does not raise an
+@@ -4812,7 +4821,7 @@
+ :func:`waitstatus_to_exitcode` can be used to convert the exit status into an
+ exitcode.
-+ # getgroups can't be invoked on iOS/tvOS/watchOS.
-+ if is_apple_mobile:
-+ NO_ARG_FUNCTIONS.append("getgroups")
-+
- for name in NO_ARG_FUNCTIONS:
- posix_func = getattr(posix, name, None)
- if posix_func is not None:
- with self.subTest(name):
-- posix_func()
-- self.assertRaises(TypeError, posix_func, 1)
-+ try:
-+ posix_func()
-+ self.assertRaises(TypeError, posix_func, 1)
-+ except Exception as e:
-+ self.fail('Problem invoking %s: %s' % (name, e))
-
- @unittest.skipUnless(hasattr(posix, 'getresuid'),
- 'test needs posix.getresuid()')
-@@ -779,9 +787,10 @@
- check_stat(uid, gid)
- self.assertRaises(OSError, chown_func, first_param, 0, -1)
- check_stat(uid, gid)
-- if 0 not in os.getgroups():
-- self.assertRaises(OSError, chown_func, first_param, -1, 0)
-- check_stat(uid, gid)
-+ if hasattr(os, 'getgroups') and not is_apple_mobile:
-+ if 0 not in os.getgroups():
-+ self.assertRaises(OSError, chown_func, first_param, -1, 0)
-+ check_stat(uid, gid)
- # test illegal types
- for t in str, float:
- self.assertRaises(TypeError, chown_func, first_param, t(uid), gid)
-@@ -1129,7 +1138,7 @@
- self.assertIsInstance(hi, int)
- self.assertGreaterEqual(hi, lo)
- # OSX evidently just returns 15 without checking the argument.
-- if sys.platform != "darwin":
-+ if sys.platform != 'darwin' and not is_apple_mobile:
- self.assertRaises(OSError, posix.sched_get_priority_min, -23)
- self.assertRaises(OSError, posix.sched_get_priority_max, -23)
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
-index cd1c3d8cfb..dd5c587fe5 100644
---- a/Lib/test/test_shutil.py
-+++ b/Lib/test/test_shutil.py
-@@ -2052,6 +2052,7 @@
- check_chown(dirname, uid, gid)
+ .. function:: wait4(pid, options)
+@@ -4826,7 +4835,7 @@
+ :func:`waitstatus_to_exitcode` can be used to convert the exit status into an
+ exitcode.
-+@unittest.skipIf(support.has_subprocess_support, 'Test requires support for subprocesses.')
- class TestWhich(BaseTest, unittest.TestCase):
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- def setUp(self):
-@@ -2994,6 +2995,7 @@
- self.assertGreaterEqual(size.lines, 0)
- @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
-+ @unittest.skipUnless(support.has_subprocess_support, 'Test requires support for subprocesses.')
- @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
- 'need os.get_terminal_size()')
- def test_stty_match(self):
-diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
-index 99c4c5cbc4..841011d4c9 100644
---- a/Lib/test/test_socket.py
-+++ b/Lib/test/test_socket.py
-@@ -1,5 +1,6 @@
- import unittest
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -1173,7 +1174,7 @@
- # I've ordered this by protocols that have both a tcp and udp
- # protocol, at least for modern Linuxes.
- if (sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
-- or sys.platform in ('linux', 'darwin')):
-+ or sys.platform in ('linux', 'darwin') or is_apple_mobile):
- # avoid the 'echo' service on this platform, as there is an
- # assumption breaking non-standard port/protocol entry
- services = ('daytime', 'qotd', 'domain')
-@@ -3684,7 +3685,7 @@
- def _testFDPassCMSG_LEN(self):
- self.createAndSendFDs(1)
+ .. data:: P_PID
+@@ -4843,7 +4852,7 @@
+ * :data:`!P_PIDFD` - wait for the child identified by the file descriptor
+ *id* (a process file descriptor created with :func:`pidfd_open`).
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparate(self):
-@@ -3695,7 +3696,7 @@
- maxcmsgs=2)
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- @testFDPassSeparate.client_skip
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- def _testFDPassSeparate(self):
- fd0, fd1 = self.newFDs(2)
-@@ -3708,7 +3709,7 @@
- array.array("i", [fd1]))]),
- len(MSG))
+ .. note:: :data:`!P_PIDFD` is only available on Linux >= 5.4.
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparateMinSpace(self):
-@@ -3722,7 +3723,7 @@
- maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC)
+@@ -4858,7 +4867,7 @@
+ :func:`waitid` causes child processes to be reported if they have been
+ continued from a job control stop since they were last reported.
- @testFDPassSeparateMinSpace.client_skip
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- def _testFDPassSeparateMinSpace(self):
- fd0, fd1 = self.newFDs(2)
-@@ -3746,7 +3747,7 @@
- nbytes = self.sendmsgToServer([msg])
- self.assertEqual(nbytes, len(msg))
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-- @unittest.skipIf(sys.platform == "darwin", "see issue #24725")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- def testFDPassEmpty(self):
- # Try to pass an empty FD array. Can receive either no array
- # or an empty array.
-@@ -4566,28 +4567,33 @@
- pass
-
- @requireAttrs(socket.socket, "sendmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class SendmsgUnixStreamTest(SendmsgStreamTests, SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "recvmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class RecvmsgUnixStreamTest(RecvmsgTests, RecvmsgGenericStreamTests,
- SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "recvmsg_into")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class RecvmsgIntoUnixStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests,
- SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "sendmsg", "recvmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS")
- class RecvmsgSCMRightsStreamTest(SCMRightsTest, SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "sendmsg", "recvmsg_into")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS")
- class RecvmsgIntoSCMRightsStreamTest(RecvmsgIntoMixin, SCMRightsTest,
- SendrecvmsgUnixStreamTestBase):
-diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
-index c81d559cde..c5c60a3d53 100644
---- a/Lib/test/test_socketserver.py
-+++ b/Lib/test/test_socketserver.py
-@@ -8,12 +8,13 @@
- import select
- import signal
- import socket
-+import sys
- import threading
- import unittest
- import socketserver
- import test.support
--from test.support import reap_children, verbose
-+from test.support import is_apple_mobile, reap_children, verbose
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -188,12 +189,14 @@
- self.stream_examine)
-
- @requires_unix_sockets
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_UnixStreamServer(self):
- self.run_server(socketserver.UnixStreamServer,
- socketserver.StreamRequestHandler,
- self.stream_examine)
-
- @requires_unix_sockets
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_ThreadingUnixStreamServer(self):
- self.run_server(socketserver.ThreadingUnixStreamServer,
- socketserver.StreamRequestHandler,
-diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
-index b6dbf3d52c..0460604eca 100644
---- a/Lib/test/test_sysconfig.py
-+++ b/Lib/test/test_sysconfig.py
-@@ -335,7 +335,7 @@
- self.assertTrue(os.path.isfile(config_h), config_h)
+ .. data:: WEXITED
+@@ -4869,7 +4878,7 @@
+ The other ``wait*`` functions always report children that have terminated,
+ so this option is not available for them.
- def test_get_scheme_names(self):
-- wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv']
-+ wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos']
- if HAS_USER_BASE:
- wanted.extend(['nt_user', 'osx_framework_user', 'posix_user'])
- self.assertEqual(get_scheme_names(), tuple(sorted(wanted)))
-diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
-index 9e4972ecb6..07065a5c1e 100644
---- a/Lib/test/test_threading.py
-+++ b/Lib/test/test_threading.py
-@@ -3,7 +3,7 @@
- """
-
- import test.support
--from test.support import threading_helper, requires_subprocess
-+from test.support import threading_helper, requires_subprocess, is_apple_mobile
- from test.support import verbose, cpython_only, os_helper
- from test.support.import_helper import import_module
- from test.support.script_helper import assert_python_ok, assert_python_failure
-@@ -1225,6 +1225,7 @@
- os.set_blocking(r, False)
- return (r, w)
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform)
- def test_threads_join(self):
- # Non-daemon threads should be joined at subinterpreter shutdown
- # (issue #18808)
-@@ -1253,6 +1254,7 @@
- # The thread was joined properly.
- self.assertEqual(os.read(r, 1), b"x")
-
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform)
- def test_threads_join_2(self):
- # Same as above, but a delay gets introduced after the thread's
- # Python code returned but before the thread state is deleted.
-diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
-index aa6a8fbf8c..e73c287475 100644
---- a/Lib/test/test_venv.py
-+++ b/Lib/test/test_venv.py
-@@ -19,7 +19,7 @@
- import tempfile
- from test.support import (captured_stdout, captured_stderr,
- skip_if_broken_multiprocessing_synchronize, verbose,
-- requires_subprocess, is_emscripten, is_wasi,
-+ requires_subprocess, is_apple_mobile, is_emscripten, is_wasi,
- requires_venv_with_pip, TEST_HOME_DIR,
- requires_resource)
- from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
-@@ -41,6 +41,8 @@
+ .. versionadded:: 3.3
- if is_emscripten or is_wasi:
- raise unittest.SkipTest("venv is not available on Emscripten/WASI.")
-+if is_apple_mobile:
-+ raise unittest.SkipTest("venv is not available on mobile Apple platforms.")
+@@ -4881,7 +4890,7 @@
- @requires_subprocess()
- def check_output(cmd, encoding=None):
-diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
-index e0170afdf4..035bd56bf2 100755
---- a/Lib/webbrowser.py
-+++ b/Lib/webbrowser.py
-@@ -542,6 +542,57 @@
+ This option is not available for the other ``wait*`` functions.
- # what to do if _tryorder is now empty?
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-+#
-+# Platform support for iOS
-+#
-+if sys.platform == 'ios':
-+ class MobileSafari(BaseBrowser):
-+ def open(self, url, new=0, autoraise=True):
-+ # This code is the equivalent of:
-+ # NSURL *nsurl = [NSURL URLWithString:url];
-+ # [[UIApplication sharedApplication] openURL:nsurl];
-+ from ctypes import cdll, c_void_p, c_char_p, c_uint32
-+ from ctypes import util
-+ objc = cdll.LoadLibrary(util.find_library(b'objc'))
-+ cf = cdll.LoadLibrary(util.find_library(b'CoreFoundation'))
-+ objc.objc_getClass.restype = c_void_p
-+ objc.objc_getClass.argtypes = [c_char_p]
-+ objc.sel_registerName.restype = c_void_p
-+ objc.sel_registerName.argtypes = [c_char_p]
-+ cf.CFStringCreateWithCString.restype = c_void_p
-+ cf.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_uint32]
-+
-+ # Get an NSString describing the URL
-+ kCFStringEncodingUTF8 = 0x08000100
-+ url = c_void_p(cf.CFStringCreateWithCString(None, url.encode('utf-8'), kCFStringEncodingUTF8))
-+ autorelease = c_void_p(objc.sel_registerName(b'autorelease'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = c_void_p
-+ objc.objc_msgSend(url, autorelease)
-+
-+ # Get an NSURL object representing the URL
-+ NSURL = c_void_p(objc.objc_getClass(b'NSURL'))
-+ urlWithString_ = c_void_p(objc.sel_registerName(b'URLWithString:'))
-+ objc.objc_msgSend.restype = c_void_p
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
-+ nsurl = c_void_p(objc.objc_msgSend(NSURL, urlWithString_, url))
-+
-+ # Get the shared UIApplication instance
-+ UIApplication = c_void_p(objc.objc_getClass(b'UIApplication'))
-+ sharedApplication = c_void_p(objc.sel_registerName(b'sharedApplication'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = c_void_p
-+ shared_app = c_void_p(objc.objc_msgSend(UIApplication, sharedApplication))
-+
-+ # Open the URL on the shared application
-+ openURL_ = c_void_p(objc.sel_registerName(b'openURL:'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = None
-+ objc.objc_msgSend(shared_app, openURL_, nsurl)
-+
-+ return True
-+
-+ register("mobilesafari", None, MobileSafari(), preferred=True)
+ .. versionadded:: 3.3
- #
- # Platform support for Windows
-diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
-index 2d88f5e9ba..f79201817d 100644
---- a/Modules/_posixsubprocess.c
-+++ b/Modules/_posixsubprocess.c
-@@ -32,10 +32,20 @@
+@@ -4894,7 +4903,7 @@
- #include "posixmodule.h"
+ This option is not available for :func:`waitid`.
-+#if defined(__APPLE__)
-+#include "TargetConditionals.h"
-+#endif
-+
- #ifdef _Py_MEMORY_SANITIZER
- # include
- #endif
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them
-+// because they aren't conventional multiprocess environments.
-+#if TARGET_OS_IPHONE
-+# undef HAVE_FORK
-+#endif
-+
- #if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64)
- # include
- # define SYS_getdents64 __NR_getdents64
-@@ -725,11 +735,16 @@
- saved_errno = 0;
- for (i = 0; exec_array[i] != NULL; ++i) {
- const char *executable = exec_array[i];
-+
-+#if TARGET_OS_TV || TARGET_OS_WATCH
-+ errno = ENOTSUP;
-+#else
- if (envp) {
- execve(executable, argv, envp);
- } else {
- execv(executable, argv);
- }
-+#endif /* TARGET_OS_TV || TARGET_OS_WATCH */
- if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) {
- saved_errno = errno;
- }
-@@ -795,7 +810,9 @@
- PyObject *preexec_fn,
- PyObject *preexec_fn_args_tuple)
- {
--
-+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked;
-+ * so fail fast if any attempt is made to invoke fork_exec */
-+#ifdef HAVE_FORK
- pid_t pid;
-
- #ifdef VFORK_USABLE
-@@ -830,7 +847,7 @@
- pid = fork();
- }
- } else
--#endif
-+#endif /* VFORK_USABLE */
- {
- pid = fork();
- }
-@@ -863,6 +880,9 @@
- preexec_fn, preexec_fn_args_tuple);
- _exit(255);
- return 0; /* Dead code to avoid a potential compiler warning. */
-+#else /* HAVE_FORK */
-+ return -1;
-+#endif /* HAVE_FORK */
- }
- /*[clinic input]
-@@ -943,6 +963,10 @@
- int *c_fds_to_keep = NULL;
- Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep);
-
-+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked;
-+ * so fail fast if any attempt is made to invoke fork_exec */
-+#ifdef HAVE_FORK
-+
- PyInterpreterState *interp = PyInterpreterState_Get();
- if ((preexec_fn != Py_None) && interp->finalizing) {
- PyErr_SetString(PyExc_RuntimeError,
-@@ -1140,7 +1164,7 @@
- }
- old_sigmask = &old_sigs;
- }
--#endif
-+#endif /* VFORK_USABLE */
-
- pid = do_fork_exec(exec_array, argv, envp, cwd,
- p2cread, p2cwrite, c2pread, c2pwrite,
-@@ -1173,7 +1197,7 @@
- * the thread signal mask. */
- (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
- }
--#endif
-+#endif /* VFORK_USABLE */
+ .. data:: WNOHANG
+@@ -4903,7 +4912,7 @@
+ :func:`waitid` to return right away if no child process status is available
+ immediately.
- if (need_after_fork)
- PyOS_AfterFork_Parent();
-@@ -1207,6 +1231,10 @@
- }
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- return pid == -1 ? NULL : PyLong_FromPid(pid);
-+
-+#else /* HAVE_FORK */
-+ return NULL;
-+#endif
- }
- /* module level code ********************************************************/
-diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
-index 7b1104ba5a..d5fa1d72c6 100644
---- a/Modules/mathmodule.c
-+++ b/Modules/mathmodule.c
-@@ -198,6 +198,10 @@
- }
+ .. data:: WNOWAIT
+@@ -4913,7 +4922,7 @@
+ This option is not available for the other ``wait*`` functions.
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- /*
- sin(pi*x), giving accurate results for all finite x (especially x
- integral or close to an integer). This is here for use in the
-diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
-index b9ca2865c0..a71f8977b1 100644
---- a/Modules/posixmodule.c
-+++ b/Modules/posixmodule.c
-@@ -78,6 +78,8 @@
-
- #include
-
-+#include "TargetConditionals.h"
-+
- #if defined(__has_builtin)
- #if __has_builtin(__builtin_available)
- #define HAVE_BUILTIN_AVAILABLE 1
-@@ -363,6 +365,26 @@
- # define fsync _commit
- #endif /* ! __WATCOMC__ || __QNX__ */
-
-+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them
-+// because they aren't conventional multiprocess environment.
-+#if TARGET_OS_IPHONE
-+# undef HAVE_EXECV
-+# undef HAVE_FORK
-+# undef HAVE_FORK1
-+# undef HAVE_FORKPTY
-+# undef HAVE_GETGROUPS
-+# undef HAVE_POSIX_SPAWN
-+# undef HAVE_POSIX_SPAWNP
-+# undef HAVE_SCHED_H
-+# undef HAVE_SENDFILE
-+# undef HAVE_SETPRIORITY
-+# undef HAVE_SPAWNV
-+# undef HAVE_WAIT
-+# undef HAVE_WAIT3
-+# undef HAVE_WAIT4
-+# undef HAVE_WAITPID
-+#endif
-+
- /*[clinic input]
- # one of the few times we lie about this name!
- module os
-@@ -1537,7 +1559,9 @@
- */
- #include
- #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__))
-+# if !TARGET_OS_TV && !TARGET_OS_WATCH
- extern char **environ;
-+# endif
- #endif /* !_MSC_VER */
-
- static PyObject *
-@@ -1553,6 +1577,7 @@
- d = PyDict_New();
- if (d == NULL)
- return NULL;
-+#if !TARGET_OS_TV && !TARGET_OS_WATCH
- #ifdef MS_WINDOWS
- /* _wenviron must be initialized in this way if the program is started
- through main() instead of wmain(). */
-@@ -1606,6 +1631,7 @@
- Py_DECREF(k);
- Py_DECREF(v);
- }
-+#endif /* !TARGET_OS_TV && !TARGET_OS_WATCH */
- return d;
- }
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-@@ -5685,6 +5711,9 @@
- /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
- {
- long result;
-+#if TARGET_OS_IPHONE
-+ result = -1;
-+#else
- const char *bytes = PyBytes_AsString(command);
-
- if (PySys_Audit("os.system", "(O)", command) < 0) {
-@@ -5694,6 +5723,7 @@
- Py_BEGIN_ALLOW_THREADS
- result = system(bytes);
- Py_END_ALLOW_THREADS
-+#endif /* TARGET_OS_IPHONE */
- return result;
- }
- #endif
-@@ -14702,6 +14732,7 @@
- int is_symlink;
- int need_stat;
- #endif
-+#if !TARGET_OS_TV && !TARGET_OS_WATCH
- #ifdef MS_WINDOWS
- unsigned long dir_bits;
- #endif
-@@ -14762,6 +14793,7 @@
- #endif
- return result;
-+#endif /* !TARGET_OS_TV && !TARGET_OS_WATCH */
+ .. data:: CLD_EXITED
+@@ -4926,7 +4935,7 @@
+ These are the possible values for :attr:`!si_code` in the result returned by
+ :func:`waitid`.
- error:
- Py_XDECREF(st_mode);
-diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c
-index cc2e2a4389..8a6e35d2db 100644
---- a/Modules/pwdmodule.c
-+++ b/Modules/pwdmodule.c
-@@ -1,6 +1,10 @@
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
- /* UNIX password file access module */
+ .. versionadded:: 3.3
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- #include "Python.h"
- #include "posixmodule.h"
+@@ -4961,7 +4970,7 @@
+ :func:`WIFEXITED`, :func:`WEXITSTATUS`, :func:`WIFSIGNALED`,
+ :func:`WTERMSIG`, :func:`WIFSTOPPED`, :func:`WSTOPSIG` functions.
-@@ -182,6 +186,22 @@
- if (nomem == 1) {
- return PyErr_NoMemory();
- }
-+
-+// iPhone has a "user" with UID 501, username "mobile"; but the simulator
-+// doesn't reflect this. Generate a simulated response.
-+#if TARGET_IPHONE_SIMULATOR
-+ if (uid == 501) {
-+ struct passwd mp;
-+ mp.pw_name = "mobile";
-+ mp.pw_passwd = "/smx7MYTQIi2M";
-+ mp.pw_uid = 501;
-+ mp.pw_gid = 501;
-+ mp.pw_gecos = "Mobile User";
-+ mp.pw_dir = "/var/mobile";
-+ mp.pw_shell = "/bin/sh";
-+ return mkpwent(module, &mp);
-+ }
-+#endif
- PyObject *uid_obj = _PyLong_FromUid(uid);
- if (uid_obj == NULL)
- return NULL;
-@@ -265,6 +285,22 @@
- PyErr_NoMemory();
- }
- else {
-+// iPhone has a "user" with UID 501, username "mobile"; but the simulator
-+// doesn't reflect this. Generate a simulated response.
-+#if TARGET_IPHONE_SIMULATOR
-+ if (strcmp(name, "mobile") == 0) {
-+ struct passwd mp;
-+ mp.pw_name = "mobile";
-+ mp.pw_passwd = "/smx7MYTQIi2M";
-+ mp.pw_uid = 501;
-+ mp.pw_gid = 501;
-+ mp.pw_gecos = "Mobile User";
-+ mp.pw_dir = "/var/mobile";
-+ mp.pw_shell = "/bin/sh";
-+ retval = mkpwent(module, &mp);
-+ goto out;
-+ }
-+#endif
- PyErr_Format(PyExc_KeyError,
- "getpwnam(): name not found: %R", name);
- }
-diff --git a/Modules/timemodule.c b/Modules/timemodule.c
-index f5b0f39e14..90678a1ca2 100644
---- a/Modules/timemodule.c
-+++ b/Modules/timemodule.c
-@@ -114,6 +114,11 @@
- }
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not Emscripten, not WASI, not iOS.
+ .. versionadded:: 3.9
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
-+
- /* Forward declarations */
- static int pysleep(_PyTime_t timeout);
+@@ -4977,7 +4986,7 @@
-@@ -305,11 +310,13 @@
- if (_PyTime_AsTimespec(t, &tp) == -1)
- return NULL;
+ This function should be employed only if :func:`WIFSIGNALED` is true.
-+#if !TARGET_OS_IPHONE
- ret = clock_settime((clockid_t)clk_id, &tp);
- if (ret != 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
- }
-+#endif
- Py_RETURN_NONE;
- }
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-@@ -338,11 +345,13 @@
- return NULL;
- }
-+#if !TARGET_OS_IPHONE
- ret = clock_settime((clockid_t)clk_id, &ts);
- if (ret != 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
- }
-+#endif
- Py_RETURN_NONE;
- }
+ .. function:: WIFCONTINUED(status)
+@@ -4988,7 +4997,7 @@
-diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c
-index 587063ef1a..94f2dd3d70 100644
---- a/Python/bootstrap_hash.c
-+++ b/Python/bootstrap_hash.c
-@@ -36,6 +36,10 @@
- #endif
+ See :data:`WCONTINUED` option.
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- #ifdef Py_DEBUG
- int _Py_HashSecret_Initialized = 0;
- #else
-@@ -181,6 +185,9 @@
- }
- #elif defined(HAVE_GETENTROPY)
-+// iOS, tvOS and watchOS have an incomplete definitions of getentropy
-+// so it is *found* by configure, but doesn't actually exist.
-+#elif defined(HAVE_GETENTROPY) && !TARGET_OS_IPHONE
- #define PY_GETENTROPY 1
-
- /* Fill buffer with size pseudo-random bytes generated by getentropy():
-diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c
-index 6761bba457..470e2bb2ea 100644
---- a/Python/dynload_shlib.c
-+++ b/Python/dynload_shlib.c
-@@ -28,6 +28,10 @@
- #define LEAD_UNDERSCORE ""
- #endif
+ .. function:: WIFSTOPPED(status)
+@@ -5000,14 +5009,14 @@
+ done using :data:`WUNTRACED` option or when the process is being traced (see
+ :manpage:`ptrace(2)`).
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+ .. function:: WIFSIGNALED(status)
+
+ Return ``True`` if the process was terminated by a signal, otherwise return
+ ``False``.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+
+ .. function:: WIFEXITED(status)
+@@ -5016,7 +5025,7 @@
+ by calling ``exit()`` or ``_exit()``, or by returning from ``main()``;
+ otherwise return ``False``.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+
+ .. function:: WEXITSTATUS(status)
+@@ -5025,7 +5034,7 @@
+
+ This function should be employed only if :func:`WIFEXITED` is true.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+
+ .. function:: WSTOPSIG(status)
+@@ -5034,7 +5043,7 @@
+
+ This function should be employed only if :func:`WIFSTOPPED` is true.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+
+ .. function:: WTERMSIG(status)
+@@ -5043,7 +5052,7 @@
+
+ This function should be employed only if :func:`WIFSIGNALED` is true.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not Emscripten, not WASI, not iOS.
+
+
+ Interface to the scheduler
+diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst
+index 2f5bf53bc5c..0cc5e532711 100644
+--- a/Doc/library/platform.rst
++++ b/Doc/library/platform.rst
+@@ -148,6 +148,9 @@
+ Returns the system/OS name, such as ``'Linux'``, ``'Darwin'``, ``'Java'``,
+ ``'Windows'``. An empty string is returned if the value cannot be determined.
+
++ On iOS and Android, this returns the user-facing OS name (i.e, ``'iOS``,
++ ``'iPadOS'`` or ``'Android'``). To obtain the kernel name (``'Darwin'`` or
++ ``'Linux'``), use :func:`os.uname()`.
+
+ .. function:: system_alias(system, release, version)
+
+@@ -161,6 +164,8 @@
+ Returns the system's release version, e.g. ``'#3 on degas'``. An empty string is
+ returned if the value cannot be determined.
+
++ On iOS and Android, this is the user-facing OS version. To obtain the
++ Darwin or Linux kernel version, use :func:`os.uname()`.
+
+ .. function:: uname()
+
+@@ -234,7 +239,6 @@
+ macOS Platform
+ --------------
+
+-
+ .. function:: mac_ver(release='', versioninfo=('','',''), machine='')
+
+ Get macOS version information and return it as tuple ``(release, versioninfo,
+@@ -244,6 +248,24 @@
+ Entries which cannot be determined are set to ``''``. All tuple entries are
+ strings.
+
++iOS Platform
++------------
++
++.. function:: ios_ver(system='', release='', model='', is_simulator=False)
++
++ Get iOS version information and return it as a
++ :func:`~collections.namedtuple` with the following attributes:
++
++ * ``system`` is the OS name; either ``'iOS'`` or ``'iPadOS'``.
++ * ``release`` is the iOS version number as a string (e.g., ``'17.2'``).
++ * ``model`` is the device model identifier; this will be a string like
++ ``'iPhone13,2'`` for a physical device, or ``'iPhone'`` on a simulator.
++ * ``is_simulator`` is a boolean describing if the app is running on a
++ simulator or a physical device.
++
++ Entries which cannot be determined are set to the defaults given as
++ parameters.
+
- /* The .so extension module ABI tag, supplied by the Makefile via
- Makefile.pre.in and configure. This is used to discriminate between
- incompatible .so files so that extensions for different Python builds can
-@@ -38,12 +42,21 @@
- #ifdef __CYGWIN__
- ".dll",
- #else /* !__CYGWIN__ */
-- "." SOABI ".so",
--#ifdef ALT_SOABI
-- "." ALT_SOABI ".so",
--#endif
-- ".abi" PYTHON_ABI_STRING ".so",
-- ".so",
-+# ifdef __APPLE__
-+# if TARGET_OS_IPHONE
-+# define SHLIB_SUFFIX ".dylib"
-+# else
-+# define SHLIB_SUFFIX ".so"
-+# endif
-+# else
-+# define SHLIB_SUFFIX ".so"
-+# endif
-+ "." SOABI SHLIB_SUFFIX,
-+# ifdef ALT_SOABI
-+ "." ALT_SOABI SHLIB_SUFFIX,
-+# endif
-+ ".abi" PYTHON_ABI_STRING SHLIB_SUFFIX,
-+ SHLIB_SUFFIX,
- #endif /* __CYGWIN__ */
- NULL,
- };
-diff --git a/Python/marshal.c b/Python/marshal.c
-index 90953cbb72..36e38f3fc6 100644
---- a/Python/marshal.c
-+++ b/Python/marshal.c
-@@ -15,6 +15,10 @@
- #include "pycore_hashtable.h" // _Py_hashtable_t
- #include "marshal.h" // Py_MARSHAL_VERSION
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
+ Unix Platforms
+ --------------
+diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst
+index 98ca174d9e3..d71d7212cfd 100644
+--- a/Doc/library/pwd.rst
++++ b/Doc/library/pwd.rst
+@@ -10,7 +10,7 @@
+ This module provides access to the Unix user account and password database. It
+ is available on all Unix versions.
+
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI, not iOS.
+
+ Password database entries are reported as a tuple-like object, whose attributes
+ correspond to the members of the ``passwd`` structure (Attribute field below,
+diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst
+index 43cf8d5cdac..b51179f3e79 100644
+--- a/Doc/library/readline.rst
++++ b/Doc/library/readline.rst
+@@ -24,6 +24,8 @@
+ allowable constructs of that file, and the capabilities of the
+ Readline library in general.
+
++.. include:: ../includes/wasm-ios-notavail.rst
+
- /*[clinic input]
- module marshal
- [clinic start generated code]*/
-@@ -34,11 +38,15 @@
- * #if defined(MS_WINDOWS) && defined(_DEBUG)
- */
- #if defined(MS_WINDOWS)
--#define MAX_MARSHAL_STACK_DEPTH 1000
-+# define MAX_MARSHAL_STACK_DEPTH 1000
- #elif defined(__wasi__)
--#define MAX_MARSHAL_STACK_DEPTH 1500
-+# define MAX_MARSHAL_STACK_DEPTH 1500
- #else
--#define MAX_MARSHAL_STACK_DEPTH 2000
-+# if TARGET_OS_IPHONE
-+# define MAX_MARSHAL_STACK_DEPTH 1500
-+# else
-+# define MAX_MARSHAL_STACK_DEPTH 2000
-+# endif
- #endif
+ .. note::
+
+ The underlying Readline library API may be implemented by
+diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst
+index 7465bc5402c..dd80b1e6670 100644
+--- a/Doc/library/resource.rst
++++ b/Doc/library/resource.rst
+@@ -13,7 +13,7 @@
+ This module provides basic mechanisms for measuring and controlling system
+ resources utilized by a program.
- #define TYPE_NULL '0'
-diff --git a/Python/sysmodule.c b/Python/sysmodule.c
-index 4bd38b4b26..ae04d93528 100644
---- a/Python/sysmodule.c
-+++ b/Python/sysmodule.c
-@@ -48,6 +48,10 @@
- extern const char *PyWin_DLLVersionString;
- #endif
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI.
+
+ Symbolic constants are used to specify particular system resources and to
+ request usage information about either the current process or its children.
+diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
+index 60f21bc9105..48c6841c648 100644
+--- a/Doc/library/signal.rst
++++ b/Doc/library/signal.rst
+@@ -26,9 +26,9 @@
+ underlying implementation), with the exception of the handler for
+ :const:`SIGCHLD`, which follows the underlying implementation.
+
+-On WebAssembly platforms ``wasm32-emscripten`` and ``wasm32-wasi``, signals
+-are emulated and therefore behave differently. Several functions and signals
+-are not available on these platforms.
++On WebAssembly platforms, signals are emulated and therefore behave
++differently. Several functions and signals are not available on these
++platforms.
+
+ Execution of Python signal handlers
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
+index 10f03b3fe02..cc2c8be7dd2 100644
+--- a/Doc/library/socket.rst
++++ b/Doc/library/socket.rst
+@@ -1208,7 +1208,7 @@
+ buffer. Raises :exc:`OverflowError` if *length* is outside the
+ permissible range of values.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not WASI.
+
+ Most Unix platforms.
+
+@@ -1231,7 +1231,7 @@
+ amount of ancillary data that can be received, since additional
+ data may be able to fit into the padding area.
+
+- .. availability:: Unix, not Emscripten, not WASI.
++ .. availability:: Unix, not WASI.
+
+ most Unix platforms.
+
+@@ -1271,7 +1271,7 @@
+ (index int, name string) tuples.
+ :exc:`OSError` if the system call fails.
+
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not WASI.
+
+ .. versionadded:: 3.3
+
+@@ -1298,7 +1298,7 @@
+ interface name.
+ :exc:`OSError` if no interface with the given name exists.
+
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not WASI.
+
+ .. versionadded:: 3.3
+
+@@ -1315,7 +1315,7 @@
+ interface index number.
+ :exc:`OSError` if no interface with the given index exists.
+
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not WASI.
+
+ .. versionadded:: 3.3
+
+@@ -1332,7 +1332,7 @@
+ The *fds* parameter is a sequence of file descriptors.
+ Consult :meth:`~socket.sendmsg` for the documentation of these parameters.
+
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not WASI.
+
+ Unix platforms supporting :meth:`~socket.sendmsg`
+ and :const:`SCM_RIGHTS` mechanism.
+@@ -1346,7 +1346,7 @@
+ Return ``(msg, list(fds), flags, addr)``.
+ Consult :meth:`~socket.recvmsg` for the documentation of these parameters.
+
+- .. availability:: Unix, Windows, not Emscripten, not WASI.
++ .. availability:: Unix, Windows, not WASI.
+
+ Unix platforms supporting :meth:`~socket.sendmsg`
+ and :const:`SCM_RIGHTS` mechanism.
+diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
+index 33f96a2f744..743f5dd388f 100644
+--- a/Doc/library/subprocess.rst
++++ b/Doc/library/subprocess.rst
+@@ -25,7 +25,7 @@
+
+ :pep:`324` -- PEP proposing the subprocess module
+
+-.. include:: ../includes/wasm-notavail.rst
++.. include:: ../includes/wasm-ios-notavail.rst
+
+ Using the :mod:`subprocess` Module
+ ----------------------------------
+diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst
+index 79b808ab63c..332b58413d3 100644
+--- a/Doc/library/syslog.rst
++++ b/Doc/library/syslog.rst
+@@ -11,7 +11,7 @@
+ Refer to the Unix manual pages for a detailed description of the ``syslog``
+ facility.
+
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI, not iOS.
+
+ This module wraps the system ``syslog`` family of routines. A pure Python
+ library that can speak to a syslog server is available in the
+diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst
+index cd402e87a82..af593694748 100644
+--- a/Doc/library/urllib.parse.rst
++++ b/Doc/library/urllib.parse.rst
+@@ -22,11 +22,19 @@
+
+ The module has been designed to match the internet RFC on Relative Uniform
+ Resource Locators. It supports the following URL schemes: ``file``, ``ftp``,
+-``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``mailto``, ``mms``,
++``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``itms-services``, ``mailto``, ``mms``,
+ ``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtsps``, ``rtspu``,
+ ``sftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``,
+ ``telnet``, ``wais``, ``ws``, ``wss``.
-+#if defined(__APPLE__)
-+#include "TargetConditionals.h"
-+#endif
++.. impl-detail::
++
++ The inclusion of the ``itms-services`` URL scheme can prevent an app from
++ passing Apple's App Store review process for the macOS and iOS App Stores.
++ Handling for the ``itms-services`` scheme is always removed on iOS; on
++ macOS, it *may* be removed if CPython has been built with the
++ :option:`--with-app-store-compliance` option.
++
+ The :mod:`urllib.parse` module defines functions that fall into two broad
+ categories: URL parsing and URL quoting. These are covered in detail in
+ the following sections.
+diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst
+index 57b0ee7157c..c24945169e8 100644
+--- a/Doc/library/venv.rst
++++ b/Doc/library/venv.rst
+@@ -56,7 +56,7 @@
+ `Python Packaging User Guide: Creating and using virtual environments
+ `__
+
+-.. include:: ../includes/wasm-notavail.rst
++.. include:: ../includes/wasm-ios-notavail.rst
+
+ Creating virtual environments
+ -----------------------------
+diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst
+index df22c5f5e1e..1a58b4e7d7f 100644
+--- a/Doc/library/webbrowser.rst
++++ b/Doc/library/webbrowser.rst
+@@ -33,6 +33,13 @@
+ browsers are not available on Unix, the controlling process will launch a new
+ browser and wait.
+
++On iOS, the :envvar:`BROWSER` environment variable, as well as any arguments
++controlling autoraise, browser preference, and new tab/window creation will be
++ignored. Web pages will *always* be opened in the user's preferred browser, in
++a new tab, with the browser being brought to the foreground. The use of the
++:mod:`webbrowser` module on iOS requires the :mod:`ctypes` module. If
++:mod:`ctypes` isn't available, calls to :func:`.open` will fail.
++
+ The script :program:`webbrowser` can be used as a command-line interface for the
+ module. It accepts a URL as the argument. It accepts the following optional
+ parameters: ``-n`` opens the URL in a new browser window, if possible;
+@@ -147,6 +154,8 @@
+ +------------------------+-----------------------------------------+-------+
+ | ``'chromium-browser'`` | :class:`Chromium('chromium-browser')` | |
+ +------------------------+-----------------------------------------+-------+
++| ``'iosbrowser'`` | ``IOSBrowser`` | \(4) |
+++------------------------+-----------------------------------------+-------+
+
+ Notes:
+
+@@ -161,7 +170,11 @@
+ Only on Windows platforms.
+
+ (3)
+- Only on macOS platform.
++ Only on macOS.
++
++(4)
++ Only on iOS.
+
- #ifdef __EMSCRIPTEN__
- #include
- #endif
-@@ -3101,6 +3105,15 @@
- goto error;
- #endif
-+#if TARGET_OS_IPHONE
-+# if TARGET_OS_SIMULATOR
-+ res = PyDict_SetItemString(impl_info, "_simulator", Py_True);
-+# else
-+ res = PyDict_SetItemString(impl_info, "_simulator", Py_False);
-+# endif
-+ if (res < 0)
-+ goto error;
-+#endif
- /* dict ready */
+ .. versionadded:: 3.3
+ Support for Chrome/Chromium has been added.
+@@ -174,6 +187,9 @@
+ .. deprecated-removed:: 3.11 3.13
+ :class:`MacOSX` is deprecated, use :class:`MacOSXOSAScript` instead.
- ns = _PyNamespace_New(impl_info);
-diff --git a/config.sub b/config.sub
-index d74fb6deac..a30f74f03d 100755
---- a/config.sub
-+++ b/config.sub
-@@ -1121,10 +1121,9 @@
- xscale-* | xscalee[bl]-*)
- cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
- ;;
-- arm64-*)
-+ arm64-* | arm64_32-*)
- cpu=aarch64
- ;;
--
- # Recognize the canonical CPU Types that limit and/or modify the
- # company names they are paired with.
- cr16-*)
-@@ -1723,7 +1722,7 @@
- | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
- | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
- | hiux* | abug | nacl* | netware* | windows* \
-- | os9* | macos* | osx* | ios* \
-+ | os9* | macos* | osx* | ios* | tvos* | watchos* \
- | mpw* | magic* | mmixware* | mon960* | lnews* \
- | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
- | aos* | aros* | cloudabi* | sortix* | twizzler* \
-@@ -1786,6 +1785,8 @@
- ;;
- *-eabi* | *-gnueabi*)
- ;;
-+ ios*-simulator | tvos*-simulator | watchos*-simulator)
-+ ;;
- -*)
- # Blank kernel with real OS is always fine.
- ;;
-diff --git a/configure b/configure
-index b6f90bcd8c..235a639a70 100755
---- a/configure
-+++ b/configure
-@@ -4267,6 +4267,15 @@
- *-*-cygwin*)
- ac_sys_system=Cygwin
- ;;
-+ *-apple-ios*)
-+ ac_sys_system=iOS
-+ ;;
-+ *-apple-tvos*)
-+ ac_sys_system=tvOS
-+ ;;
-+ *-apple-watchos*)
-+ ac_sys_system=watchOS
-+ ;;
- *-*-vxworks*)
- ac_sys_system=VxWorks
- ;;
-@@ -4314,27 +4323,96 @@
- *-*-linux*)
- case "$host_cpu" in
- arm*)
-- _host_cpu=arm
-+ _host_ident=arm
- ;;
- *)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- esac
- ;;
- *-*-cygwin*)
-- _host_cpu=
-+ _host_ident=
-+ ;;
-+ *-apple-ios*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-iphonesimulator-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-iphonesimulator-$host_cpu
-+ esac
-+ ;;
-+ *-apple-ios*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-iphoneos-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-iphoneos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-tvos*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-appletvsimulator-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-appletvsimulator-$host_cpu
-+ esac
-+ ;;
-+ *-apple-tvos*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-appletvos-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-appletvos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-watchos*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-watchsimualtor-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-watchsimualtor-$host_cpu
-+ esac
-+ ;;
-+ *-apple-watchos*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-watchosos-arm64_32
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-watchosos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-*)
-+ case "$host_cpu" in
-+ arm*)
-+ _host_ident=arm
-+ ;;
-+ *)
-+ _host_ident=$host_cpu
-+ esac
- ;;
- *-*-vxworks*)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- ;;
- wasm32-*-* | wasm64-*-*)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- ;;
- *)
- # for now, limit cross builds to known configurations
- MACHDEP="unknown"
- as_fn_error $? "cross build not supported for $host" "$LINENO" 5
- esac
-- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}"
-+ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}"
- fi
++.. versionchanged:: 3.13
++ Support for iOS has been added.
++
+ Here are some simple examples::
+
+ url = 'https://docs.python.org/'
+diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py
+index caf145997fa..6eaedf25f9d 100644
+--- a/Doc/tools/extensions/pyspecific.py
++++ b/Doc/tools/extensions/pyspecific.py
+@@ -118,7 +118,7 @@
+ known_platforms = frozenset({
+ "AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD",
+ "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris", "Unix", "VxWorks",
+- "WASI", "Windows", "macOS",
++ "WASI", "Windows", "macOS", "iOS",
+ # libc
+ "BSD libc", "glibc", "musl",
+ # POSIX platforms with pthreads
+@@ -149,7 +149,7 @@
+
+ Example::
+
+- .. availability:: Windows, Linux >= 4.2, not Emscripten, not WASI
++ .. availability:: Windows, Linux >= 4.2, not WASI
+
+ Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not
+ parsed into separate tokens.
+diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst
+index 0e605b38d42..31c9b36bb79 100644
+--- a/Doc/using/configure.rst
++++ b/Doc/using/configure.rst
+@@ -638,7 +638,7 @@
+ macOS Options
+ -------------
+
+-See ``Mac/README.rst``.
++See :source:`Mac/README.rst`.
+
+ .. option:: --enable-universalsdk
+ .. option:: --enable-universalsdk=SDKDIR
+@@ -673,6 +673,31 @@
+ Specify the name for the python framework on macOS only valid when
+ :option:`--enable-framework` is set (default: ``Python``).
+
++.. option:: --with-app-store-compliance
++.. option:: --with-app-store-compliance=PATCH-FILE
++
++ The Python standard library contains strings that are known to trigger
++ automated inspection tool errors when submitted for distribution by
++ the macOS and iOS App Stores. If enabled, this option will apply the list of
++ patches that are known to correct app store compliance. A custom patch
++ file can also be specified. This option is disabled by default.
++
++ .. versionadded:: 3.13
++
++iOS Options
++-----------
++
++See :source:`iOS/README.rst`.
++
++.. option:: --enable-framework=INSTALLDIR
++
++ Create a Python.framework. Unlike macOS, the *INSTALLDIR* argument
++ specifying the installation path is mandatory.
++
++.. option:: --with-framework-name=FRAMEWORK
++
++ Specify the name for the framework (default: ``Python``).
++
- # Some systems cannot stand _XOPEN_SOURCE being defined at all; they
-@@ -4401,6 +4479,13 @@
- define_xopen_source=no;;
- Darwin/[12][0-9].*)
- define_xopen_source=no;;
-+ # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
-+ iOS/*)
-+ define_xopen_source=no;;
-+ tvOS/*)
-+ define_xopen_source=no;;
-+ watchOS/*)
-+ define_xopen_source=no;;
- # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
- # defining NI_NUMERICHOST.
- QNX/6.3.2)
-@@ -6892,7 +6977,42 @@
- #elif defined(__gnu_hurd__)
- i386-gnu
- #elif defined(__APPLE__)
-- darwin
-+# include "TargetConditionals.h"
-+# if TARGET_OS_IOS
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ iphonesimulator-x86_64
-+# else
-+ iphonesimulator-arm64
-+# endif
-+# else
-+ iphoneos-arm64
-+# endif
-+# elif TARGET_OS_TV
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ appletvsimulator-x86_64
-+# else
-+ appletvsimulator-arm64
-+# endif
-+# else
-+ appletvos-arm64
-+# endif
-+# elif TARGET_OS_WATCH
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ watchsimulator-x86_64
-+# else
-+ watchsimulator-arm64
-+# endif
-+# else
-+ watchos-arm64_32
-+# endif
-+# elif TARGET_OS_OSX
-+ darwin
-+# else
-+# error unknown Apple platform
-+# endif
- #elif defined(__VXWORKS__)
- vxworks
- #elif defined(__wasm32__)
-@@ -6941,6 +7061,12 @@
- case $ac_sys_system in #(
- Darwin*) :
- MULTIARCH="" ;; #(
-+ iOS) :
-+ MULTIARCH="" ;; #(
-+ tvOS) :
-+ MULTIARCH="" ;; #(
-+ watchOS) :
-+ MULTIARCH="" ;; #(
- FreeBSD*) :
- MULTIARCH="" ;; #(
- *) :
-@@ -6948,8 +7074,6 @@
- ;;
- esac
+ Cross Compiling Options
+ -----------------------
+diff --git a/Doc/using/index.rst b/Doc/using/index.rst
+index e1a3111f36a..f55a12f1ab8 100644
+--- a/Doc/using/index.rst
++++ b/Doc/using/index.rst
+@@ -18,4 +18,5 @@
+ configure.rst
+ windows.rst
+ mac.rst
++ ios.rst
+ editors.rst
+--- /dev/null
++++ b/Doc/using/ios.rst
+@@ -0,0 +1,343 @@
++.. _using-ios:
++
++===================
++Using Python on iOS
++===================
++
++:Authors:
++ Russell Keith-Magee (2024-03)
++
++Python on iOS is unlike Python on desktop platforms. On a desktop platform,
++Python is generally installed as a system resource that can be used by any user
++of that computer. Users then interact with Python by running a :program:`python`
++executable and entering commands at an interactive prompt, or by running a
++Python script.
++
++On iOS, there is no concept of installing as a system resource. The only unit
++of software distribution is an "app". There is also no console where you could
++run a :program:`python` executable, or interact with a Python REPL.
++
++As a result, the only way you can use Python on iOS is in embedded mode - that
++is, by writing a native iOS application, and embedding a Python interpreter
++using ``libPython``, and invoking Python code using the :ref:`Python embedding
++API `. The full Python interpreter, the standard library, and all
++your Python code is then packaged as a standalone bundle that can be
++distributed via the iOS App Store.
++
++If you're looking to experiment for the first time with writing an iOS app in
++Python, projects such as `BeeWare `__ and `Kivy
++`__ will provide a much more approachable user experience.
++These projects manage the complexities associated with getting an iOS project
++running, so you only need to deal with the Python code itself.
++
++Python at runtime on iOS
++========================
++
++iOS version compatibility
++-------------------------
++
++The minimum supported iOS version is specified at compile time, using the
++:option:`--host` option to ``configure``. By default, when compiled for iOS,
++Python will be compiled with a minimum supported iOS version of 13.0. To use a
++different miniumum iOS version, provide the version number as part of the
++:option:`!--host` argument - for example,
++``--host=arm64-apple-ios15.4-simulator`` would compile an ARM64 simulator build
++with a deployment target of 15.4.
++
++Platform identification
++-----------------------
++
++When executing on iOS, ``sys.platform`` will report as ``ios``. This value will
++be returned on an iPhone or iPad, regardless of whether the app is running on
++the simulator or a physical device.
++
++Information about the specific runtime environment, including the iOS version,
++device model, and whether the device is a simulator, can be obtained using
++:func:`platform.ios_ver()`. :func:`platform.system()` will report ``iOS`` or
++``iPadOS``, depending on the device.
++
++:func:`os.uname()` reports kernel-level details; it will report a name of
++``Darwin``.
++
++Standard library availability
++-----------------------------
++
++The Python standard library has some notable omissions and restrictions on
++iOS. See the :ref:`API availability guide for iOS ` for
++details.
++
++Binary extension modules
++------------------------
++
++One notable difference about iOS as a platform is that App Store distribution
++imposes hard requirements on the packaging of an application. One of these
++requirements governs how binary extension modules are distributed.
++
++The iOS App Store requires that *all* binary modules in an iOS app must be
++dynamic libraries, contained in a framework with appropriate metadata, stored
++in the ``Frameworks`` folder of the packaged app. There can be only a single
++binary per framework, and there can be no executable binary material outside
++the ``Frameworks`` folder.
++
++This conflicts with the usual Python approach for distributing binaries, which
++allows a binary extension module to be loaded from any location on
++``sys.path``. To ensure compliance with App Store policies, an iOS project must
++post-process any Python packages, converting ``.so`` binary modules into
++individual standalone frameworks with appropriate metadata and signing. For
++details on how to perform this post-processing, see the guide for :ref:`adding
++Python to your project `.
++
++To help Python discover binaries in their new location, the original ``.so``
++file on ``sys.path`` is replaced with a ``.fwork`` file. This file is a text
++file containing the location of the framework binary, relative to the app
++bundle. To allow the framework to resolve back to the original location, the
++framework must contain a ``.origin`` file that contains the location of the
++``.fwork`` file, relative to the app bundle.
++
++For example, consider the case of an import ``from foo.bar import _whiz``,
++where ``_whiz`` is implemented with the binary module
++``sources/foo/bar/_whiz.abi3.so``, with ``sources`` being the location
++registered on ``sys.path``, relative to the application bundle. This module
++*must* be distributed as ``Frameworks/foo.bar._whiz.framework/foo.bar._whiz``
++(creating the framework name from the full import path of the module), with an
++``Info.plist`` file in the ``.framework`` directory identifying the binary as a
++framework. The ``foo.bar._whiz`` module would be represented in the original
++location with a ``sources/foo/bar/_whiz.abi3.fwork`` marker file, containing
++the path ``Frameworks/foo.bar._whiz/foo.bar._whiz``. The framework would also
++contain ``Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin``, containing
++the path to the ``.fwork`` file.
++
++When running on iOS, the Python interpreter will install an
++:class:`~importlib.machinery.AppleFrameworkLoader` that is able to read and
++import ``.fwork`` files. Once imported, the ``__file__`` attribute of the
++binary module will report as the location of the ``.fwork`` file. However, the
++:class:`~importlib.machinery.ModuleSpec` for the loaded module will report the
++``origin`` as the location of the binary in the framework folder.
++
++Compiler stub binaries
++----------------------
++
++Xcode doesn't expose explicit compilers for iOS; instead, it uses an ``xcrun``
++script that resolves to a full compiler path (e.g., ``xcrun --sdk iphoneos
++clang`` to get the ``clang`` for an iPhone device). However, using this script
++poses two problems:
++
++* The output of ``xcrun`` includes paths that are machine specific, resulting
++ in a sysconfig module that cannot be shared between users; and
++
++* It results in ``CC``/``CPP``/``LD``/``AR`` definitions that include spaces.
++ There is a lot of C ecosystem tooling that assumes that you can split a
++ command line at the first space to get the path to the compiler executable;
++ this isn't the case when using ``xcrun``.
++
++To avoid these problems, Python provided stubs for these tools. These stubs are
++shell script wrappers around the underingly ``xcrun`` tools, distributed in a
++``bin`` folder distributed alongside the compiled iOS framework. These scripts
++are relocatable, and will always resolve to the appropriate local system paths.
++By including these scripts in the bin folder that accompanies a framework, the
++contents of the ``sysconfig`` module becomes useful for end-users to compile
++their own modules. When compiling third-party Python modules for iOS, you
++should ensure these stub binaries are on your path.
++
++Installing Python on iOS
++========================
++
++Tools for building iOS apps
++---------------------------
++
++Building for iOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode. This will
++require the use of the most (or second-most) recently released macOS version,
++as Apple does not maintain Xcode for older macOS versions. The Xcode Command
++Line Tools are not sufficient for iOS development; you need a *full* Xcode
++install.
++
++If you want to run your code on the iOS simulator, you'll also need to install
++an iOS Simulator Platform. You should be prompted to select an iOS Simulator
++Platform when you first run Xcode. Alternatively, you can add an iOS Simulator
++Platform by selecting from the Platforms tab of the Xcode Settings panel.
++
++.. _adding-ios:
++
++Adding Python to an iOS project
++-------------------------------
++
++Python can be added to any iOS project, using either Swift or Objective C. The
++following examples will use Objective C; if you are using Swift, you may find a
++library like `PythonKit `__ to be
++helpful.
++
++To add Python to an iOS Xcode project:
++
++1. Build or obtain a Python ``XCFramework``. See the instructions in
++ :source:`iOS/README.rst` (in the CPython source distribution) for details on
++ how to build a Python ``XCFramework``. At a minimum, you will need a build
++ that supports ``arm64-apple-ios``, plus one of either
++ ``arm64-apple-ios-simulator`` or ``x86_64-apple-ios-simulator``.
++
++2. Drag the ``XCframework`` into your iOS project. In the following
++ instructions, we'll assume you've dropped the ``XCframework`` into the root
++ of your project; however, you can use any other location that you want by
++ adjusting paths as needed.
++
++3. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project,
++ and ensure it is associated with the app target.
++
++4. Add your application code as a folder in your Xcode project. In the
++ following instructions, we'll assume that your user code is in a folder
++ named ``app`` in the root of your project; you can use any other location by
++ adjusting paths as needed. Ensure that this folder is associated with your
++ app target.
++
++5. Select the app target by selecting the root node of your Xcode project, then
++ the target name in the sidebar that appears.
++
++6. In the "General" settings, under "Frameworks, Libraries and Embedded
++ Content", add ``Python.xcframework``, with "Embed & Sign" selected.
++
++7. In the "Build Settings" tab, modify the following:
++
++ - Build Options
++
++ * User Script Sandboxing: No
++ * Enable Testability: Yes
++
++ - Search Paths
++
++ * Framework Search Paths: ``$(PROJECT_DIR)``
++ * Header Search Paths: ``"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"``
++
++ - Apple Clang - Warnings - All languages
++
++ * Quoted Include In Framework Header: No
++
++8. Add a build step that copies the Python standard library into your app. In
++ the "Build Phases" tab, add a new "Run Script" build step *before* the
++ "Embed Frameworks" step, but *after* the "Copy Bundle Resources" step. Name
++ the step "Install Target Specific Python Standard Library", disable the
++ "Based on dependency analysis" checkbox, and set the script content to:
++
++ .. code-block:: bash
++
++ set -e
++
++ mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib"
++ if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then
++ echo "Installing Python modules for iOS Simulator"
++ rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
++ else
++ echo "Installing Python modules for iOS Device"
++ rsync -au --delete "$PROJECT_DIR/Python.xcframework/ios-arm64/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
++ fi
++
++ Note that the name of the simulator "slice" in the XCframework may be
++ different, depending the CPU architectures your ``XCFramework`` supports.
++
++9. Add a second build step that processes the binary extension modules in the
++ standard library into "Framework" format. Add a "Run Script" build step
++ *directly after* the one you added in step 8, named "Prepare Python Binary
++ Modules". It should also have "Based on dependency analysis" unchecked, with
++ the following script content:
++
++ .. code-block:: bash
++
++ set -e
++
++ install_dylib () {
++ INSTALL_BASE=$1
++ FULL_EXT=$2
++
++ # The name of the extension file
++ EXT=$(basename "$FULL_EXT")
++ # The location of the extension file, relative to the bundle
++ RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/}
++ # The path to the extension file, relative to the install base
++ PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}
++ # The full dotted name of the extension module, constructed from the file path.
++ FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d "." -f 1 | tr "/" ".");
++ # A bundle identifier; not actually used, but required by Xcode framework packaging
++ FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-")
++ # The name of the framework folder.
++ FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework"
++
++ # If the framework folder doesn't exist, create it.
++ if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then
++ echo "Creating framework for $RELATIVE_EXT"
++ mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER"
++ cp "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
++ plutil -replace CFBundleExecutable -string "$FULL_MODULE_NAME" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
++ plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist"
++ fi
++
++ echo "Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME"
++ mv "$FULL_EXT" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME"
++ # Create a placeholder .fwork file where the .so was
++ echo "$FRAMEWORK_FOLDER/$FULL_MODULE_NAME" > ${FULL_EXT%.so}.fwork
++ # Create a back reference to the .so file location in the framework
++ echo "${RELATIVE_EXT%.so}.fwork" > "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin"
++ }
++
++ PYTHON_VER=$(ls -1 "$CODESIGNING_FOLDER_PATH/python/lib")
++ echo "Install Python $PYTHON_VER standard library extension modules..."
++ find "$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload" -name "*.so" | while read FULL_EXT; do
++ install_dylib python/lib/$PYTHON_VER/lib-dynload/ "$FULL_EXT"
++ done
++
++ # Clean up dylib template
++ rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist"
++
++ echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..."
++ find "$CODESIGNING_FOLDER_PATH/Frameworks" -name "*.framework" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "{}" \;
++
++10. Add Objective C code to initialize and use a Python interpreter in embedded
++ mode. You should ensure that:
++
++ * :c:member:`UTF-8 mode ` is *enabled*;
++ * :c:member:`Buffered stdio ` is *disabled*;
++ * :c:member:`Writing bytecode ` is *disabled*;
++ * :c:member:`Signal handlers ` are *enabled*;
++ * ``PYTHONHOME`` for the interpreter is configured to point at the
++ ``python`` subfolder of your app's bundle; and
++ * The ``PYTHONPATH`` for the interpreter includes:
++
++ - the ``python/lib/python3.X`` subfolder of your app's bundle,
++ - the ``python/lib/python3.X/lib-dynload`` subfolder of your app's bundle, and
++ - the ``app`` subfolder of your app's bundle
++
++ Your app's bundle location can be determined using ``[[NSBundle mainBundle]
++ resourcePath]``.
++
++Steps 8, 9 and 10 of these instructions assume that you have a single folder of
++pure Python application code, named ``app``. If you have third-party binary
++modules in your app, some additional steps will be required:
++
++* You need to ensure that any folders containing third-party binaries are
++ either associated with the app target, or copied in as part of step 8. Step 8
++ should also purge any binaries that are not appropriate for the platform a
++ specific build is targetting (i.e., delete any device binaries if you're
++ building app app targeting the simulator).
++
++* Any folders that contain third-party binaries must be processed into
++ framework form by step 9. The invocation of ``install_dylib`` that processes
++ the ``lib-dynload`` folder can be copied and adapted for this purpose.
++
++* If you're using a separate folder for third-party packages, ensure that folder
++ is included as part of the ``PYTHONPATH`` configuration in step 10.
++
++App Store Compliance
++====================
++
++The only mechanism for distributing apps to third-party iOS devices is to
++submit the app to the iOS App Store; apps submitted for distribution must pass
++Apple's app review process. This process includes a set of automated validation
++rules that inspect the submitted application bundle for problematic code.
++
++The Python standard library contains some code that is known to violate these
++automated rules. While these violations appear to be false positives, Apple's
++review rules cannot be challenged; so, it is necessary to modify the Python
++standard library for an app to pass App Store review.
++
++The Python source tree contains
++:source:`a patch file ` that will remove
++all code that is known to cause issues with the App Store review process. This
++patch is applied automatically when building for iOS.
+diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst
+index 31d37aad2a7..44fb00de373 100644
+--- a/Doc/using/mac.rst
++++ b/Doc/using/mac.rst
+@@ -188,6 +188,28 @@
+ * `PyInstaller `__: A cross-platform packaging tool that creates
+ a single file or folder as a distributable artifact.
+
++App Store Compliance
++--------------------
++
++Apps submitted for distribution through the macOS App Store must pass Apple's
++app review process. This process includes a set of automated validation rules
++that inspect the submitted application bundle for problematic code.
++
++The Python standard library contains some code that is known to violate these
++automated rules. While these violations appear to be false positives, Apple's
++review rules cannot be challenged. Therefore, it is necessary to modify the
++Python standard library for an app to pass App Store review.
++
++The Python source tree contains
++:source:`a patch file ` that will remove
++all code that is known to cause issues with the App Store review process. This
++patch is applied automatically when CPython is configured with the
++:option:`--with-app-store-compliance` option.
++
++This patch is not normally required to use CPython on a Mac; nor is it required
++if you are distributing an app *outside* the macOS App Store. It is *only*
++required if you are using the macOS App Store as a distribution channel.
++
+ Other Resources
+ ===============
--{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5
--printf "%s\n" "$MULTIARCH" >&6; }
+--- /dev/null
++++ b/Lib/_ios_support.py
+@@ -0,0 +1,71 @@
++import sys
++try:
++ from ctypes import cdll, c_void_p, c_char_p, util
++except ImportError:
++ # ctypes is an optional module. If it's not present, we're limited in what
++ # we can tell about the system, but we don't want to prevent the module
++ # from working.
++ print("ctypes isn't available; iOS system calls will not be available")
++ objc = None
++else:
++ # ctypes is available. Load the ObjC library, and wrap the objc_getClass,
++ # sel_registerName methods
++ lib = util.find_library("objc")
++ if lib is None:
++ # Failed to load the objc library
++ raise RuntimeError("ObjC runtime library couldn't be loaded")
++
++ objc = cdll.LoadLibrary(lib)
++ objc.objc_getClass.restype = c_void_p
++ objc.objc_getClass.argtypes = [c_char_p]
++ objc.sel_registerName.restype = c_void_p
++ objc.sel_registerName.argtypes = [c_char_p]
++
++
++def get_platform_ios():
++ # Determine if this is a simulator using the multiarch value
++ is_simulator = sys.implementation._multiarch.endswith("simulator")
++
++ # We can't use ctypes; abort
++ if not objc:
++ return None
++
++ # Most of the methods return ObjC objects
++ objc.objc_msgSend.restype = c_void_p
++ # All the methods used have no arguments.
++ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
++
++ # Equivalent of:
++ # device = [UIDevice currentDevice]
++ UIDevice = objc.objc_getClass(b"UIDevice")
++ SEL_currentDevice = objc.sel_registerName(b"currentDevice")
++ device = objc.objc_msgSend(UIDevice, SEL_currentDevice)
++
++ # Equivalent of:
++ # device_systemVersion = [device systemVersion]
++ SEL_systemVersion = objc.sel_registerName(b"systemVersion")
++ device_systemVersion = objc.objc_msgSend(device, SEL_systemVersion)
++
++ # Equivalent of:
++ # device_systemName = [device systemName]
++ SEL_systemName = objc.sel_registerName(b"systemName")
++ device_systemName = objc.objc_msgSend(device, SEL_systemName)
++
++ # Equivalent of:
++ # device_model = [device model]
++ SEL_model = objc.sel_registerName(b"model")
++ device_model = objc.objc_msgSend(device, SEL_model)
++
++ # UTF8String returns a const char*;
++ SEL_UTF8String = objc.sel_registerName(b"UTF8String")
++ objc.objc_msgSend.restype = c_char_p
++
++ # Equivalent of:
++ # system = [device_systemName UTF8String]
++ # release = [device_systemVersion UTF8String]
++ # model = [device_model UTF8String]
++ system = objc.objc_msgSend(device_systemName, SEL_UTF8String).decode()
++ release = objc.objc_msgSend(device_systemVersion, SEL_UTF8String).decode()
++ model = objc.objc_msgSend(device_model, SEL_UTF8String).decode()
++
++ return system, release, model, is_simulator
+diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
+index 6cedee74236..0e88cffc74f 100644
+--- a/Lib/ctypes/__init__.py
++++ b/Lib/ctypes/__init__.py
+@@ -346,6 +346,17 @@
+ winmode=None):
+ if name:
+ name = _os.fspath(name)
++
++ # If the filename that has been provided is an iOS/tvOS/watchOS
++ # .fwork file, dereference the location to the true origin of the
++ # binary.
++ if name.endswith(".fwork"):
++ with open(name) as f:
++ name = _os.path.join(
++ _os.path.dirname(_sys.executable),
++ f.read().strip()
++ )
++
+ self._name = name
+ flags = self._func_flags_
+ if use_errno:
+diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
+index c550883e7c7..12d7428fe9a 100644
+--- a/Lib/ctypes/util.py
++++ b/Lib/ctypes/util.py
+@@ -67,7 +67,7 @@
+ return fname
+ return None
- if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then
- if test x$PLATFORM_TRIPLET != x$MULTIARCH; then
-@@ -6959,6 +7083,16 @@
- MULTIARCH=$PLATFORM_TRIPLET
- fi
+-elif os.name == "posix" and sys.platform == "darwin":
++elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}:
+ from ctypes.macholib.dyld import dyld_find as _dyld_find
+ def find_library(name):
+ possible = ['lib%s.dylib' % name,
+diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
+index 61dafc0f4cb..306c3282103 100644
+--- a/Lib/importlib/_bootstrap_external.py
++++ b/Lib/importlib/_bootstrap_external.py
+@@ -52,7 +52,7 @@
-+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5
-+printf "%s\n" "$MULTIARCH" >&6; }
-+
-+case $ac_sys_system in #(
-+ iOS|tvOS|watchOS) :
-+ SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f1` ;; #(
-+ *) :
-+ SOABI_PLATFORM=$PLATFORM_TRIPLET
-+ ;;
-+esac
+ # Bootstrap-related code ######################################################
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
+-_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
++_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
+ _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
+ + _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
- if test x$MULTIARCH != x; then
- MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\""
-@@ -7002,8 +7136,14 @@
- PY_SUPPORT_TIER=3 ;; #(
- x86_64-*-freebsd*/clang) :
- PY_SUPPORT_TIER=3 ;; #(
-+ aarch64-apple-ios*-simulator/clang) :
-+ PY_SUPPORT_TIER=3 ;; #(
-+ x86_64-apple-ios*-simulator/clang) :
-+ PY_SUPPORT_TIER=3 ;; #(
-+ aarch64-apple-ios*/clang) :
-+ PY_SUPPORT_TIER=3 ;; #(
- *) :
-- PY_SUPPORT_TIER=0
-+ PY_SUPPORT_TIER=0
- ;;
- esac
+@@ -1694,6 +1694,46 @@
+ return f'FileFinder({self.path!r})'
-@@ -12668,6 +12808,7 @@
- esac
- ;;
- CYGWIN*) SHLIB_SUFFIX=.dll;;
-+ iOS|tvOS|watchOS) SHLIB_SUFFIX=.dylib;;
- *) SHLIB_SUFFIX=.so;;
- esac
- fi
-@@ -12750,6 +12891,9 @@
- BLDSHARED="$LDSHARED"
- fi
- ;;
-+ iOS/*|tvOS/*|watchOS/*)
-+ LDSHARED='$(CC) -dynamiclib -undefined dynamic_lookup'
-+ LDCXXSHARED='$(CXX) -dynamiclib -undefined dynamic_lookup';;
- Emscripten|WASI)
- LDSHARED='$(CC) -shared'
- LDCXXSHARED='$(CXX) -shared';;
-@@ -14291,6 +14435,10 @@
- ctypes_malloc_closure=yes
- ;; #(
-+ iOS|tvOS|watchOS) :
++class AppleFrameworkLoader(ExtensionFileLoader):
++ """A loader for modules that have been packaged as frameworks for
++ compatibility with Apple's iOS App Store policies.
++ """
++ def create_module(self, spec):
++ # If the ModuleSpec has been created by the FileFinder, it will have
++ # been created with an origin pointing to the .fwork file. We need to
++ # redirect this to the location in the Frameworks folder, using the
++ # content of the .fwork file.
++ if spec.origin.endswith(".fwork"):
++ with _io.FileIO(spec.origin, 'r') as file:
++ framework_binary = file.read().decode().strip()
++ bundle_path = _path_split(sys.executable)[0]
++ spec.origin = _path_join(bundle_path, framework_binary)
+
-+ ctypes_malloc_closure=yes
-+ ;; #(
- sunos5) :
- as_fn_append LIBFFI_LIBS " -mimpure-text"
- ;; #(
-@@ -24337,7 +24485,7 @@
- printf "%s\n" "$ABIFLAGS" >&6; }
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5
- printf %s "checking SOABI... " >&6; }
--SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
-+SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM}
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5
- printf "%s\n" "$SOABI" >&6; }
++ # If the loader is created based on the spec for a loaded module, the
++ # path will be pointing at the Framework location. If this occurs,
++ # get the original .fwork location to use as the module's __file__.
++ if self.path.endswith(".fwork"):
++ path = self.path
++ else:
++ with _io.FileIO(self.path + ".origin", 'r') as file:
++ origin = file.read().decode().strip()
++ bundle_path = _path_split(sys.executable)[0]
++ path = _path_join(bundle_path, origin)
++
++ module = _bootstrap._call_with_frames_removed(_imp.create_dynamic, spec)
++
++ _bootstrap._verbose_message(
++ "Apple framework extension module {!r} loaded from {!r} (path {!r})",
++ spec.name,
++ spec.origin,
++ path,
++ )
++
++ # Ensure that the __file__ points at the .fwork location
++ module.__file__ = path
++
++ return module
++
+ # Import setup ###############################################################
-@@ -24345,7 +24493,7 @@
- if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then
- # Similar to SOABI but remove "d" flag from ABIFLAGS
+ def _fix_up_module(ns, name, pathname, cpathname=None):
+@@ -1726,10 +1766,17 @@
-- ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
-+ ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${SOABI_PLATFORM:+-$SOABI_PLATFORM}
+ Each item is a tuple (loader, suffixes).
+ """
+- extensions = ExtensionFileLoader, _imp.extension_suffixes()
++ if sys.platform in {"ios", "tvos", "watchos"}:
++ extension_loaders = [(AppleFrameworkLoader, [
++ suffix.replace(".so", ".fwork")
++ for suffix in _imp.extension_suffixes()
++ ])]
++ else:
++ extension_loaders = []
++ extension_loaders.append((ExtensionFileLoader, _imp.extension_suffixes()))
+ source = SourceFileLoader, SOURCE_SUFFIXES
+ bytecode = SourcelessFileLoader, BYTECODE_SUFFIXES
+- return [extensions, source, bytecode]
++ return extension_loaders + [source, bytecode]
+
+
+ def _set_bootstrap_module(_bootstrap_module):
+diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py
+index b56fa94eb9c..37fef357fe2 100644
+--- a/Lib/importlib/abc.py
++++ b/Lib/importlib/abc.py
+@@ -180,7 +180,11 @@
+ else:
+ return self.source_to_code(source, path)
- printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h
+-_register(ExecutionLoader, machinery.ExtensionFileLoader)
++_register(
++ ExecutionLoader,
++ machinery.ExtensionFileLoader,
++ machinery.AppleFrameworkLoader,
++)
-@@ -28522,6 +28670,29 @@
- py_cv_module_ossaudiodev=n/a
- py_cv_module_spwd=n/a
- ;; #(
-+ iOS|tvOS|watchOS) :
-+
-+
+
+ class FileLoader(_bootstrap_external.FileLoader, ResourceLoader, ExecutionLoader):
+diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py
+index d9a19a13f7b..fbd30b159fb 100644
+--- a/Lib/importlib/machinery.py
++++ b/Lib/importlib/machinery.py
+@@ -12,6 +12,7 @@
+ from ._bootstrap_external import SourceFileLoader
+ from ._bootstrap_external import SourcelessFileLoader
+ from ._bootstrap_external import ExtensionFileLoader
++from ._bootstrap_external import AppleFrameworkLoader
+ from ._bootstrap_external import NamespaceLoader
+
+
+diff --git a/Lib/inspect.py b/Lib/inspect.py
+index 497169dacb5..cb3317e30a9 100644
+--- a/Lib/inspect.py
++++ b/Lib/inspect.py
+@@ -955,6 +955,10 @@
+ elif any(filename.endswith(s) for s in
+ importlib.machinery.EXTENSION_SUFFIXES):
+ return None
++ elif filename.endswith(".fwork"):
++ # Apple mobile framework markers are another type of non-source file
++ return None
+
-+ py_cv_module__curses=n/a
-+ py_cv_module__curses_panel=n/a
-+ py_cv_module__gdbm=n/a
-+ py_cv_module__multiprocessing=n/a
-+ py_cv_module__posixshmem=n/a
-+ py_cv_module__posixsubprocess=n/a
-+ py_cv_module__scproxy=n/a
-+ py_cv_module__tkinter=n/a
-+ py_cv_module__xxsubinterpreters=n/a
-+ py_cv_module_grp=n/a
-+ py_cv_module_nis=n/a
-+ py_cv_module_ossaudiodev=n/a
-+ py_cv_module_readline=n/a
-+ py_cv_module_pwd=n/a
-+ py_cv_module_spwd=n/a
-+ py_cv_module_syslog=n/a
-+ py_cv_module_=n/a
+ # return a filename found in the linecache even if it doesn't exist on disk
+ if filename in linecache.cache:
+ return filename
+@@ -985,6 +989,7 @@
+ return object
+ if hasattr(object, '__module__'):
+ return sys.modules.get(object.__module__)
+
-+ ;; #(
- CYGWIN*) :
+ # Try the filename to modulename cache
+ if _filename is not None and _filename in modulesbyfile:
+ return sys.modules.get(modulesbyfile[_filename])
+@@ -1078,7 +1083,7 @@
+ # Allow filenames in form of "" to pass through.
+ # `doctest` monkeypatches `linecache` module to enable
+ # inspection, so let `linecache.getlines` to be called.
+- if not (file.startswith('<') and file.endswith('>')):
++ if (not (file.startswith('<') and file.endswith('>'))) or file.endswith('.fwork'):
+ raise OSError('source code not available')
+
+ module = getmodule(object, file)
+diff --git a/Lib/modulefinder.py b/Lib/modulefinder.py
+index a0a020f9eeb..ac478ee7f51 100644
+--- a/Lib/modulefinder.py
++++ b/Lib/modulefinder.py
+@@ -72,7 +72,12 @@
+ if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
+ kind = _PY_SOURCE
+
+- elif isinstance(spec.loader, importlib.machinery.ExtensionFileLoader):
++ elif isinstance(
++ spec.loader, (
++ importlib.machinery.ExtensionFileLoader,
++ importlib.machinery.AppleFrameworkLoader,
++ )
++ ):
+ kind = _C_EXTENSION
+
+ elif isinstance(spec.loader, importlib.machinery.SourcelessFileLoader):
+diff --git a/Lib/platform.py b/Lib/platform.py
+index c5b60480369..c99f08899e4 100755
+--- a/Lib/platform.py
++++ b/Lib/platform.py
+@@ -497,6 +497,78 @@
+ # If that also doesn't work return the default values
+ return release, versioninfo, machine
++
++# A namedtuple for iOS version information.
++IOSVersionInfo = collections.namedtuple(
++ "IOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def ios_ver(system="", release="", model="", is_simulator=False):
++ """Get iOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
++ """
++ if sys.platform == "ios":
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return IOSVersionInfo(*result)
++
++ return IOSVersionInfo(system, release, model, is_simulator)
++
++
++# A namedtuple for tvOS version information.
++TVOSVersionInfo = collections.namedtuple(
++ "TVOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def tvos_ver(system="", release="", model="", is_simulator=False):
++ """Get tvOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
++ """
++ if sys.platform == "tvos":
++ # TODO: Can the iOS implementation be used here?
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return TVOSVersionInfo(*result)
++
++ return TVOSVersionInfo(system, release, model, is_simulator)
++
++
++# A namedtuple for watchOS version information.
++WatchOSVersionInfo = collections.namedtuple(
++ "WatchOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def watchos_ver(system="", release="", model="", is_simulator=False):
++ """Get watchOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
++ """
++ if sys.platform == "watchos":
++ # TODO: Can the iOS implementation be used here?
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return WatchOSVersionInfo(*result)
++
++ return WatchOSVersionInfo(system, release, model, is_simulator)
++
++
+ def _java_getprop(name, default):
-diff --git a/configure.ac b/configure.ac
-index ba768aea93..98d9a48918 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -553,6 +553,15 @@
- *-*-cygwin*)
- ac_sys_system=Cygwin
- ;;
-+ *-apple-ios*)
-+ ac_sys_system=iOS
-+ ;;
-+ *-apple-tvos*)
-+ ac_sys_system=tvOS
-+ ;;
-+ *-apple-watchos*)
-+ ac_sys_system=watchOS
-+ ;;
- *-*-vxworks*)
- ac_sys_system=VxWorks
- ;;
-@@ -599,27 +608,96 @@
- *-*-linux*)
- case "$host_cpu" in
- arm*)
-- _host_cpu=arm
-+ _host_ident=arm
- ;;
- *)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- esac
- ;;
- *-*-cygwin*)
-- _host_cpu=
-+ _host_ident=
-+ ;;
-+ *-apple-ios*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-iphonesimulator-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-iphonesimulator-$host_cpu
-+ esac
-+ ;;
-+ *-apple-ios*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-iphoneos-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-iphoneos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-tvos*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-appletvsimulator-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-appletvsimulator-$host_cpu
-+ esac
-+ ;;
-+ *-apple-tvos*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-appletvos-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-appletvos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-watchos*-simulator)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-watchsimualtor-arm64
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-watchsimualtor-$host_cpu
-+ esac
-+ ;;
-+ *-apple-watchos*)
-+ _host_os_min_version=`echo $host | cut -d '-' -f3`
-+ case "$host_cpu" in
-+ aarch64)
-+ _host_ident=${_host_os_min_version:3}-watchosos-arm64_32
-+ ;;
-+ *)
-+ _host_ident=${_host_os_min_version:3}-watchosos-$host_cpu
-+ esac
-+ ;;
-+ *-apple-*)
-+ case "$host_cpu" in
-+ arm*)
-+ _host_ident=arm
-+ ;;
-+ *)
-+ _host_ident=$host_cpu
-+ esac
- ;;
- *-*-vxworks*)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- ;;
- wasm32-*-* | wasm64-*-*)
-- _host_cpu=$host_cpu
-+ _host_ident=$host_cpu
- ;;
- *)
- # for now, limit cross builds to known configurations
- MACHDEP="unknown"
- AC_MSG_ERROR([cross build not supported for $host])
- esac
-- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}"
-+ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}"
- fi
+ from java.lang import System
+@@ -612,7 +684,7 @@
+ if cleaned == platform:
+ break
+ platform = cleaned
+- while platform[-1] == '-':
++ while platform and platform[-1] == '-':
+ platform = platform[:-1]
+
+ return platform
+@@ -653,7 +725,7 @@
+ default in case the command should fail.
- # Some systems cannot stand _XOPEN_SOURCE being defined at all; they
-@@ -685,6 +763,13 @@
- define_xopen_source=no;;
- Darwin/@<:@[12]@:>@@<:@0-9@:>@.*)
- define_xopen_source=no;;
-+ # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
-+ iOS/*)
-+ define_xopen_source=no;;
-+ tvOS/*)
-+ define_xopen_source=no;;
-+ watchOS/*)
-+ define_xopen_source=no;;
- # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
- # defining NI_NUMERICHOST.
- QNX/6.3.2)
-@@ -1072,7 +1157,42 @@
- #elif defined(__gnu_hurd__)
- i386-gnu
- #elif defined(__APPLE__)
-- darwin
-+# include "TargetConditionals.h"
-+# if TARGET_OS_IOS
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ iphonesimulator-x86_64
-+# else
-+ iphonesimulator-arm64
-+# endif
-+# else
-+ iphoneos-arm64
-+# endif
-+# elif TARGET_OS_TV
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ appletvsimulator-x86_64
-+# else
-+ appletvsimulator-arm64
-+# endif
-+# else
-+ appletvos-arm64
-+# endif
-+# elif TARGET_OS_WATCH
-+# if TARGET_OS_SIMULATOR
-+# if __x86_64__
-+ watchsimulator-x86_64
-+# else
-+ watchsimulator-arm64
-+# endif
-+# else
-+ watchos-arm64_32
-+# endif
-+# elif TARGET_OS_OSX
-+ darwin
-+# else
-+# error unknown Apple platform
-+# endif
- #elif defined(__VXWORKS__)
- vxworks
- #elif defined(__wasm32__)
-@@ -1117,11 +1237,13 @@
- AC_MSG_CHECKING([for multiarch])
- AS_CASE([$ac_sys_system],
- [Darwin*], [MULTIARCH=""],
-+ [iOS], [MULTIARCH=""],
-+ [tvOS], [MULTIARCH=""],
-+ [watchOS], [MULTIARCH=""],
- [FreeBSD*], [MULTIARCH=""],
- [MULTIARCH=$($CC --print-multiarch 2>/dev/null)]
- )
- AC_SUBST([MULTIARCH])
--AC_MSG_RESULT([$MULTIARCH])
+ """
+- if sys.platform in ('dos', 'win32', 'win16'):
++ if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'}:
+ # XXX Others too ?
+ return default
- if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then
- if test x$PLATFORM_TRIPLET != x$MULTIARCH; then
-@@ -1131,6 +1253,12 @@
- MULTIARCH=$PLATFORM_TRIPLET
- fi
- AC_SUBST([PLATFORM_TRIPLET])
-+AC_MSG_RESULT([$MULTIARCH])
-+
-+AS_CASE([$ac_sys_system],
-+ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f1`],
-+ [SOABI_PLATFORM=$PLATFORM_TRIPLET]
-+)
+@@ -815,6 +887,25 @@
+ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
+ return 'Alpha' if cpu_number >= 128 else 'VAX'
- if test x$MULTIARCH != x; then
- MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\""
-@@ -1161,6 +1289,15 @@
- [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten
- [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface
- [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
-+ [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
-+ [x86_64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on x86_64
-+ [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
-+ dnl [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS Simulator on ARM64
-+ dnl [x86_64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS Simulator on x86_64
-+ dnl [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS on ARM64
-+ dnl [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS Simulator on ARM64
-+ dnl [x86_64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS Simulator on x86_64
-+ dnl [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS on ARM64_32
- [PY_SUPPORT_TIER=0]
- )
++ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as
++ # uname.machine. On device it returns the model name for some reason; but
++ # there's only one CPU architecture for devices, so we know the right
++ # answer.
++ def get_ios():
++ if sys.implementation._multiarch.endswith("simulator"):
++ return os.uname().machine
++ return 'arm64'
++
++ def get_tvos():
++ if sys.implementation._multiarch.endswith("simulator"):
++ return os.uname().machine
++ return 'arm64'
++
++ def get_watchos():
++ if sys.implementation._multiarch.endswith("simulator"):
++ return os.uname().machine
++ return 'arm64_32'
++
+ def from_subprocess():
+ """
+ Fall back to `uname -p`
+@@ -969,6 +1060,14 @@
+ system = 'Windows'
+ release = 'Vista'
-@@ -3240,6 +3377,7 @@
- esac
- ;;
- CYGWIN*) SHLIB_SUFFIX=.dll;;
-+ iOS|tvOS|watchOS) SHLIB_SUFFIX=.dylib;;
- *) SHLIB_SUFFIX=.so;;
- esac
- fi
-@@ -3320,6 +3458,9 @@
- BLDSHARED="$LDSHARED"
- fi
- ;;
-+ iOS/*|tvOS/*|watchOS/*)
-+ LDSHARED='$(CC) -dynamiclib -undefined dynamic_lookup'
-+ LDCXXSHARED='$(CXX) -dynamiclib -undefined dynamic_lookup';;
- Emscripten|WASI)
- LDSHARED='$(CC) -shared'
- LDCXXSHARED='$(CXX) -shared';;
-@@ -3837,6 +3978,9 @@
- dnl when do we need USING_APPLE_OS_LIBFFI?
- ctypes_malloc_closure=yes
- ],
-+ [iOS|tvOS|watchOS], [
-+ ctypes_malloc_closure=yes
-+ ],
- [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])]
- )
- AS_VAR_IF([ctypes_malloc_closure], [yes], [
-@@ -5931,14 +6075,14 @@
- AC_MSG_CHECKING([ABIFLAGS])
- AC_MSG_RESULT([$ABIFLAGS])
- AC_MSG_CHECKING([SOABI])
--SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
-+SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM}
- AC_MSG_RESULT([$SOABI])
++ # Normalize responses on Apple mobile platforms
++ if sys.platform == 'ios':
++ system, release, _, _ = ios_ver()
++ if sys.platform == 'tvos':
++ system, release, _, _ = tvos_ver()
++ if sys.platform == 'watchos':
++ system, release, _, _ = watchos_ver()
++
+ vals = system, node, release, version, machine
+ # Replace 'unknown' values with the more portable ''
+ _uname_cache = uname_result(*map(_unknown_as_blank, vals))
+@@ -1248,11 +1347,18 @@
+ system, release, version = system_alias(system, release, version)
- # Release and debug (Py_DEBUG) ABI are compatible, but not Py_TRACE_REFS ABI
- if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then
+ if system == 'Darwin':
+- # macOS (darwin kernel)
+- macos_release = mac_ver()[0]
+- if macos_release:
+- system = 'macOS'
+- release = macos_release
++ # macOS and iOS both report as a "Darwin" kernel
++ if sys.platform == "ios":
++ system, release, _, _ = ios_ver()
++ elif sys.platform == "tvos":
++ system, release, _, _ = tvos_ver()
++ elif sys.platform == "watchos":
++ system, release, _, _ = watchos_ver()
++ else:
++ macos_release = mac_ver()[0]
++ if macos_release:
++ system = 'macOS'
++ release = macos_release
+
+ if system == 'Windows':
+ # MS platforms
+diff --git a/Lib/site.py b/Lib/site.py
+index 924cfbecec2..763bab27430 100644
+--- a/Lib/site.py
++++ b/Lib/site.py
+@@ -287,8 +287,8 @@
+ if env_base:
+ return env_base
+
+- # Emscripten, VxWorks, and WASI have no home directories
+- if sys.platform in {"emscripten", "vxworks", "wasi"}:
++ # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
++ if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
+ return None
+
+ def joinuser(*args):
+diff --git a/Lib/subprocess.py b/Lib/subprocess.py
+index 1d17ae3608a..34dfa0019a5 100644
+--- a/Lib/subprocess.py
++++ b/Lib/subprocess.py
+@@ -74,8 +74,8 @@
+ else:
+ _mswindows = True
+
+-# wasm32-emscripten and wasm32-wasi do not support processes
+-_can_fork_exec = sys.platform not in {"emscripten", "wasi"}
++# some platforms do not support subprocesses
++_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
+
+ if _mswindows:
+ import _winapi
+@@ -103,18 +103,22 @@
+ if _can_fork_exec:
+ from _posixsubprocess import fork_exec as _fork_exec
+ # used in methods that are called by __del__
+- _waitpid = os.waitpid
+- _waitstatus_to_exitcode = os.waitstatus_to_exitcode
+- _WIFSTOPPED = os.WIFSTOPPED
+- _WSTOPSIG = os.WSTOPSIG
+- _WNOHANG = os.WNOHANG
++ class _del_safe:
++ waitpid = os.waitpid
++ waitstatus_to_exitcode = os.waitstatus_to_exitcode
++ WIFSTOPPED = os.WIFSTOPPED
++ WSTOPSIG = os.WSTOPSIG
++ WNOHANG = os.WNOHANG
++ ECHILD = errno.ECHILD
+ else:
+- _fork_exec = None
+- _waitpid = None
+- _waitstatus_to_exitcode = None
+- _WIFSTOPPED = None
+- _WSTOPSIG = None
+- _WNOHANG = None
++ class _del_safe:
++ waitpid = None
++ waitstatus_to_exitcode = None
++ WIFSTOPPED = None
++ WSTOPSIG = None
++ WNOHANG = None
++ ECHILD = errno.ECHILD
++
+ import select
+ import selectors
+
+@@ -1958,20 +1962,16 @@
+ raise child_exception_type(err_msg)
+
+
+- def _handle_exitstatus(self, sts,
+- _waitstatus_to_exitcode=_waitstatus_to_exitcode,
+- _WIFSTOPPED=_WIFSTOPPED,
+- _WSTOPSIG=_WSTOPSIG):
++ def _handle_exitstatus(self, sts, _del_safe=_del_safe):
+ """All callers to this function MUST hold self._waitpid_lock."""
+ # This method is called (indirectly) by __del__, so it cannot
+ # refer to anything outside of its local scope.
+- if _WIFSTOPPED(sts):
+- self.returncode = -_WSTOPSIG(sts)
++ if _del_safe.WIFSTOPPED(sts):
++ self.returncode = -_del_safe.WSTOPSIG(sts)
+ else:
+- self.returncode = _waitstatus_to_exitcode(sts)
++ self.returncode = _del_safe.waitstatus_to_exitcode(sts)
+
+- def _internal_poll(self, _deadstate=None, _waitpid=_waitpid,
+- _WNOHANG=_WNOHANG, _ECHILD=errno.ECHILD):
++ def _internal_poll(self, _deadstate=None, _del_safe=_del_safe):
+ """Check if child process has terminated. Returns returncode
+ attribute.
+
+@@ -1987,13 +1987,13 @@
+ try:
+ if self.returncode is not None:
+ return self.returncode # Another thread waited.
+- pid, sts = _waitpid(self.pid, _WNOHANG)
++ pid, sts = _del_safe.waitpid(self.pid, _del_safe.WNOHANG)
+ if pid == self.pid:
+ self._handle_exitstatus(sts)
+ except OSError as e:
+ if _deadstate is not None:
+ self.returncode = _deadstate
+- elif e.errno == _ECHILD:
++ elif e.errno == _del_safe.ECHILD:
+ # This happens if SIGCLD is set to be ignored or
+ # waiting for child processes has otherwise been
+ # disabled for our process. This child is dead, we
+diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py
+index 122d441bd19..6a7d3b60610 100644
+--- a/Lib/sysconfig.py
++++ b/Lib/sysconfig.py
+@@ -21,6 +21,7 @@
+
+ # Keys for get_config_var() that are never converted to Python integers.
+ _ALWAYS_STR = {
++ 'IPHONEOS_DEPLOYMENT_TARGET',
+ 'MACOSX_DEPLOYMENT_TARGET',
+ }
+
+@@ -57,6 +58,7 @@
+ 'scripts': '{base}/Scripts',
+ 'data': '{base}',
+ },
++
+ # Downstream distributors can overwrite the default install scheme.
+ # This is done to support downstream modifications where distributors change
+ # the installation layout (eg. different site-packages directory).
+@@ -112,8 +114,8 @@
+ if env_base:
+ return env_base
+
+- # Emscripten, VxWorks, and WASI have no home directories
+- if sys.platform in {"emscripten", "vxworks", "wasi"}:
++ # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
++ if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
+ return None
+
+ def joinuser(*args):
+@@ -294,6 +296,7 @@
+ 'home': 'posix_home',
+ 'user': 'osx_framework_user',
+ }
++
+ return {
+ 'prefix': 'posix_prefix',
+ 'home': 'posix_home',
+@@ -813,10 +816,23 @@
+ if m:
+ release = m.group()
+ elif osname[:6] == "darwin":
+- import _osx_support
+- osname, release, machine = _osx_support.get_platform_osx(
+- get_config_vars(),
+- osname, release, machine)
++ if sys.platform == "ios":
++ release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
++ elif sys.platform == "tvos":
++ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
++ elif sys.platform == "watchos":
++ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
++ else:
++ import _osx_support
++ osname, release, machine = _osx_support.get_platform_osx(
++ get_config_vars(),
++ osname, release, machine)
+
+ return f"{osname}-{release}-{machine}"
+
+diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
+index 6efeaad8126..e9b0df085d0 100644
+--- a/Lib/test/pythoninfo.py
++++ b/Lib/test/pythoninfo.py
+@@ -287,6 +287,7 @@
+ "HOMEDRIVE",
+ "HOMEPATH",
+ "IDLESTARTUP",
++ "IPHONEOS_DEPLOYMENT_TARGET",
+ "LANG",
+ "LDFLAGS",
+ "LDSHARED",
+diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
+index 4e793f15494..c187f799f2b 100644
+--- a/Lib/test/support/__init__.py
++++ b/Lib/test/support/__init__.py
+@@ -43,7 +43,7 @@
+ "requires_limited_api", "requires_specialization",
+ # sys
+ "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi",
+- "check_impl_detail", "unix_shell", "setswitchinterval",
++ "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval",
+ # os
+ "get_pagesize",
+ # network
+@@ -530,7 +530,7 @@
+
+ is_android = hasattr(sys, 'getandroidapilevel')
+
+-if sys.platform not in ('win32', 'vxworks'):
++if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
+ unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
+ else:
+ unix_shell = None
+@@ -540,19 +540,35 @@
+ is_emscripten = sys.platform == "emscripten"
+ is_wasi = sys.platform == "wasi"
+
+-has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi
++# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
++# have subprocess or fork support.
++is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
++is_apple = is_apple_mobile or sys.platform == "darwin"
++
++has_fork_support = hasattr(os, "fork") and not (
++ is_emscripten
++ or is_wasi
++ or is_apple_mobile
++)
+
+ def requires_fork():
+ return unittest.skipUnless(has_fork_support, "requires working os.fork()")
+
+-has_subprocess_support = not is_emscripten and not is_wasi
++has_subprocess_support = not (
++ is_emscripten
++ or is_wasi
++ or is_apple_mobile
++)
+
+ def requires_subprocess():
+ """Used for subprocess, os.spawn calls, fd inheritance"""
+ return unittest.skipUnless(has_subprocess_support, "requires subprocess support")
+
+ # Emscripten's socket emulation and WASI sockets have limitations.
+-has_socket_support = not is_emscripten and not is_wasi
++has_socket_support = not (
++ is_emscripten
++ or is_wasi
++)
+
+ def requires_working_socket(*, module=False):
+ """Skip tests or modules that require working sockets
+diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py
+index 20f38fd36a8..1f64710c9c2 100644
+--- a/Lib/test/support/os_helper.py
++++ b/Lib/test/support/os_helper.py
+@@ -22,8 +22,8 @@
+
+ # TESTFN_UNICODE is a non-ascii filename
+ TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f"
+-if sys.platform == 'darwin':
+- # In Mac OS X's VFS API file names are, by definition, canonically
++if support.is_apple:
++ # On Apple's VFS API file names are, by definition, canonically
+ # decomposed Unicode, encoded using UTF-8. See QA1173:
+ # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
+ import unicodedata
+@@ -48,8 +48,8 @@
+ 'encoding (%s). Unicode filename tests may not be effective'
+ % (TESTFN_UNENCODABLE, sys.getfilesystemencoding()))
+ TESTFN_UNENCODABLE = None
+-# macOS and Emscripten deny unencodable filenames (invalid utf-8)
+-elif sys.platform not in {'darwin', 'emscripten', 'wasi'}:
++# Apple and Emscripten deny unencodable filenames (invalid utf-8)
++elif not support.is_apple and sys.platform not in {"emscripten", "wasi"}:
+ try:
+ # ascii and utf-8 cannot encode the byte 0xff
+ b'\xff'.decode(sys.getfilesystemencoding())
+@@ -615,7 +615,8 @@
+ if hasattr(os, 'sysconf'):
+ try:
+ MAXFD = os.sysconf("SC_OPEN_MAX")
+- except OSError:
++ except (OSError, ValueError):
++ # gh-118201: ValueError is raised intermittently on iOS
+ pass
+
+ old_modes = None
+diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
+index f25580371a2..1686b152f07 100644
+--- a/Lib/test/test_asyncio/test_events.py
++++ b/Lib/test/test_asyncio/test_events.py
+@@ -1894,6 +1894,7 @@
+ else:
+ self.assertEqual(-signal.SIGKILL, returncode)
+
++ @support.requires_subprocess()
+ def test_subprocess_exec(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo.py')
+
+@@ -1915,6 +1916,7 @@
+ self.check_killed(proto.returncode)
+ self.assertEqual(b'Python The Winner', proto.data[1])
+
++ @support.requires_subprocess()
+ def test_subprocess_interactive(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo.py')
+
+@@ -1942,6 +1944,7 @@
+ self.loop.run_until_complete(proto.completed)
+ self.check_killed(proto.returncode)
+
++ @support.requires_subprocess()
+ def test_subprocess_shell(self):
+ connect = self.loop.subprocess_shell(
+ functools.partial(MySubprocessProtocol, self.loop),
+@@ -1958,6 +1961,7 @@
+ self.assertEqual(proto.data[2], b'')
+ transp.close()
+
++ @support.requires_subprocess()
+ def test_subprocess_exitcode(self):
+ connect = self.loop.subprocess_shell(
+ functools.partial(MySubprocessProtocol, self.loop),
+@@ -1969,6 +1973,7 @@
+ self.assertEqual(7, proto.returncode)
+ transp.close()
+
++ @support.requires_subprocess()
+ def test_subprocess_close_after_finish(self):
+ connect = self.loop.subprocess_shell(
+ functools.partial(MySubprocessProtocol, self.loop),
+@@ -1983,6 +1988,7 @@
+ self.assertEqual(7, proto.returncode)
+ self.assertIsNone(transp.close())
+
++ @support.requires_subprocess()
+ def test_subprocess_kill(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo.py')
+
+@@ -1999,6 +2005,7 @@
+ self.check_killed(proto.returncode)
+ transp.close()
+
++ @support.requires_subprocess()
+ def test_subprocess_terminate(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo.py')
+
+@@ -2016,6 +2023,7 @@
+ transp.close()
+
+ @unittest.skipIf(sys.platform == 'win32', "Don't have SIGHUP")
++ @support.requires_subprocess()
+ def test_subprocess_send_signal(self):
+ # bpo-31034: Make sure that we get the default signal handler (killing
+ # the process). The parent process may have decided to ignore SIGHUP,
+@@ -2040,6 +2048,7 @@
+ finally:
+ signal.signal(signal.SIGHUP, old_handler)
+
++ @support.requires_subprocess()
+ def test_subprocess_stderr(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
+
+@@ -2061,6 +2070,7 @@
+ self.assertTrue(proto.data[2].startswith(b'ERR:test'), proto.data[2])
+ self.assertEqual(0, proto.returncode)
+
++ @support.requires_subprocess()
+ def test_subprocess_stderr_redirect_to_stdout(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
+
+@@ -2086,6 +2096,7 @@
+ transp.close()
+ self.assertEqual(0, proto.returncode)
+
++ @support.requires_subprocess()
+ def test_subprocess_close_client_stream(self):
+ prog = os.path.join(os.path.dirname(__file__), 'echo3.py')
+
+@@ -2120,6 +2131,7 @@
+ self.loop.run_until_complete(proto.completed)
+ self.check_killed(proto.returncode)
+
++ @support.requires_subprocess()
+ def test_subprocess_wait_no_same_group(self):
+ # start the new process in a new session
+ connect = self.loop.subprocess_shell(
+@@ -2132,6 +2144,7 @@
+ self.assertEqual(7, proto.returncode)
+ transp.close()
+
++ @support.requires_subprocess()
+ def test_subprocess_exec_invalid_args(self):
+ async def connect(**kwds):
+ await self.loop.subprocess_exec(
+@@ -2145,6 +2158,7 @@
+ with self.assertRaises(ValueError):
+ self.loop.run_until_complete(connect(shell=True))
+
++ @support.requires_subprocess()
+ def test_subprocess_shell_invalid_args(self):
+
+ async def connect(cmd=None, **kwds):
+diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
+index 3c8cc5f3649..210990593ad 100644
+--- a/Lib/test/test_asyncio/test_streams.py
++++ b/Lib/test/test_asyncio/test_streams.py
+@@ -10,7 +10,6 @@
+ import unittest
+ from unittest import mock
+ import warnings
+-from test.support import socket_helper
+ try:
+ import ssl
+ except ImportError:
+@@ -18,6 +17,7 @@
+
+ import asyncio
+ from test.test_asyncio import utils as test_utils
++from test.support import requires_subprocess, socket_helper
+
+
+ def tearDownModule():
+@@ -770,6 +770,7 @@
+ self.assertEqual(msg2, b"hello world 2!\n")
+
+ @unittest.skipIf(sys.platform == 'win32', "Don't have pipes")
++ @requires_subprocess()
+ def test_read_all_from_pipe_reader(self):
+ # See asyncio issue 168. This test is derived from the example
+ # subprocess_attach_read_pipe.py, but we configure the
+diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py
+index 859d2932c33..ed43895fd68 100644
+--- a/Lib/test/test_asyncio/test_subprocess.py
++++ b/Lib/test/test_asyncio/test_subprocess.py
+@@ -47,6 +47,7 @@
+ self._proc.pid = -1
+
+
++@support.requires_subprocess()
+ class SubprocessTransportTests(test_utils.TestCase):
+ def setUp(self):
+ super().setUp()
+@@ -110,6 +111,7 @@
+ transport.close()
+
+
++@support.requires_subprocess()
+ class SubprocessMixin:
+
+ def test_stdin_stdout(self):
+diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
+index 35c924a0cd6..9452213c685 100644
+--- a/Lib/test/test_asyncio/test_unix_events.py
++++ b/Lib/test/test_asyncio/test_unix_events.py
+@@ -1873,7 +1873,7 @@
+ wsock.close()
+
+
+-@unittest.skipUnless(hasattr(os, 'fork'), 'requires os.fork()')
++@support.requires_fork()
+ class TestFork(unittest.IsolatedAsyncioTestCase):
+
+ async def test_fork_not_share_event_loop(self):
+diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
+index 98c74a44e4c..40284774a58 100644
+--- a/Lib/test/test_capi/test_misc.py
++++ b/Lib/test/test_capi/test_misc.py
+@@ -1979,6 +1979,13 @@
+ self.addCleanup(os.close, r)
+ self.addCleanup(os.close, w)
+
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if support.is_apple_mobile:
++ loader = "AppleFrameworkLoader"
++ else:
++ loader = "ExtensionFileLoader"
++
+ script = textwrap.dedent(f"""
+ import importlib.machinery
+ import importlib.util
+@@ -1986,7 +1993,7 @@
+
+ fullname = '_test_module_state_shared'
+ origin = importlib.util.find_spec('_testmultiphase').origin
+- loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
++ loader = importlib.machinery.{loader}(fullname, origin)
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ module = importlib.util.module_from_spec(spec)
+ attr_id = str(id(module.Error)).encode()
+@@ -2160,7 +2167,12 @@
+ def setUp(self):
+ fullname = '_testmultiphase_meth_state_access' # XXX
+ origin = importlib.util.find_spec('_testmultiphase').origin
+- loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if support.is_apple_mobile:
++ loader = importlib.machinery.AppleFrameworkLoader(fullname, origin)
++ else:
++ loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
+index 1b588826010..74879ba2a9f 100644
+--- a/Lib/test/test_cmd_line_script.py
++++ b/Lib/test/test_cmd_line_script.py
+@@ -14,8 +14,7 @@
+
+ import textwrap
+ from test import support
+-from test.support import import_helper
+-from test.support import os_helper
++from test.support import import_helper, is_apple, os_helper
+ from test.support.script_helper import (
+ make_pkg, make_script, make_zip_pkg, make_zip_script,
+ assert_python_ok, assert_python_failure, spawn_python, kill_python)
+@@ -555,12 +554,17 @@
+ self.assertTrue(text[3].startswith('NameError'))
+
+ def test_non_ascii(self):
+- # Mac OS X denies the creation of a file with an invalid UTF-8 name.
++ # Apple platforms deny the creation of a file with an invalid UTF-8 name.
+ # Windows allows creating a name with an arbitrary bytes name, but
+ # Python cannot a undecodable bytes argument to a subprocess.
+- # WASI does not permit invalid UTF-8 names.
+- if (os_helper.TESTFN_UNDECODABLE
+- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')):
++ # Emscripten/WASI does not permit invalid UTF-8 names.
++ if (
++ os_helper.TESTFN_UNDECODABLE
++ and sys.platform not in {
++ "win32", "emscripten", "wasi"
++ }
++ and not is_apple
++ ):
+ name = os.fsdecode(os_helper.TESTFN_UNDECODABLE)
+ elif os_helper.TESTFN_NONASCII:
+ name = os_helper.TESTFN_NONASCII
+diff --git a/Lib/test/test_concurrent_futures/test_thread_pool.py b/Lib/test/test_concurrent_futures/test_thread_pool.py
+index 812f989d8f3..dfcf9e16e40 100644
+--- a/Lib/test/test_concurrent_futures/test_thread_pool.py
++++ b/Lib/test/test_concurrent_futures/test_thread_pool.py
+@@ -49,6 +49,7 @@
+ self.assertEqual(len(executor._threads), 1)
+ executor.shutdown(wait=True)
+
++ @support.requires_fork()
+ @unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork')
+ @support.requires_resource('cpu')
+ def test_hang_global_shutdown_lock(self):
+diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py
+index 203dd6fe57d..6d734d05245 100644
+--- a/Lib/test/test_fcntl.py
++++ b/Lib/test/test_fcntl.py
+@@ -6,7 +6,9 @@
+ import struct
+ import sys
+ import unittest
+-from test.support import verbose, cpython_only, get_pagesize
++from test.support import (
++ cpython_only, get_pagesize, is_apple, requires_subprocess, verbose
++)
+ from test.support.import_helper import import_module
+ from test.support.os_helper import TESTFN, unlink
+
+@@ -56,8 +58,10 @@
+ else:
+ start_len = "qq"
+
+- if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
+- or sys.platform == 'darwin'):
++ if (
++ sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
++ or is_apple
++ ):
+ if struct.calcsize('l') == 8:
+ off_t = 'l'
+ pid_t = 'i'
+@@ -157,6 +161,7 @@
+ self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
+
+ @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
++ @requires_subprocess()
+ def test_lockf_exclusive(self):
+ self.f = open(TESTFN, 'wb+')
+ cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
+@@ -169,6 +174,7 @@
+ self.assertEqual(p.exitcode, 0)
+
+ @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
++ @requires_subprocess()
+ def test_lockf_share(self):
+ self.f = open(TESTFN, 'wb+')
+ cmd = fcntl.LOCK_SH | fcntl.LOCK_NB
+diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py
+index 4c4a4498d6f..bed0e6d973b 100644
+--- a/Lib/test/test_ftplib.py
++++ b/Lib/test/test_ftplib.py
+@@ -18,6 +18,7 @@
+
+ from unittest import TestCase, skipUnless
+ from test import support
++from test.support import requires_subprocess
+ from test.support import threading_helper
+ from test.support import socket_helper
+ from test.support import warnings_helper
+@@ -900,6 +901,7 @@
+
+
+ @skipUnless(ssl, "SSL not available")
++@requires_subprocess()
+ class TestTLS_FTPClassMixin(TestFTPClass):
+ """Repeat TestFTPClass tests starting the TLS layer for both control
+ and data connections first.
+@@ -916,6 +918,7 @@
+
+
+ @skipUnless(ssl, "SSL not available")
++@requires_subprocess()
+ class TestTLS_FTPClass(TestCase):
+ """Specific TLS_FTP class tests."""
+
+diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py
+index 81bb5bb288e..dddf5e8cd93 100644
+--- a/Lib/test/test_gc.py
++++ b/Lib/test/test_gc.py
+@@ -1188,6 +1188,7 @@
+ self.assertEqual(len(gc.garbage), 0)
+
+
++ @requires_subprocess()
+ @unittest.skipIf(BUILD_WITH_NDEBUG,
+ 'built with -NDEBUG')
+ def test_refcount_errors(self):
+diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
+index bdfc5bfe260..515486c76cd 100644
+--- a/Lib/test/test_genericpath.py
++++ b/Lib/test/test_genericpath.py
+@@ -7,9 +7,9 @@
+ import sys
+ import unittest
+ import warnings
+-from test.support import is_emscripten
+-from test.support import os_helper
+-from test.support import warnings_helper
++from test.support import (
++ is_apple, is_emscripten, os_helper, warnings_helper
++)
+ from test.support.script_helper import assert_python_ok
+ from test.support.os_helper import FakePath
+
+@@ -487,12 +487,16 @@
+ self.assertIsInstance(abspath(path), str)
+
+ def test_nonascii_abspath(self):
+- if (os_helper.TESTFN_UNDECODABLE
+- # macOS and Emscripten deny the creation of a directory with an
+- # invalid UTF-8 name. Windows allows creating a directory with an
+- # arbitrary bytes name, but fails to enter this directory
+- # (when the bytes name is used).
+- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')):
++ if (
++ os_helper.TESTFN_UNDECODABLE
++ # Apple platforms and Emscripten/WASI deny the creation of a
++ # directory with an invalid UTF-8 name. Windows allows creating a
++ # directory with an arbitrary bytes name, but fails to enter this
++ # directory (when the bytes name is used).
++ and sys.platform not in {
++ "win32", "emscripten", "wasi"
++ } and not is_apple
++ ):
+ name = os_helper.TESTFN_UNDECODABLE
+ elif os_helper.TESTFN_NONASCII:
+ name = os_helper.TESTFN_NONASCII
+diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
+index 88d06fe04fb..1dc38dba3d3 100644
+--- a/Lib/test/test_httpservers.py
++++ b/Lib/test/test_httpservers.py
+@@ -31,8 +31,9 @@
+
+ import unittest
+ from test import support
+-from test.support import os_helper
+-from test.support import threading_helper
++from test.support import (
++ is_apple, os_helper, requires_subprocess, threading_helper
++)
+
+ support.requires_working_socket(module=True)
+
+@@ -411,8 +412,8 @@
+ reader.close()
+ return body
+
+- @unittest.skipIf(sys.platform == 'darwin',
+- 'undecodable name cannot always be decoded on macOS')
++ @unittest.skipIf(is_apple,
++ 'undecodable name cannot always be decoded on Apple platforms')
+ @unittest.skipIf(sys.platform == 'win32',
+ 'undecodable name cannot be decoded on win32')
+ @unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
+@@ -423,11 +424,11 @@
+ with open(os.path.join(self.tempdir, filename), 'wb') as f:
+ f.write(os_helper.TESTFN_UNDECODABLE)
+ response = self.request(self.base_url + '/')
+- if sys.platform == 'darwin':
+- # On Mac OS the HFS+ filesystem replaces bytes that aren't valid
+- # UTF-8 into a percent-encoded value.
++ if is_apple:
++ # On Apple platforms the HFS+ filesystem replaces bytes that
++ # aren't valid UTF-8 into a percent-encoded value.
+ for name in os.listdir(self.tempdir):
+- if name != 'test': # Ignore a filename created in setUp().
++ if name != 'test': # Ignore a filename created in setUp().
+ filename = name
+ break
+ body = self.check_status_and_reason(response, HTTPStatus.OK)
+@@ -698,6 +699,7 @@
+
+ @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
+ "This test can't be run reliably as root (issue #13308).")
++@requires_subprocess()
+ class CGIHTTPServerTestCase(BaseTestCase):
+ class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
+ def run_cgi(self):
+diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
+index c6accc4183a..ce0b0d74c62 100644
+--- a/Lib/test/test_import/__init__.py
++++ b/Lib/test/test_import/__init__.py
+@@ -5,7 +5,11 @@
+ import importlib.util
+ from importlib._bootstrap_external import _get_sourcefile
+ from importlib.machinery import (
+- BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader,
++ AppleFrameworkLoader,
++ BuiltinImporter,
++ ExtensionFileLoader,
++ FrozenImporter,
++ SourceFileLoader,
+ )
+ import marshal
+ import os
+@@ -26,7 +30,7 @@
+
+ from test.support import os_helper
+ from test.support import (
+- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten,
++ STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten,
+ is_wasi, run_in_subinterp, run_in_subinterp_with_config)
+ from test.support.import_helper import (
+ forget, make_legacy_pyc, unlink, unload, ready_to_import,
+@@ -63,6 +67,7 @@
+ MODULE_KINDS = {
+ BuiltinImporter: 'built-in',
+ ExtensionFileLoader: 'extension',
++ AppleFrameworkLoader: 'framework extension',
+ FrozenImporter: 'frozen',
+ SourceFileLoader: 'pure Python',
+ }
+@@ -88,7 +93,12 @@
+ assert module.__spec__.origin == 'built-in', module.__spec__
+
+ def require_extension(module, *, skip=False):
+- _require_loader(module, ExtensionFileLoader, skip)
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ _require_loader(module, AppleFrameworkLoader, skip)
++ else:
++ _require_loader(module, ExtensionFileLoader, skip)
+
+ def require_frozen(module, *, skip=True):
+ module = _require_loader(module, FrozenImporter, skip)
+@@ -131,7 +141,8 @@
+ # it to its nominal state.
+ sys.modules.pop('_testsinglephase', None)
+ _orig._clear_globals()
+- _testinternalcapi.clear_extension('_testsinglephase', _orig.__file__)
++ origin = _orig.__spec__.origin
++ _testinternalcapi.clear_extension('_testsinglephase', origin)
+ import _testsinglephase
+
+
+@@ -357,7 +368,7 @@
+ self.assertEqual(cm.exception.path, _testcapi.__file__)
+ self.assertRegex(
+ str(cm.exception),
+- r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)"
++ r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|fwork|pyd)\)"
+ )
+ else:
+ self.assertEqual(
+@@ -1706,6 +1717,14 @@
+ os.set_blocking(r, False)
+ return (r, w)
+
++ def create_extension_loader(self, modname, filename):
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ return AppleFrameworkLoader(modname, filename)
++ else:
++ return ExtensionFileLoader(modname, filename)
++
+ def import_script(self, name, fd, filename=None, check_override=None):
+ override_text = ''
+ if check_override is not None:
+@@ -1714,12 +1733,19 @@
+ _imp._override_multi_interp_extensions_check({check_override})
+ '''
+ if filename:
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ loader = "AppleFrameworkLoader"
++ else:
++ loader = "ExtensionFileLoader"
++
+ return textwrap.dedent(f'''
+ from importlib.util import spec_from_loader, module_from_spec
+- from importlib.machinery import ExtensionFileLoader
++ from importlib.machinery import {loader}
+ import os, sys
+ {override_text}
+- loader = ExtensionFileLoader({name!r}, {filename!r})
++ loader = {loader}({name!r}, {filename!r})
+ spec = spec_from_loader({name!r}, loader)
+ try:
+ module = module_from_spec(spec)
+@@ -1900,7 +1926,7 @@
+ def test_multi_init_extension_non_isolated_compat(self):
+ modname = '_test_non_isolated'
+ filename = _testmultiphase.__file__
+- loader = ExtensionFileLoader(modname, filename)
++ loader = self.create_extension_loader(modname, filename)
+ spec = importlib.util.spec_from_loader(modname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+@@ -1918,7 +1944,7 @@
+ def test_multi_init_extension_per_interpreter_gil_compat(self):
+ modname = '_test_shared_gil_only'
+ filename = _testmultiphase.__file__
+- loader = ExtensionFileLoader(modname, filename)
++ loader = self.create_extension_loader(modname, filename)
+ spec = importlib.util.spec_from_loader(modname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+@@ -2048,10 +2074,25 @@
+ @classmethod
+ def setUpClass(cls):
+ spec = importlib.util.find_spec(cls.NAME)
+- from importlib.machinery import ExtensionFileLoader
+- cls.FILE = spec.origin
+ cls.LOADER = type(spec.loader)
+- assert cls.LOADER is ExtensionFileLoader
++
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader, and we need to differentiate between the
++ # spec.origin and the original file location.
++ if is_apple_mobile:
++ assert cls.LOADER is AppleFrameworkLoader
++
++ cls.ORIGIN = spec.origin
++ with open(spec.origin + ".origin", "r") as f:
++ cls.FILE = os.path.join(
++ os.path.dirname(sys.executable),
++ f.read().strip()
++ )
++ else:
++ assert cls.LOADER is ExtensionFileLoader
++
++ cls.ORIGIN = spec.origin
++ cls.FILE = spec.origin
+
+ # Start fresh.
+ cls.clean_up()
+@@ -2067,14 +2108,15 @@
+ @classmethod
+ def clean_up(cls):
+ name = cls.NAME
+- filename = cls.FILE
+ if name in sys.modules:
+ if hasattr(sys.modules[name], '_clear_globals'):
+- assert sys.modules[name].__file__ == filename
++ assert sys.modules[name].__file__ == cls.FILE, \
++ f"{sys.modules[name].__file__} != {cls.FILE}"
++
+ sys.modules[name]._clear_globals()
+ del sys.modules[name]
+ # Clear all internally cached data for the extension.
+- _testinternalcapi.clear_extension(name, filename)
++ _testinternalcapi.clear_extension(name, cls.ORIGIN)
+
+ #########################
+ # helpers
+@@ -2082,7 +2124,7 @@
+ def add_module_cleanup(self, name):
+ def clean_up():
+ # Clear all internally cached data for the extension.
+- _testinternalcapi.clear_extension(name, self.FILE)
++ _testinternalcapi.clear_extension(name, self.ORIGIN)
+ self.addCleanup(clean_up)
+
+ def _load_dynamic(self, name, path):
+@@ -2105,7 +2147,7 @@
+ except AttributeError:
+ already_loaded = self.already_loaded = {}
+ assert name not in already_loaded
+- mod = self._load_dynamic(name, self.FILE)
++ mod = self._load_dynamic(name, self.ORIGIN)
+ self.assertNotIn(mod, already_loaded.values())
+ already_loaded[name] = mod
+ return types.SimpleNamespace(
+@@ -2117,7 +2159,7 @@
+ def re_load(self, name, mod):
+ assert sys.modules[name] is mod
+ assert mod.__dict__ == mod.__dict__
+- reloaded = self._load_dynamic(name, self.FILE)
++ reloaded = self._load_dynamic(name, self.ORIGIN)
+ return types.SimpleNamespace(
+ name=name,
+ module=reloaded,
+@@ -2137,7 +2179,7 @@
+ name = {self.NAME!r}
+ if name in sys.modules:
+ sys.modules.pop(name)._clear_globals()
+- _testinternalcapi.clear_extension(name, {self.FILE!r})
++ _testinternalcapi.clear_extension(name, {self.ORIGIN!r})
+ '''))
+ _interpreters.destroy(interpid)
+ self.addCleanup(clean_up)
+@@ -2154,7 +2196,7 @@
+ postcleanup = f'''
+ {import_}
+ mod._clear_globals()
+- _testinternalcapi.clear_extension(name, {self.FILE!r})
++ _testinternalcapi.clear_extension(name, {self.ORIGIN!r})
+ '''
+
+ try:
+@@ -2192,7 +2234,7 @@
+ # mod.__name__ might not match, but the spec will.
+ self.assertEqual(mod.__spec__.name, loaded.name)
+ self.assertEqual(mod.__file__, self.FILE)
+- self.assertEqual(mod.__spec__.origin, self.FILE)
++ self.assertEqual(mod.__spec__.origin, self.ORIGIN)
+ if not isolated:
+ self.assertTrue(issubclass(mod.error, Exception))
+ self.assertEqual(mod.int_const, 1969)
+@@ -2586,7 +2628,7 @@
+ # First, load in the main interpreter but then completely clear it.
+ loaded_main = self.load(self.NAME)
+ loaded_main.module._clear_globals()
+- _testinternalcapi.clear_extension(self.NAME, self.FILE)
++ _testinternalcapi.clear_extension(self.NAME, self.ORIGIN)
+
+ # At this point:
+ # * alive in 0 interpreters
+diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py
+index 3de120958fd..cdc8884d668 100644
+--- a/Lib/test/test_importlib/extension/test_finder.py
++++ b/Lib/test/test_importlib/extension/test_finder.py
+@@ -1,3 +1,4 @@
++from test.support import is_apple_mobile
+ from test.test_importlib import abc, util
+
+ machinery = util.import_importlib('importlib.machinery')
+@@ -19,9 +20,27 @@
+ )
+
+ def find_spec(self, fullname):
+- importer = self.machinery.FileFinder(util.EXTENSIONS.path,
+- (self.machinery.ExtensionFileLoader,
+- self.machinery.EXTENSION_SUFFIXES))
++ if is_apple_mobile:
++ # Apple mobile platforms require a specialist loader that uses
++ # .fwork files as placeholders for the true `.so` files.
++ loaders = [
++ (
++ self.machinery.AppleFrameworkLoader,
++ [
++ ext.replace(".so", ".fwork")
++ for ext in self.machinery.EXTENSION_SUFFIXES
++ ]
++ )
++ ]
++ else:
++ loaders = [
++ (
++ self.machinery.ExtensionFileLoader,
++ self.machinery.EXTENSION_SUFFIXES
++ )
++ ]
++
++ importer = self.machinery.FileFinder(util.EXTENSIONS.path, *loaders)
+
+ return importer.find_spec(fullname)
+
+diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py
+index 12f9e43d123..7e8c9c8184a 100644
+--- a/Lib/test/test_importlib/extension/test_loader.py
++++ b/Lib/test/test_importlib/extension/test_loader.py
+@@ -1,3 +1,4 @@
++from test.support import is_apple_mobile
+ from warnings import catch_warnings
+ from test.test_importlib import abc, util
+
+@@ -25,8 +26,15 @@
+ raise unittest.SkipTest(
+ f"{util.EXTENSIONS.name} is a builtin module"
+ )
+- self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
+- util.EXTENSIONS.file_path)
++
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ self.LoaderClass = self.machinery.AppleFrameworkLoader
++ else:
++ self.LoaderClass = self.machinery.ExtensionFileLoader
++
++ self.loader = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path)
+
+ def load_module(self, fullname):
+ with warnings.catch_warnings():
+@@ -34,13 +42,11 @@
+ return self.loader.load_module(fullname)
+
+ def test_equality(self):
+- other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
+- util.EXTENSIONS.file_path)
++ other = self.LoaderClass(util.EXTENSIONS.name, util.EXTENSIONS.file_path)
+ self.assertEqual(self.loader, other)
+
+ def test_inequality(self):
+- other = self.machinery.ExtensionFileLoader('_' + util.EXTENSIONS.name,
+- util.EXTENSIONS.file_path)
++ other = self.LoaderClass('_' + util.EXTENSIONS.name, util.EXTENSIONS.file_path)
+ self.assertNotEqual(self.loader, other)
+
+ def test_load_module_API(self):
+@@ -60,8 +66,7 @@
+ ('__package__', '')]:
+ self.assertEqual(getattr(module, attr), value)
+ self.assertIn(util.EXTENSIONS.name, sys.modules)
+- self.assertIsInstance(module.__loader__,
+- self.machinery.ExtensionFileLoader)
++ self.assertIsInstance(module.__loader__, self.LoaderClass)
+
+ # No extension module as __init__ available for testing.
+ test_package = None
+@@ -88,7 +93,7 @@
+ self.assertFalse(self.loader.is_package(util.EXTENSIONS.name))
+ for suffix in self.machinery.EXTENSION_SUFFIXES:
+ path = os.path.join('some', 'path', 'pkg', '__init__' + suffix)
+- loader = self.machinery.ExtensionFileLoader('pkg', path)
++ loader = self.LoaderClass('pkg', path)
+ self.assertTrue(loader.is_package('pkg'))
+
+
+@@ -103,6 +108,14 @@
+ def setUp(self):
+ if not self.machinery.EXTENSION_SUFFIXES or not util.EXTENSIONS:
+ raise unittest.SkipTest("Requires dynamic loading support.")
++
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ self.LoaderClass = self.machinery.AppleFrameworkLoader
++ else:
++ self.LoaderClass = self.machinery.ExtensionFileLoader
++
+ self.name = '_testsinglephase'
+ if self.name in sys.builtin_module_names:
+ raise unittest.SkipTest(
+@@ -111,8 +124,8 @@
+ finder = self.machinery.FileFinder(None)
+ self.spec = importlib.util.find_spec(self.name)
+ assert self.spec
+- self.loader = self.machinery.ExtensionFileLoader(
+- self.name, self.spec.origin)
++
++ self.loader = self.LoaderClass(self.name, self.spec.origin)
+
+ def load_module(self):
+ with warnings.catch_warnings():
+@@ -122,7 +135,7 @@
+ def load_module_by_name(self, fullname):
+ # Load a module from the test extension by name.
+ origin = self.spec.origin
+- loader = self.machinery.ExtensionFileLoader(fullname, origin)
++ loader = self.LoaderClass(fullname, origin)
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+@@ -139,8 +152,7 @@
+ with self.assertRaises(AttributeError):
+ module.__path__
+ self.assertIs(module, sys.modules[self.name])
+- self.assertIsInstance(module.__loader__,
+- self.machinery.ExtensionFileLoader)
++ self.assertIsInstance(module.__loader__, self.LoaderClass)
+
+ # No extension module as __init__ available for testing.
+ test_package = None
+@@ -184,6 +196,14 @@
+ def setUp(self):
+ if not self.machinery.EXTENSION_SUFFIXES or not util.EXTENSIONS:
+ raise unittest.SkipTest("Requires dynamic loading support.")
++
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if is_apple_mobile:
++ self.LoaderClass = self.machinery.AppleFrameworkLoader
++ else:
++ self.LoaderClass = self.machinery.ExtensionFileLoader
++
+ self.name = '_testmultiphase'
+ if self.name in sys.builtin_module_names:
+ raise unittest.SkipTest(
+@@ -192,8 +212,7 @@
+ finder = self.machinery.FileFinder(None)
+ self.spec = importlib.util.find_spec(self.name)
+ assert self.spec
+- self.loader = self.machinery.ExtensionFileLoader(
+- self.name, self.spec.origin)
++ self.loader = self.LoaderClass(self.name, self.spec.origin)
+
+ def load_module(self):
+ # Load the module from the test extension.
+@@ -204,7 +223,7 @@
+ def load_module_by_name(self, fullname):
+ # Load a module from the test extension by name.
+ origin = self.spec.origin
+- loader = self.machinery.ExtensionFileLoader(fullname, origin)
++ loader = self.LoaderClass(fullname, origin)
+ spec = importlib.util.spec_from_loader(fullname, loader)
+ module = importlib.util.module_from_spec(spec)
+ loader.exec_module(module)
+@@ -230,8 +249,7 @@
+ with self.assertRaises(AttributeError):
+ module.__path__
+ self.assertIs(module, sys.modules[self.name])
+- self.assertIsInstance(module.__loader__,
+- self.machinery.ExtensionFileLoader)
++ self.assertIsInstance(module.__loader__, self.LoaderClass)
+
+ def test_functionality(self):
+ # Test basic functionality of stuff defined in an extension module.
+diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py
+index e018af2e16b..743e947e564 100644
+--- a/Lib/test/test_importlib/test_util.py
++++ b/Lib/test/test_importlib/test_util.py
+@@ -701,13 +701,20 @@
+
+ @unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
+ def test_incomplete_multi_phase_init_module(self):
++ # Apple extensions must be distributed as frameworks. This requires
++ # a specialist loader.
++ if support.is_apple_mobile:
++ loader = "AppleFrameworkLoader"
++ else:
++ loader = "ExtensionFileLoader"
++
+ prescript = textwrap.dedent(f'''
+ from importlib.util import spec_from_loader, module_from_spec
+- from importlib.machinery import ExtensionFileLoader
++ from importlib.machinery import {loader}
+
+ name = '_test_shared_gil_only'
+ filename = {_testmultiphase.__file__!r}
+- loader = ExtensionFileLoader(name, filename)
++ loader = {loader}(name, filename)
+ spec = spec_from_loader(name, loader)
+
+ ''')
+diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py
+index a900cc1dddf..89272484009 100644
+--- a/Lib/test/test_importlib/util.py
++++ b/Lib/test/test_importlib/util.py
+@@ -8,6 +8,7 @@
+ import os.path
+ from test import support
+ from test.support import import_helper
++from test.support import is_apple_mobile
+ from test.support import os_helper
+ import unittest
+ import sys
+@@ -43,6 +44,11 @@
+ global EXTENSIONS
+ for path in sys.path:
+ for ext in machinery.EXTENSION_SUFFIXES:
++ # Apple mobile platforms mechanically load .so files,
++ # but the findable files are labelled .fwork
++ if is_apple_mobile:
++ ext = ext.replace(".so", ".fwork")
++
+ filename = EXTENSIONS.name + ext
+ file_path = os.path.join(path, filename)
+ if os.path.exists(file_path):
+diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py
+index 0cd9e721b20..ffa58230425 100644
+--- a/Lib/test/test_interpreters.py
++++ b/Lib/test/test_interpreters.py
+@@ -752,6 +752,7 @@
+
+ class FinalizationTests(TestBase):
+
++ @support.requires_subprocess()
+ def test_gh_109793(self):
+ import subprocess
+ argv = [sys.executable, '-c', '''if True:
+diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
+index daa40a6ba36..1cfc28884f8 100644
+--- a/Lib/test/test_io.py
++++ b/Lib/test/test_io.py
+@@ -39,11 +39,9 @@
+ from test import support
+ from test.support.script_helper import (
+ assert_python_ok, assert_python_failure, run_python_until_end)
+-from test.support import import_helper
+-from test.support import os_helper
+-from test.support import threading_helper
+-from test.support import warnings_helper
+-from test.support import skip_if_sanitizer
++from test.support import (
++ import_helper, is_apple, os_helper, skip_if_sanitizer, threading_helper, warnings_helper
++)
+ from test.support.os_helper import FakePath
+
+ import codecs
+@@ -631,10 +629,10 @@
+ self.read_ops(f, True)
+
+ def test_large_file_ops(self):
+- # On Windows and Mac OSX this test consumes large resources; It takes
+- # a long time to build the >2 GiB file and takes >2 GiB of disk space
+- # therefore the resource must be enabled to run this test.
+- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
++ # On Windows and Apple platforms this test consumes large resources; It
++ # takes a long time to build the >2 GiB file and takes >2 GiB of disk
++ # space therefore the resource must be enabled to run this test.
++ if sys.platform[:3] == 'win' or is_apple:
+ support.requires(
+ 'largefile',
+ 'test requires %s bytes and a long time to run' % self.LARGE)
+diff --git a/Lib/test/test_lib2to3/test_parser.py b/Lib/test/test_lib2to3/test_parser.py
+index 2c798b181fd..e12ed1e9389 100644
+--- a/Lib/test/test_lib2to3/test_parser.py
++++ b/Lib/test/test_lib2to3/test_parser.py
+@@ -62,9 +62,7 @@
+ shutil.rmtree(tmpdir)
+
+ @unittest.skipIf(sys.executable is None, 'sys.executable required')
+- @unittest.skipIf(
+- sys.platform in {'emscripten', 'wasi'}, 'requires working subprocess'
+- )
++ @test.support.requires_subprocess()
+ def test_load_grammar_from_subprocess(self):
+ tmpdir = tempfile.mkdtemp()
+ tmpsubdir = os.path.join(tmpdir, 'subdir')
+diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
+index 6dd1b6f8047..a51f60a0b18 100644
+--- a/Lib/test/test_logging.py
++++ b/Lib/test/test_logging.py
+@@ -3866,6 +3866,7 @@
+ self.addCleanup(os.remove, fn)
+
+ @threading_helper.requires_working_threading()
++ @support.requires_subprocess()
+ def test_config_queue_handler(self):
+ q = CustomQueue()
+ dq = {
+@@ -3894,12 +3895,10 @@
+ msg = str(ctx.exception)
+ self.assertEqual(msg, "Unable to configure handler 'ah'")
+
++ @support.requires_subprocess()
+ def test_multiprocessing_queues(self):
+ # See gh-119819
+
+- # will skip test if it's not available
+- import_helper.import_module('_multiprocessing')
+-
+ cd = copy.deepcopy(self.config_queue_handler)
+ from multiprocessing import Queue as MQ, Manager as MM
+ q1 = MQ() # this can't be pickled
+diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
+index 3d9d6d5d0ac..9c759170450 100644
+--- a/Lib/test/test_marshal.py
++++ b/Lib/test/test_marshal.py
+@@ -1,5 +1,5 @@
+ from test import support
+-from test.support import os_helper, requires_debug_ranges
++from test.support import is_apple_mobile, os_helper, requires_debug_ranges
+ from test.support.script_helper import assert_python_ok
+ import array
+ import io
+@@ -260,7 +260,7 @@
+ #if os.name == 'nt' and support.Py_DEBUG:
+ if os.name == 'nt':
+ MAX_MARSHAL_STACK_DEPTH = 1000
+- elif sys.platform == 'wasi':
++ elif sys.platform == 'wasi' or is_apple_mobile:
+ MAX_MARSHAL_STACK_DEPTH = 1500
+ else:
+ MAX_MARSHAL_STACK_DEPTH = 2000
+diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
+index 1867e8c957f..f75e40940e4 100644
+--- a/Lib/test/test_mmap.py
++++ b/Lib/test/test_mmap.py
+@@ -1,5 +1,5 @@
+ from test.support import (
+- requires, _2G, _4G, gc_collect, cpython_only, is_emscripten
++ requires, _2G, _4G, gc_collect, cpython_only, is_emscripten, is_apple,
+ )
+ from test.support.import_helper import import_module
+ from test.support.os_helper import TESTFN, unlink
+@@ -1009,7 +1009,7 @@
+ unlink(TESTFN)
+
+ def _make_test_file(self, num_zeroes, tail):
+- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
++ if sys.platform[:3] == 'win' or is_apple:
+ requires('largefile',
+ 'test requires %s bytes and a long time to run' % str(0x180000000))
+ f = open(TESTFN, 'w+b')
+diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
+index 88037059e96..e38b9341cfb 100644
+--- a/Lib/test/test_os.py
++++ b/Lib/test/test_os.py
+@@ -2371,6 +2371,7 @@
+ support.is_emscripten or support.is_wasi,
+ "musl libc issue on Emscripten/WASI, bpo-46390"
+ )
++ @unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
+ def test_fpathconf(self):
+ self.check(os.pathconf, "PC_NAME_MAX")
+ self.check(os.fpathconf, "PC_NAME_MAX")
+@@ -3944,6 +3945,7 @@
+ self.assertGreaterEqual(size.columns, 0)
+ self.assertGreaterEqual(size.lines, 0)
+
++ @support.requires_subprocess()
+ def test_stty_match(self):
+ """Check if stty returns the same results
+
+diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py
+index b62a9e38977..39b9f7b178b 100644
+--- a/Lib/test/test_platform.py
++++ b/Lib/test/test_platform.py
+@@ -10,6 +10,14 @@
+ from test import support
+ from test.support import os_helper
+
++try:
++ # Some of the iOS tests need ctypes to operate.
++ # Confirm that the ctypes module is available
++ # is available.
++ import _ctypes
++except ImportError:
++ _ctypes = None
++
+ FEDORA_OS_RELEASE = """\
+ NAME=Fedora
+ VERSION="32 (Thirty Two)"
+@@ -219,6 +227,30 @@
+ self.assertEqual(res[-1], res.processor)
+ self.assertEqual(len(res), 6)
+
++ if os.name == "posix":
++ uname = os.uname()
++ self.assertEqual(res.node, uname.nodename)
++ self.assertEqual(res.version, uname.version)
++ self.assertEqual(res.machine, uname.machine)
++
++ if sys.platform == "android":
++ self.assertEqual(res.system, "Android")
++ self.assertEqual(res.release, platform.android_ver().release)
++ elif sys.platform == "ios":
++ # Platform module needs ctypes for full operation. If ctypes
++ # isn't available, there's no ObjC module, and dummy values are
++ # returned.
++ if _ctypes:
++ self.assertIn(res.system, {"iOS", "iPadOS"})
++ self.assertEqual(res.release, platform.ios_ver().release)
++ else:
++ self.assertEqual(res.system, "")
++ self.assertEqual(res.release, "")
++ else:
++ self.assertEqual(res.system, uname.sysname)
++ self.assertEqual(res.release, uname.release)
++
++
+ @unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
+ def test_uname_win32_without_wmi(self):
+ def raises_oserror(*a):
+@@ -405,6 +437,56 @@
+ # parent
+ support.wait_process(pid, exitcode=0)
+
++ def test_ios_ver(self):
++ result = platform.ios_ver()
++
++ # ios_ver is only fully available on iOS where ctypes is available.
++ if sys.platform == "ios" and _ctypes:
++ system, release, model, is_simulator = result
++ # Result is a namedtuple
++ self.assertEqual(result.system, system)
++ self.assertEqual(result.release, release)
++ self.assertEqual(result.model, model)
++ self.assertEqual(result.is_simulator, is_simulator)
++
++ # We can't assert specific values without reproducing the logic of
++ # ios_ver(), so we check that the values are broadly what we expect.
++
++ # System is either iOS or iPadOS, depending on the test device
++ self.assertIn(system, {"iOS", "iPadOS"})
++
++ # Release is a numeric version specifier with at least 2 parts
++ parts = release.split(".")
++ self.assertGreaterEqual(len(parts), 2)
++ self.assertTrue(all(part.isdigit() for part in parts))
++
++ # If this is a simulator, we get a high level device descriptor
++ # with no identifying model number. If this is a physical device,
++ # we get a model descriptor like "iPhone13,1"
++ if is_simulator:
++ self.assertIn(model, {"iPhone", "iPad"})
++ else:
++ self.assertTrue(
++ (model.startswith("iPhone") or model.startswith("iPad"))
++ and "," in model
++ )
++
++ self.assertEqual(type(is_simulator), bool)
++ else:
++ # On non-iOS platforms, calling ios_ver doesn't fail; you get
++ # default values
++ self.assertEqual(result.system, "")
++ self.assertEqual(result.release, "")
++ self.assertEqual(result.model, "")
++ self.assertFalse(result.is_simulator)
++
++ # Check the fallback values can be overridden by arguments
++ override = platform.ios_ver("Foo", "Bar", "Whiz", True)
++ self.assertEqual(override.system, "Foo")
++ self.assertEqual(override.release, "Bar")
++ self.assertEqual(override.model, "Whiz")
++ self.assertTrue(override.is_simulator)
++
+ @unittest.skipIf(support.is_emscripten, "Does not apply to Emscripten")
+ def test_libc_ver(self):
+ # check that libc_ver(executable) doesn't raise an exception
+@@ -500,7 +582,8 @@
+ 'root:xnu-4570.71.2~1/RELEASE_X86_64'),
+ 'x86_64', 'i386')
+ arch = ('64bit', '')
+- with mock.patch.object(platform, 'uname', return_value=uname), \
++ with mock.patch.object(sys, "platform", "darwin"), \
++ mock.patch.object(platform, 'uname', return_value=uname), \
+ mock.patch.object(platform, 'architecture', return_value=arch):
+ for mac_ver, expected_terse, expected in [
+ # darwin: mac_ver() returns empty strings
+diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
+index 7ed45acf28c..9bb1d056eb7 100644
+--- a/Lib/test/test_posix.py
++++ b/Lib/test/test_posix.py
+@@ -1,7 +1,7 @@
+ "Test posix functions"
+
+ from test import support
+-from test.support import import_helper
++from test.support import is_apple
+ from test.support import os_helper
+ from test.support import warnings_helper
+ from test.support.script_helper import assert_python_ok
+@@ -564,6 +564,7 @@
+
+ @unittest.skipUnless(hasattr(posix, 'confstr'),
+ 'test needs posix.confstr()')
++ @unittest.skipIf(support.is_apple_mobile, "gh-118201: Test is flaky on iOS")
+ def test_confstr(self):
+ self.assertRaises(ValueError, posix.confstr, "CS_garbage")
+ self.assertEqual(len(posix.confstr("CS_PATH")) > 0, True)
+@@ -792,9 +793,10 @@
+ check_stat(uid, gid)
+ self.assertRaises(OSError, chown_func, first_param, 0, -1)
+ check_stat(uid, gid)
+- if 0 not in os.getgroups():
+- self.assertRaises(OSError, chown_func, first_param, -1, 0)
+- check_stat(uid, gid)
++ if hasattr(os, 'getgroups'):
++ if 0 not in os.getgroups():
++ self.assertRaises(OSError, chown_func, first_param, -1, 0)
++ check_stat(uid, gid)
+ # test illegal types
+ for t in str, float:
+ self.assertRaises(TypeError, chown_func, first_param, t(uid), gid)
+@@ -1260,8 +1262,8 @@
+ self.assertIsInstance(lo, int)
+ self.assertIsInstance(hi, int)
+ self.assertGreaterEqual(hi, lo)
+- # OSX evidently just returns 15 without checking the argument.
+- if sys.platform != "darwin":
++ # Apple plaforms return 15 without checking the argument.
++ if not is_apple:
+ self.assertRaises(OSError, posix.sched_get_priority_min, -23)
+ self.assertRaises(OSError, posix.sched_get_priority_max, -23)
+
+@@ -2041,11 +2043,13 @@
+
+
+ @unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn")
++@support.requires_subprocess()
+ class TestPosixSpawn(unittest.TestCase, _PosixSpawnMixin):
+ spawn_func = getattr(posix, 'posix_spawn', None)
+
+
+ @unittest.skipUnless(hasattr(os, 'posix_spawnp'), "test needs os.posix_spawnp")
++@support.requires_subprocess()
+ class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin):
+ spawn_func = getattr(posix, 'posix_spawnp', None)
+
+diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py
+index 51e3a46d0df..3f2bac0155f 100644
+--- a/Lib/test/test_pty.py
++++ b/Lib/test/test_pty.py
+@@ -1,12 +1,17 @@
+-from test.support import verbose, reap_children
+-from test.support.os_helper import TESTFN, unlink
++import sys
++import unittest
++from test.support import (
++ is_apple_mobile, is_emscripten, is_wasi, reap_children, verbose
++)
+ from test.support.import_helper import import_module
++from test.support.os_helper import TESTFN, unlink
+
+-# Skip these tests if termios or fcntl are not available
++# Skip these tests if termios is not available
+ import_module('termios')
+-# fcntl is a proxy for not being one of the wasm32 platforms even though we
+-# don't use this module... a proper check for what crashes those is needed.
+-import_module("fcntl")
++
++# Skip tests on WASM platforms, plus iOS/tvOS/watchOS
++if is_apple_mobile or is_emscripten or is_wasi:
++ raise unittest.SkipTest(f"pty tests not required on {sys.platform}")
+
+ import errno
+ import os
+@@ -17,7 +22,6 @@
+ import signal
+ import socket
+ import io # readline
+-import unittest
+ import warnings
+
+ TEST_STRING_1 = b"I wish to buy a fish license.\n"
+diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py
+index 31757205ca3..6b88b121580 100644
+--- a/Lib/test/test_selectors.py
++++ b/Lib/test/test_selectors.py
+@@ -6,8 +6,7 @@
+ import socket
+ import sys
+ from test import support
+-from test.support import os_helper
+-from test.support import socket_helper
++from test.support import is_apple, os_helper, socket_helper
+ from time import sleep
+ import unittest
+ import unittest.mock
+@@ -520,7 +519,7 @@
+ try:
+ fds = s.select()
+ except OSError as e:
+- if e.errno == errno.EINVAL and sys.platform == 'darwin':
++ if e.errno == errno.EINVAL and is_apple:
+ # unexplainable errors on macOS don't need to fail the test
+ self.skipTest("Invalid argument error calling poll()")
+ raise
+diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
+index 7bc5d12e09c..1680706a4d5 100644
+--- a/Lib/test/test_shutil.py
++++ b/Lib/test/test_shutil.py
+@@ -2228,6 +2228,7 @@
+ check_chown(dirname, uid, gid)
+
+
++@support.requires_subprocess()
+ class TestWhich(BaseTest, unittest.TestCase):
+
+ def setUp(self):
+@@ -3261,6 +3262,7 @@
+ self.assertGreaterEqual(size.lines, 0)
+
+ @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
++ @support.requires_subprocess()
+ @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
+ 'need os.get_terminal_size()')
+ def test_stty_match(self):
+diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
+index c7b9549dd3a..591cd4177d9 100644
+--- a/Lib/test/test_signal.py
++++ b/Lib/test/test_signal.py
+@@ -13,9 +13,10 @@
+ import time
+ import unittest
+ from test import support
+-from test.support import os_helper
++from test.support import (
++ is_apple, is_apple_mobile, os_helper, threading_helper
++)
+ from test.support.script_helper import assert_python_ok, spawn_python
+-from test.support import threading_helper
+ try:
+ import _testcapi
+ except ImportError:
+@@ -832,7 +833,7 @@
+ self.assertEqual(self.hndl_called, True)
+
+ # Issue 3864, unknown if this affects earlier versions of freebsd also
+- @unittest.skipIf(sys.platform in ('netbsd5',),
++ @unittest.skipIf(sys.platform in ('netbsd5',) or is_apple_mobile,
+ 'itimer not reliable (does not mix well with threading) on some BSDs.')
+ def test_itimer_virtual(self):
+ self.itimer = signal.ITIMER_VIRTUAL
+@@ -1344,7 +1345,7 @@
+ # Python handler
+ self.assertEqual(len(sigs), N, "Some signals were lost")
+
+- @unittest.skipIf(sys.platform == "darwin", "crashes due to system bug (FB13453490)")
++ @unittest.skipIf(is_apple, "crashes due to system bug (FB13453490)")
+ @unittest.skipUnless(hasattr(signal, "SIGUSR1"),
+ "test needs SIGUSR1")
+ @threading_helper.requires_working_threading()
+diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
+index cda956499ed..16a876f837f 100644
+--- a/Lib/test/test_socket.py
++++ b/Lib/test/test_socket.py
+@@ -3,6 +3,7 @@
+ from test.support import os_helper
+ from test.support import socket_helper
+ from test.support import threading_helper
++from test.support import is_apple
+
+ import _thread as thread
+ import array
+@@ -1171,8 +1172,11 @@
+ # Find one service that exists, then check all the related interfaces.
+ # I've ordered this by protocols that have both a tcp and udp
+ # protocol, at least for modern Linuxes.
+- if (sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
+- or sys.platform in ('linux', 'darwin')):
++ if (
++ sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
++ or sys.platform == 'linux'
++ or is_apple
++ ):
+ # avoid the 'echo' service on this platform, as there is an
+ # assumption breaking non-standard port/protocol entry
+ services = ('daytime', 'qotd', 'domain')
+@@ -3683,7 +3687,7 @@
+ def _testFDPassCMSG_LEN(self):
+ self.createAndSendFDs(1)
+
+- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
++ @unittest.skipIf(is_apple, "skipping, see issue #12958")
+ @unittest.skipIf(AIX, "skipping, see issue #22397")
+ @requireAttrs(socket, "CMSG_SPACE")
+ def testFDPassSeparate(self):
+@@ -3694,7 +3698,7 @@
+ maxcmsgs=2)
+
+ @testFDPassSeparate.client_skip
+- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
++ @unittest.skipIf(is_apple, "skipping, see issue #12958")
+ @unittest.skipIf(AIX, "skipping, see issue #22397")
+ def _testFDPassSeparate(self):
+ fd0, fd1 = self.newFDs(2)
+@@ -3707,7 +3711,7 @@
+ array.array("i", [fd1]))]),
+ len(MSG))
+
+- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
++ @unittest.skipIf(is_apple, "skipping, see issue #12958")
+ @unittest.skipIf(AIX, "skipping, see issue #22397")
+ @requireAttrs(socket, "CMSG_SPACE")
+ def testFDPassSeparateMinSpace(self):
+@@ -3721,7 +3725,7 @@
+ maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC)
+
+ @testFDPassSeparateMinSpace.client_skip
+- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
++ @unittest.skipIf(is_apple, "skipping, see issue #12958")
+ @unittest.skipIf(AIX, "skipping, see issue #22397")
+ def _testFDPassSeparateMinSpace(self):
+ fd0, fd1 = self.newFDs(2)
+@@ -3745,7 +3749,7 @@
+ nbytes = self.sendmsgToServer([msg])
+ self.assertEqual(nbytes, len(msg))
+
+- @unittest.skipIf(sys.platform == "darwin", "see issue #24725")
++ @unittest.skipIf(is_apple, "skipping, see issue #12958")
+ def testFDPassEmpty(self):
+ # Try to pass an empty FD array. Can receive either no array
+ # or an empty array.
+diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py
+index f0b99b13f68..f10b5209eb7 100644
+--- a/Lib/test/test_sqlite3/test_dbapi.py
++++ b/Lib/test/test_sqlite3/test_dbapi.py
+@@ -32,7 +32,7 @@
+
+ from test.support import (
+ SHORT_TIMEOUT, check_disallow_instantiation, requires_subprocess,
+- is_emscripten, is_wasi
++ is_apple, is_emscripten, is_wasi
+ )
+ from test.support import threading_helper
+ from _testcapi import INT_MAX, ULLONG_MAX
+@@ -679,7 +679,7 @@
+ cx.execute(self._sql)
+
+ @unittest.skipIf(sys.platform == "win32", "skipped on Windows")
+- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS")
++ @unittest.skipIf(is_apple, "skipped on Apple platforms")
+ @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI")
+ @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths")
+ def test_open_with_undecodable_path(self):
+@@ -725,7 +725,7 @@
+ cx.execute(self._sql)
+
+ @unittest.skipIf(sys.platform == "win32", "skipped on Windows")
+- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS")
++ @unittest.skipIf(is_apple, "skipped on Apple platforms")
+ @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI")
+ @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths")
+ def test_open_undecodable_uri(self):
+diff --git a/Lib/test/test_stat.py b/Lib/test/test_stat.py
+index c77fec3d39d..ca55d429aec 100644
+--- a/Lib/test/test_stat.py
++++ b/Lib/test/test_stat.py
+@@ -2,8 +2,7 @@
+ import os
+ import socket
+ import sys
+-from test.support import os_helper
+-from test.support import socket_helper
++from test.support import is_apple, os_helper, socket_helper
+ from test.support.import_helper import import_fresh_module
+ from test.support.os_helper import TESTFN
+
+diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py
+index 196fd60d197..9543f9a383c 100644
+--- a/Lib/test/test_sys_settrace.py
++++ b/Lib/test/test_sys_settrace.py
+@@ -7,7 +7,7 @@
+ import gc
+ from functools import wraps
+ import asyncio
+-from test.support import import_helper
++from test.support import import_helper, requires_subprocess
+ import contextlib
+ import warnings
+
+diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
+index 1137c2032b9..89d046c865c 100644
+--- a/Lib/test/test_sysconfig.py
++++ b/Lib/test/test_sysconfig.py
+@@ -6,7 +6,11 @@
+ from copy import copy
+
+ from test.support import (
+- captured_stdout, PythonSymlink, requires_subprocess, is_wasi
++ captured_stdout,
++ is_apple_mobile,
++ is_wasi,
++ PythonSymlink,
++ requires_subprocess,
+ )
+ from test.support.import_helper import import_module
+ from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink,
+@@ -339,6 +343,8 @@
+ # XXX more platforms to tests here
+
+ @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
++ @unittest.skipIf(is_apple_mobile,
++ f"{sys.platform} doesn't distribute header files in the runtime environment")
+ def test_get_config_h_filename(self):
+ config_h = sysconfig.get_config_h_filename()
+ self.assertTrue(os.path.isfile(config_h), config_h)
+@@ -448,6 +454,8 @@
+ self.assertEqual(my_platform, test_platform)
+
+ @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
++ @unittest.skipIf(is_apple_mobile,
++ f"{sys.platform} doesn't include config folder at runtime")
+ def test_srcdir(self):
+ # See Issues #15322, #15364.
+ srcdir = sysconfig.get_config_var('srcdir')
+@@ -516,6 +524,8 @@
+ @unittest.skipIf(sys.platform.startswith('win'),
+ 'Test is not Windows compatible')
+ @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds")
++ @unittest.skipIf(is_apple_mobile,
++ f"{sys.platform} doesn't include config folder at runtime")
+ def test_get_makefile_filename(self):
+ makefile = sysconfig.get_makefile_filename()
+ self.assertTrue(os.path.isfile(makefile), makefile)
+diff --git a/Lib/test/test_unicode_file_functions.py b/Lib/test/test_unicode_file_functions.py
+index 47619c8807b..25c16e3a0b7 100644
+--- a/Lib/test/test_unicode_file_functions.py
++++ b/Lib/test/test_unicode_file_functions.py
+@@ -5,7 +5,7 @@
+ import unittest
+ import warnings
+ from unicodedata import normalize
+-from test.support import os_helper
++from test.support import is_apple, os_helper
+ from test import support
+
+
+@@ -23,13 +23,13 @@
+ '10_\u1fee\u1ffd',
+ ]
+
+-# Mac OS X decomposes Unicode names, using Normal Form D.
++# Apple platforms decompose Unicode names, using Normal Form D.
+ # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
+ # "However, most volume formats do not follow the exact specification for
+ # these normal forms. For example, HFS Plus uses a variant of Normal Form D
+ # in which U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through
+ # U+2FAFF are not decomposed."
+-if sys.platform != 'darwin':
++if not is_apple:
+ filenames.extend([
+ # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all different
+ '11_\u0385\u03d3\u03d4',
+@@ -119,11 +119,11 @@
+ os.stat(name)
+ self._apply_failure(os.listdir, name, self._listdir_failure)
+
+- # Skip the test on darwin, because darwin does normalize the filename to
++ # Skip the test on Apple platforms, because they don't normalize the filename to
+ # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC,
+ # NFKD in Python is useless, because darwin will normalize it later and so
+ # open(), os.stat(), etc. don't raise any exception.
+- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X')
++ @unittest.skipIf(is_apple, 'irrelevant test on Apple platforms')
+ @unittest.skipIf(
+ support.is_emscripten or support.is_wasi,
+ "test fails on Emscripten/WASI when host platform is macOS."
+@@ -142,10 +142,10 @@
+ self._apply_failure(os.remove, name)
+ self._apply_failure(os.listdir, name)
+
+- # Skip the test on darwin, because darwin uses a normalization different
++ # Skip the test on Apple platforms, because they use a normalization different
+ # than Python NFD normalization: filenames are different even if we use
+ # Python NFD normalization.
+- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X')
++ @unittest.skipIf(is_apple, 'irrelevant test on Apple platforms')
+ def test_listdir(self):
+ sf0 = set(self.files)
+ with warnings.catch_warnings():
+diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
+index 69cf1dc7aef..6febb491788 100644
+--- a/Lib/test/test_urllib2.py
++++ b/Lib/test/test_urllib2.py
+@@ -1,6 +1,7 @@
+ import unittest
+ from test import support
+ from test.support import os_helper
++from test.support import requires_subprocess
+ from test.support import warnings_helper
+ from test import test_urllib
+ from unittest import mock
+@@ -999,6 +1000,7 @@
+
+ file_obj.close()
+
++ @requires_subprocess()
+ def test_http_body_pipe(self):
+ # A file reading from a pipe.
+ # A pipe cannot be seek'ed. There is no way to determine the
+diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
+index feaf9784549..ec73bcc2027 100644
+--- a/Lib/test/test_venv.py
++++ b/Lib/test/test_venv.py
+@@ -19,8 +19,8 @@
+ import tempfile
+ from test.support import (captured_stdout, captured_stderr,
+ skip_if_broken_multiprocessing_synchronize, verbose,
+- requires_subprocess, is_emscripten, is_wasi,
+- requires_venv_with_pip, TEST_HOME_DIR,
++ requires_subprocess, is_apple_mobile, is_emscripten,
++ is_wasi, requires_venv_with_pip, TEST_HOME_DIR,
+ requires_resource, copy_python_src_ignore)
+ from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree,
+ TESTFN, FakePath)
+@@ -40,8 +40,10 @@
+ or sys._base_executable != sys.executable,
+ 'cannot run venv.create from within a venv on this platform')
+
+-if is_emscripten or is_wasi:
+- raise unittest.SkipTest("venv is not available on Emscripten/WASI.")
++# Skip tests on WASM platforms, plus iOS/tvOS/watchOS
++if is_apple_mobile or is_emscripten or is_wasi:
++ raise unittest.SkipTest(f"venv tests not required on {sys.platform}")
++
+
+ @requires_subprocess()
+ def check_output(cmd, encoding=None):
+diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py
+index 2d695bc8831..4a6586fb1dd 100644
+--- a/Lib/test/test_webbrowser.py
++++ b/Lib/test/test_webbrowser.py
+@@ -5,11 +5,14 @@
+ import subprocess
+ from unittest import mock
+ from test import support
++from test.support import is_apple_mobile
+ from test.support import import_helper
+ from test.support import os_helper
++from test.support import requires_subprocess
++from test.support import threading_helper
+
+-if not support.has_subprocess_support:
+- raise unittest.SkipTest("test webserver requires subprocess")
++# The webbrowser module uses threading locks
++threading_helper.requires_working_threading(module=True)
+
+ URL = 'https://www.example.com'
+ CMD_NAME = 'test'
+@@ -24,6 +27,7 @@
+ return 0
+
+
++@requires_subprocess()
+ class CommandTestMixin:
+
+ def _test(self, meth, *, args=[URL], kw={}, options, arguments):
+@@ -219,6 +223,73 @@
+ arguments=['openURL({},new-tab)'.format(URL)])
+
+
++@unittest.skipUnless(sys.platform == "ios", "Test only applicable to iOS")
++class IOSBrowserTest(unittest.TestCase):
++ def _obj_ref(self, *args):
++ # Construct a string representation of the arguments that can be used
++ # as a proxy for object instance references
++ return "|".join(str(a) for a in args)
++
++ @unittest.skipIf(getattr(webbrowser, "objc", None) is None,
++ "iOS Webbrowser tests require ctypes")
++ def setUp(self):
++ # Intercept the the objc library. Wrap the calls to get the
++ # references to classes and selectors to return strings, and
++ # wrap msgSend to return stringified object references
++ self.orig_objc = webbrowser.objc
++
++ webbrowser.objc = mock.Mock()
++ webbrowser.objc.objc_getClass = lambda cls: f"C#{cls.decode()}"
++ webbrowser.objc.sel_registerName = lambda sel: f"S#{sel.decode()}"
++ webbrowser.objc.objc_msgSend.side_effect = self._obj_ref
++
++ def tearDown(self):
++ webbrowser.objc = self.orig_objc
++
++ def _test(self, meth, **kwargs):
++ # The browser always gets focus, there's no concept of separate browser
++ # windows, and there's no API-level control over creating a new tab.
++ # Therefore, all calls to webbrowser are effectively the same.
++ getattr(webbrowser, meth)(URL, **kwargs)
++
++ # The ObjC String version of the URL is created with UTF-8 encoding
++ url_string_args = [
++ "C#NSString",
++ "S#stringWithCString:encoding:",
++ b'https://www.example.com',
++ 4,
++ ]
++ # The NSURL version of the URL is created from that string
++ url_obj_args = [
++ "C#NSURL",
++ "S#URLWithString:",
++ self._obj_ref(*url_string_args),
++ ]
++ # The openURL call is invoked on the shared application
++ shared_app_args = ["C#UIApplication", "S#sharedApplication"]
++
++ # Verify that the last call is the one that opens the URL.
++ webbrowser.objc.objc_msgSend.assert_called_with(
++ self._obj_ref(*shared_app_args),
++ "S#openURL:options:completionHandler:",
++ self._obj_ref(*url_obj_args),
++ None,
++ None
++ )
++
++ def test_open(self):
++ self._test('open')
++
++ def test_open_with_autoraise_false(self):
++ self._test('open', autoraise=False)
++
++ def test_open_new(self):
++ self._test('open_new')
++
++ def test_open_new_tab(self):
++ self._test('open_new_tab')
++
++
+ class BrowserRegistrationTest(unittest.TestCase):
+
+ def setUp(self):
+@@ -302,6 +373,10 @@
+ webbrowser.register(name, None, webbrowser.GenericBrowser(name))
+ webbrowser.get(sys.executable)
+
++ @unittest.skipIf(
++ is_apple_mobile,
++ "Apple mobile doesn't allow modifying browser with environment"
++ )
+ def test_environment(self):
+ webbrowser = import_helper.import_fresh_module('webbrowser')
+ try:
+@@ -313,6 +388,10 @@
+ webbrowser = import_helper.import_fresh_module('webbrowser')
+ webbrowser.get()
+
++ @unittest.skipIf(
++ is_apple_mobile,
++ "Apple mobile doesn't allow modifying browser with environment"
++ )
+ def test_environment_preferred(self):
+ webbrowser = import_helper.import_fresh_module('webbrowser')
+ try:
+diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
+index ba6711e4ef5..2fa8612b584 100755
+--- a/Lib/webbrowser.py
++++ b/Lib/webbrowser.py
+@@ -473,6 +473,9 @@
+ # OS X can use below Unix support (but we prefer using the OS X
+ # specific stuff)
+
++ if sys.platform == "ios":
++ register("iosbrowser", None, IOSBrowser(), preferred=True)
++
+ if sys.platform == "serenityos":
+ # SerenityOS webbrowser, simply called "Browser".
+ register("Browser", None, BackgroundBrowser("Browser"))
+@@ -653,6 +656,70 @@
+ rc = osapipe.close()
+ return not rc
+
++#
++# Platform support for iOS
++#
++if sys.platform == "ios":
++ from _ios_support import objc
++ if objc:
++ # If objc exists, we know ctypes is also importable.
++ from ctypes import c_void_p, c_char_p, c_ulong
++
++ class IOSBrowser(BaseBrowser):
++ def open(self, url, new=0, autoraise=True):
++ sys.audit("webbrowser.open", url)
++ # If ctypes isn't available, we can't open a browser
++ if objc is None:
++ return False
++
++ # All the messages in this call return object references.
++ objc.objc_msgSend.restype = c_void_p
++
++ # This is the equivalent of:
++ # NSString url_string =
++ # [NSString stringWithCString:url.encode("utf-8")
++ # encoding:NSUTF8StringEncoding];
++ NSString = objc.objc_getClass(b"NSString")
++ constructor = objc.sel_registerName(b"stringWithCString:encoding:")
++ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_char_p, c_ulong]
++ url_string = objc.objc_msgSend(
++ NSString,
++ constructor,
++ url.encode("utf-8"),
++ 4, # NSUTF8StringEncoding = 4
++ )
++
++ # Create an NSURL object representing the URL
++ # This is the equivalent of:
++ # NSURL *nsurl = [NSURL URLWithString:url];
++ NSURL = objc.objc_getClass(b"NSURL")
++ urlWithString_ = objc.sel_registerName(b"URLWithString:")
++ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
++ ns_url = objc.objc_msgSend(NSURL, urlWithString_, url_string)
++
++ # Get the shared UIApplication instance
++ # This code is the equivalent of:
++ # UIApplication shared_app = [UIApplication sharedApplication]
++ UIApplication = objc.objc_getClass(b"UIApplication")
++ sharedApplication = objc.sel_registerName(b"sharedApplication")
++ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
++ shared_app = objc.objc_msgSend(UIApplication, sharedApplication)
++
++ # Open the URL on the shared application
++ # This code is the equivalent of:
++ # [shared_app openURL:ns_url
++ # options:NIL
++ # completionHandler:NIL];
++ openURL_ = objc.sel_registerName(b"openURL:options:completionHandler:")
++ objc.objc_msgSend.argtypes = [
++ c_void_p, c_void_p, c_void_p, c_void_p, c_void_p
++ ]
++ # Method returns void
++ objc.objc_msgSend.restype = None
++ objc.objc_msgSend(shared_app, openURL_, ns_url, None, None)
++
++ return True
++
+
+ def main():
+ import getopt
+--- /dev/null
++++ b/Mac/Resources/app-store-compliance.patch
+@@ -0,0 +1,29 @@
++diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
++index d6c83a75c1c..19ed4e01091 100644
++--- a/Lib/test/test_urlparse.py
+++++ b/Lib/test/test_urlparse.py
++@@ -237,11 +237,6 @@ def test_roundtrips(self):
++ '','',''),
++ ('git+ssh', 'git@github.com','/user/project.git',
++ '', '')),
++- ('itms-services://?action=download-manifest&url=https://example.com/app',
++- ('itms-services', '', '', '',
++- 'action=download-manifest&url=https://example.com/app', ''),
++- ('itms-services', '', '',
++- 'action=download-manifest&url=https://example.com/app', '')),
++ ('+scheme:path/to/file',
++ ('', '', '+scheme:path/to/file', '', '', ''),
++ ('', '', '+scheme:path/to/file', '', '')),
++diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py
++index 8f724f907d4..148caf742c9 100644
++--- a/Lib/urllib/parse.py
+++++ b/Lib/urllib/parse.py
++@@ -59,7 +59,7 @@
++ 'imap', 'wais', 'file', 'mms', 'https', 'shttp',
++ 'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync',
++ 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh',
++- 'ws', 'wss', 'itms-services']
+++ 'ws', 'wss']
++
++ uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap',
++ 'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip',
+diff --git a/Makefile.pre.in b/Makefile.pre.in
+index 4a957fb0044..9e26787e51d 100644
+--- a/Makefile.pre.in
++++ b/Makefile.pre.in
+@@ -178,18 +178,29 @@
+ EXE= @EXEEXT@
+ BUILDEXE= @BUILDEXEEXT@
+
++# Name of the patch file to apply for app store compliance
++APP_STORE_COMPLIANCE_PATCH=@APP_STORE_COMPLIANCE_PATCH@
++
+ # Short name and location for Mac OS X Python framework
+ UNIVERSALSDK=@UNIVERSALSDK@
+ PYTHONFRAMEWORK= @PYTHONFRAMEWORK@
+ PYTHONFRAMEWORKDIR= @PYTHONFRAMEWORKDIR@
+ PYTHONFRAMEWORKPREFIX= @PYTHONFRAMEWORKPREFIX@
+ PYTHONFRAMEWORKINSTALLDIR= @PYTHONFRAMEWORKINSTALLDIR@
+-# Deployment target selected during configure, to be checked
++PYTHONFRAMEWORKINSTALLNAMEPREFIX= @PYTHONFRAMEWORKINSTALLNAMEPREFIX@
++RESSRCDIR= @RESSRCDIR@
++# macOS deployment target selected during configure, to be checked
+ # by distutils. The export statement is needed to ensure that the
+ # deployment target is active during build.
+ MACOSX_DEPLOYMENT_TARGET=@CONFIGURE_MACOSX_DEPLOYMENT_TARGET@
+ @EXPORT_MACOSX_DEPLOYMENT_TARGET@export MACOSX_DEPLOYMENT_TARGET
+
++# iOS Deployment target selected during configure. Unlike macOS, the iOS
++# deployment target is controlled using `-mios-version-min` arguments added to
++# CFLAGS and LDFLAGS by the configure script. This variable is not used during
++# the build, and is only listed here so it will be included in sysconfigdata.
++IPHONEOS_DEPLOYMENT_TARGET=@IPHONEOS_DEPLOYMENT_TARGET@
++
+ # Option to install to strip binaries
+ STRIPFLAG=-s
+
+@@ -614,7 +625,7 @@
+ .PHONY: all
+
+ .PHONY: build_all
+-build_all: check-clean-src $(BUILDPYTHON) platform sharedmods \
++build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) platform sharedmods \
+ gdbhooks Programs/_testembed scripts checksharedmods rundsymutil
+
+ .PHONY: build_wasm
+@@ -637,6 +648,16 @@
+ exit 1; \
+ fi
+
++# Check that the app store compliance patch can be applied (if configured).
++# This is checked as a dry-run against the original library sources;
++# the patch will be actually applied during the install phase.
++.PHONY: check-app-store-compliance
++check-app-store-compliance:
++ @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \
++ patch --dry-run --quiet --force --strip 1 --directory "$(abs_srcdir)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)"; \
++ echo "App store compliance patch can be applied."; \
++ fi
++
+ # Profile generation build must start from a clean tree.
+ profile-clean-stamp:
+ $(MAKE) clean
+@@ -826,7 +847,7 @@
+ $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^
+
+ libpython$(LDVERSION).dylib: $(LIBRARY_OBJS)
+- $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \
++ $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \
+
+
+ libpython$(VERSION).sl: $(LIBRARY_OBJS)
+@@ -851,14 +872,13 @@
+ # This rule is here for OPENSTEP/Rhapsody/MacOSX. It builds a temporary
+ # minimal framework (not including the Lib directory and such) in the current
+ # directory.
+-RESSRCDIR=Mac/Resources/framework
+ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \
+ $(LIBRARY) \
+ $(RESSRCDIR)/Info.plist
+ $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)
+ $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
+- -all_load $(LIBRARY) -Wl,-single_module \
+- -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \
++ -all_load $(LIBRARY) \
++ -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/$(PYTHONFRAMEWORK) \
+ -compatibility_version $(VERSION) \
+ -current_version $(VERSION) \
+ -framework CoreFoundation $(LIBS);
+@@ -870,6 +890,21 @@
+ $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)
+ $(LN) -fsn Versions/Current/Resources $(PYTHONFRAMEWORKDIR)/Resources
+
++# This rule is for iOS, which requires an annoyingly just slighly different
++# format for frameworks to macOS. It *doesn't* use a versioned framework, and
++# the Info.plist must be in the root of the framework.
++$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK): \
++ $(LIBRARY) \
++ $(RESSRCDIR)/Info.plist
++ $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)
++ $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
++ -all_load $(LIBRARY) \
++ -install_name $(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/$(PYTHONFRAMEWORK) \
++ -compatibility_version $(VERSION) \
++ -current_version $(VERSION) \
++ -framework CoreFoundation $(LIBS);
++ $(INSTALL_DATA) $(RESSRCDIR)/Info.plist $(PYTHONFRAMEWORKDIR)/Info.plist
++
+ # This rule builds the Cygwin Python DLL and import library if configured
+ # for a shared core library; otherwise, this rule is a noop.
+ $(DLLLIBRARY) libpython$(LDVERSION).dll.a: $(LIBRARY_OBJS)
+@@ -1857,6 +1892,54 @@
+ $(RUNSHARED) /usr/libexec/oah/translate \
+ ./$(BUILDPYTHON) -E -m test -j 0 -u all $(TESTOPTS)
+
++# Run the test suite on the iOS simulator. Must be run on a macOS machine with
++# a full Xcode install that has an iPhone SE (3rd edition) simulator available.
++# This must be run *after* a `make install` has completed the build. The
++# `--with-framework-name` argument *cannot* be used when configuring the build.
++XCFOLDER:=iOSTestbed.$(MULTIARCH).$(shell date +%s)
++XCRESULT=$(XCFOLDER)/$(MULTIARCH).xcresult
++.PHONY: testios
++testios:
++ @if test "$(MACHDEP)" != "ios"; then \
++ echo "Cannot run the iOS testbed for a non-iOS build."; \
++ exit 1;\
++ fi
++ @if test "$(findstring -iphonesimulator,$(MULTIARCH))" != "-iphonesimulator"; then \
++ echo "Cannot run the iOS testbed for non-simulator builds."; \
++ exit 1;\
++ fi
++ @if test $(PYTHONFRAMEWORK) != "Python"; then \
++ echo "Cannot run the iOS testbed with a non-default framework name."; \
++ exit 1;\
++ fi
++ @if ! test -d $(PYTHONFRAMEWORKPREFIX); then \
++ echo "Cannot find a finalized iOS Python.framework. Have you run 'make install' to finalize the framework build?"; \
++ exit 1;\
++ fi
++ # Copy the testbed project into the build folder
++ cp -r $(srcdir)/iOS/testbed $(XCFOLDER)
++ # Copy the framework from the install location to the testbed project.
++ cp -r $(PYTHONFRAMEWORKPREFIX)/* $(XCFOLDER)/Python.xcframework/ios-arm64_x86_64-simulator
++
++ # Run the test suite for the Xcode project, targeting the iOS simulator.
++ # If the suite fails, touch a file in the test folder as a marker
++ if ! xcodebuild test -project $(XCFOLDER)/iOSTestbed.xcodeproj -scheme "iOSTestbed" -destination "platform=iOS Simulator,name=iPhone SE (3rd Generation)" -resultBundlePath $(XCRESULT) -derivedDataPath $(XCFOLDER)/DerivedData ; then \
++ touch $(XCFOLDER)/failed; \
++ fi
++
++ # Regardless of success or failure, extract and print the test output
++ xcrun xcresulttool get --path $(XCRESULT) \
++ --id $$( \
++ xcrun xcresulttool get --path $(XCRESULT) --format json | \
++ $(PYTHON_FOR_BUILD) -c "import sys, json; result = json.load(sys.stdin); print(result['actions']['_values'][0]['actionResult']['logRef']['id']['_value'])" \
++ ) \
++ --format json | \
++ $(PYTHON_FOR_BUILD) -c "import sys, json; result = json.load(sys.stdin); print(result['subsections']['_values'][1]['subsections']['_values'][0]['emittedOutput']['_value'])"
++
++ @if test -e $(XCFOLDER)/failed ; then \
++ exit 1; \
++ fi
++
+ # Like testall, but with only one pass and without multiple processes.
+ # Run an optional script to include information about the build environment.
+ .PHONY: buildbottest
+@@ -1900,7 +1983,7 @@
+ # which can lead to two parallel `./python setup.py build` processes that
+ # step on each others toes.
+ .PHONY: install
+-install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@
++install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@
+ if test "x$(ENSUREPIP)" != "xno" ; then \
+ case $(ENSUREPIP) in \
+ upgrade) ensurepip="--upgrade" ;; \
+@@ -2328,6 +2411,14 @@
+ $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \
+ $(DESTDIR)$(LIBDEST); \
+ $(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
++ @ # If app store compliance has been configured, apply the patch to the
++ @ # installed library code. The patch has been previously validated against
++ @ # the original source tree, so we can ignore any errors that are raised
++ @ # due to files that are missing because of --disable-test-modules etc.
++ @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \
++ echo "Applying app store compliance patch"; \
++ patch --force --reject-file "$(abs_builddir)/app-store-compliance.rej" --strip 2 --directory "$(DESTDIR)$(LIBDEST)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)" || true ; \
++ fi
+ @ # Build PYC files for the 3 optimization levels (0, 1, 2)
+ -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
+ $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \
+@@ -2504,10 +2595,11 @@
+ # only have to cater for the structural bits of the framework.
+
+ .PHONY: frameworkinstallframework
+-frameworkinstallframework: frameworkinstallstructure install frameworkinstallmaclib
++frameworkinstallframework: @FRAMEWORKINSTALLFIRST@ install frameworkinstallmaclib
+
+-.PHONY: frameworkinstallstructure
+-frameworkinstallstructure: $(LDLIBRARY)
++# macOS uses a versioned frameworks structure that includes a full install
++.PHONY: frameworkinstallversionedstructure
++frameworkinstallversionedstructure: $(LDLIBRARY)
+ @if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \
+ echo Not configured with --enable-framework; \
+ exit 1; \
+@@ -2528,6 +2620,27 @@
+ $(LN) -fsn Versions/Current/Resources $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Resources
+ $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY)
+
++# iOS/tvOS/watchOS uses a non-versioned framework with Info.plist in the
++# framework root, no .lproj data, and only stub compilation assistance binaries
++.PHONY: frameworkinstallunversionedstructure
++frameworkinstallunversionedstructure: $(LDLIBRARY)
++ @if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \
++ echo Not configured with --enable-framework; \
++ exit 1; \
++ else true; \
++ fi
++ if test -d $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; then \
++ echo "Clearing stale header symlink directory"; \
++ rm -rf $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; \
++ fi
++ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)
++ sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Info.plist
++ $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY)
++ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(BINDIR)
++ for file in $(srcdir)/$(RESSRCDIR)/bin/* ; do \
++ $(INSTALL) -m $(EXEMODE) $$file $(DESTDIR)$(BINDIR); \
++ done
++
+ # This installs Mac/Lib into the framework
+ # Install a number of symlinks to keep software that expects a normal unix
+ # install (which includes python-config) happy.
+@@ -2568,6 +2681,19 @@
+ frameworkinstallextras:
+ cd Mac && $(MAKE) installextras DESTDIR="$(DESTDIR)"
+
++# On iOS, bin/lib can't live inside the framework; include needs to be called
++# "Headers", but *must* be in the framework, and *not* include the `python3.X`
++# subdirectory. The install has put these folders in the same folder as
++# Python.framework; Move the headers to their final framework-compatible home.
++.PHONY: frameworkinstallmobileheaders
++frameworkinstallmobileheaders: frameworkinstallunversionedstructure inclinstall
++ if test -d $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; then \
++ echo "Removing old framework headers"; \
++ rm -rf $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; \
++ fi
++ mv "$(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include/python$(LDVERSION)" "$(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers"
++ $(LN) -fs "../$(PYTHONFRAMEWORKDIR)/Headers" "$(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include/python$(LDVERSION)"
++
+ # Build the toplevel Makefile
+ Makefile.pre: $(srcdir)/Makefile.pre.in config.status
+ CONFIG_FILES=Makefile.pre CONFIG_HEADERS= ./config.status
+@@ -2678,6 +2804,10 @@
+ -find build -type f -a ! -name '*.gc??' -exec rm -f {} ';'
+ -rm -f Include/pydtrace_probes.h
+ -rm -f profile-gen-stamp
++ -rm -rf iOS/testbed/Python.xcframework/ios-*/bin
++ -rm -rf iOS/testbed/Python.xcframework/ios-*/lib
++ -rm -rf iOS/testbed/Python.xcframework/ios-*/include
++ -rm -rf iOS/testbed/Python.xcframework/ios-*/Python.framework
+
+ .PHONY: profile-removal
+ profile-removal:
+@@ -2703,6 +2833,8 @@
+ config.cache config.log pyconfig.h Modules/config.c
+ -rm -rf build platform
+ -rm -rf $(PYTHONFRAMEWORKDIR)
++ -rm -rf iOS/Frameworks
++ -rm -rf iOSTestbed.*
+ -rm -f python-config.py python-config
+
+ # Make things extra clean, before making a distribution:
+diff --git a/Modules/getpath.c b/Modules/getpath.c
+index 0a310000751..83a2bc469ae 100644
+--- a/Modules/getpath.c
++++ b/Modules/getpath.c
+@@ -15,6 +15,7 @@
+ #endif
+
+ #ifdef __APPLE__
++# include "TargetConditionals.h"
+ # include
+ #endif
+
+@@ -759,7 +760,7 @@
+ return winmodule_to_dict(dict, key, PyWin_DLLhModule);
+ }
+ #endif
+-#elif defined(WITH_NEXT_FRAMEWORK)
++#elif defined(WITH_NEXT_FRAMEWORK) && !defined(TARGET_OS_IPHONE)
+ static char modPath[MAXPATHLEN + 1];
+ static int modPathInitialized = -1;
+ if (modPathInitialized < 0) {
+@@ -953,4 +954,3 @@
+
+ return _PyStatus_OK();
+ }
+-
+diff --git a/Python/marshal.c b/Python/marshal.c
+index 90953cbb728..be858033249 100644
+--- a/Python/marshal.c
++++ b/Python/marshal.c
+@@ -15,6 +15,10 @@
+ #include "pycore_hashtable.h" // _Py_hashtable_t
+ #include "marshal.h" // Py_MARSHAL_VERSION
+
++#ifdef __APPLE__
++# include "TargetConditionals.h"
++#endif /* __APPLE__ */
++
+ /*[clinic input]
+ module marshal
+ [clinic start generated code]*/
+@@ -34,11 +38,14 @@
+ * #if defined(MS_WINDOWS) && defined(_DEBUG)
+ */
+ #if defined(MS_WINDOWS)
+-#define MAX_MARSHAL_STACK_DEPTH 1000
++# define MAX_MARSHAL_STACK_DEPTH 1000
+ #elif defined(__wasi__)
+-#define MAX_MARSHAL_STACK_DEPTH 1500
++# define MAX_MARSHAL_STACK_DEPTH 1500
++// TARGET_OS_IPHONE covers any non-macOS Apple platform.
++#elif defined(__APPLE__) && TARGET_OS_IPHONE
++# define MAX_MARSHAL_STACK_DEPTH 1500
+ #else
+-#define MAX_MARSHAL_STACK_DEPTH 2000
++# define MAX_MARSHAL_STACK_DEPTH 2000
+ #endif
+
+ #define TYPE_NULL '0'
+diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h
+index ed4a0ac2dd3..bc8da328ba9 100644
+--- a/Python/stdlib_module_names.h
++++ b/Python/stdlib_module_names.h
+@@ -39,6 +39,7 @@
+ "_heapq",
+ "_imp",
+ "_io",
++"_ios_support",
+ "_json",
+ "_locale",
+ "_lsprof",
+diff --git a/config.sub b/config.sub
+index d74fb6deac9..1bb6a05dc11 100755
+--- a/config.sub
++++ b/config.sub
+@@ -1,14 +1,15 @@
+ #! /bin/sh
+ # Configuration validation subroutine script.
+-# Copyright 1992-2021 Free Software Foundation, Inc.
++# Copyright 1992-2024 Free Software Foundation, Inc.
+
+ # shellcheck disable=SC2006,SC2268 # see below for rationale
+
+-timestamp='2021-08-14'
++# Patched 2024-02-03 to include support for arm64_32 and iOS/tvOS/watchOS simulators
++timestamp='2024-01-01'
+
+ # This file is free software; you can redistribute it and/or modify it
+ # under the terms of the GNU General Public License as published by
+-# the Free Software Foundation; either version 3 of the License, or
++# the Free Software Foundation, either version 3 of the License, or
+ # (at your option) any later version.
+ #
+ # This program is distributed in the hope that it will be useful, but
+@@ -76,13 +77,13 @@
+ version="\
+ GNU config.sub ($timestamp)
+
+-Copyright 1992-2021 Free Software Foundation, Inc.
++Copyright 1992-2024 Free Software Foundation, Inc.
+
+ This is free software; see the source for copying conditions. There is NO
+ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+ help="
+-Try \`$me --help' for more information."
++Try '$me --help' for more information."
+
+ # Parse command line
+ while test $# -gt 0 ; do
+@@ -130,7 +131,7 @@
+ # Separate into logical components for further validation
+ case $1 in
+ *-*-*-*-*)
+- echo Invalid configuration \`"$1"\': more than four components >&2
++ echo "Invalid configuration '$1': more than four components" >&2
+ exit 1
+ ;;
+ *-*-*-*)
+@@ -145,7 +146,8 @@
+ nto-qnx* | linux-* | uclinux-uclibc* \
+ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+- | storm-chaos* | os2-emx* | rtmk-nova*)
++ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \
++ | windows-* )
+ basic_machine=$field1
+ basic_os=$maybe_os
+ ;;
+@@ -943,7 +945,7 @@
+ EOF
+ IFS=$saved_IFS
+ ;;
+- # We use `pc' rather than `unknown'
++ # We use 'pc' rather than 'unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+@@ -1020,6 +1022,11 @@
+ ;;
+
+ # Here we normalize CPU types with a missing or matching vendor
++ armh-unknown | armh-alt)
++ cpu=armv7l
++ vendor=alt
++ basic_os=${basic_os:-linux-gnueabihf}
++ ;;
+ dpx20-unknown | dpx20-bull)
+ cpu=rs6000
+ vendor=bull
+@@ -1070,7 +1077,7 @@
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ cpu=i586
+ ;;
+- pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
++ pentiumpro-* | p6-* | 6x86-* | athlon-* | athlon_*-*)
+ cpu=i686
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+@@ -1121,7 +1128,7 @@
+ xscale-* | xscalee[bl]-*)
+ cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
+ ;;
+- arm64-*)
++ arm64-* | aarch64le-* | arm64_32-*)
+ cpu=aarch64
+ ;;
+
+@@ -1175,7 +1182,7 @@
+ case $cpu in
+ 1750a | 580 \
+ | a29k \
+- | aarch64 | aarch64_be \
++ | aarch64 | aarch64_be | aarch64c | arm64ec \
+ | abacus \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+@@ -1194,50 +1201,29 @@
+ | d10v | d30v | dlx | dsp16xx \
+ | e2k | elxsi | epiphany \
+ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
++ | javascript \
+ | h8300 | h8500 \
+ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i*86 | i860 | i960 | ia16 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
++ | kvx \
+ | le32 | le64 \
+ | lm32 \
+- | loongarch32 | loongarch64 | loongarchx32 \
++ | loongarch32 | loongarch64 \
+ | m32c | m32r | m32rle \
+ | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+ | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+ | m88110 | m88k | maxq | mb | mcore | mep | metag \
+ | microblaze | microblazeel \
+- | mips | mipsbe | mipseb | mipsel | mipsle \
+- | mips16 \
+- | mips64 | mips64eb | mips64el \
+- | mips64octeon | mips64octeonel \
+- | mips64orion | mips64orionel \
+- | mips64r5900 | mips64r5900el \
+- | mips64vr | mips64vrel \
+- | mips64vr4100 | mips64vr4100el \
+- | mips64vr4300 | mips64vr4300el \
+- | mips64vr5000 | mips64vr5000el \
+- | mips64vr5900 | mips64vr5900el \
+- | mipsisa32 | mipsisa32el \
+- | mipsisa32r2 | mipsisa32r2el \
+- | mipsisa32r3 | mipsisa32r3el \
+- | mipsisa32r5 | mipsisa32r5el \
+- | mipsisa32r6 | mipsisa32r6el \
+- | mipsisa64 | mipsisa64el \
+- | mipsisa64r2 | mipsisa64r2el \
+- | mipsisa64r3 | mipsisa64r3el \
+- | mipsisa64r5 | mipsisa64r5el \
+- | mipsisa64r6 | mipsisa64r6el \
+- | mipsisa64sb1 | mipsisa64sb1el \
+- | mipsisa64sr71k | mipsisa64sr71kel \
+- | mipsr5900 | mipsr5900el \
+- | mipstx39 | mipstx39el \
++ | mips* \
+ | mmix \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
++ | nanomips* \
+ | nds32 | nds32le | nds32be \
+ | nfp \
+ | nios | nios2 | nios2eb | nios2el \
+@@ -1269,6 +1255,7 @@
+ | ubicom32 \
+ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+ | vax \
++ | vc4 \
+ | visium \
+ | w65 \
+ | wasm32 | wasm64 \
+@@ -1280,7 +1267,7 @@
+ ;;
+
+ *)
+- echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
++ echo "Invalid configuration '$1': machine '$cpu-$vendor' not recognized" 1>&2
+ exit 1
+ ;;
+ esac
+@@ -1301,11 +1288,12 @@
+
+ # Decode manufacturer-specific aliases for certain operating systems.
+
+-if test x$basic_os != x
++if test x"$basic_os" != x
+ then
+
+-# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
++# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just
+ # set os.
++obj=
+ case $basic_os in
+ gnu/linux*)
+ kernel=linux
+@@ -1336,6 +1324,10 @@
+ kernel=linux
+ os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+ ;;
++ managarm*)
++ kernel=managarm
++ os=`echo "$basic_os" | sed -e 's|managarm|mlibc|'`
++ ;;
+ *)
+ kernel=
+ os=$basic_os
+@@ -1501,10 +1493,16 @@
+ os=eabi
+ ;;
+ *)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ esac
+ ;;
++ aout* | coff* | elf* | pe*)
++ # These are machine code file formats, not OSes
++ obj=$os
++ os=
++ ;;
+ *)
+ # No normalization, but not necessarily accepted, that comes below.
+ ;;
+@@ -1523,12 +1521,15 @@
+ # system, and we'll never get to this point.
+
+ kernel=
++obj=
+ case $cpu-$vendor in
+ score-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ spu-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ *-acorn)
+ os=riscix1.2
+@@ -1538,28 +1539,35 @@
+ os=gnu
+ ;;
+ arm*-semi)
+- os=aout
++ os=
++ obj=aout
+ ;;
+ c4x-* | tic4x-*)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ c8051-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ clipper-intergraph)
+ os=clix
+ ;;
+ hexagon-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ tic54x-*)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ tic55x-*)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ tic6x-*)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+@@ -1581,19 +1589,24 @@
+ os=sunos3
+ ;;
+ m68*-cisco)
+- os=aout
++ os=
++ obj=aout
+ ;;
+ mep-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ mips*-cisco)
+- os=elf
++ os=
++ obj=elf
+ ;;
+- mips*-*)
+- os=elf
++ mips*-*|nanomips*-*)
++ os=
++ obj=elf
+ ;;
+ or32-*)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=sysv3
+@@ -1602,7 +1615,8 @@
+ os=sunos4.1.1
+ ;;
+ pru-*)
+- os=elf
++ os=
++ obj=elf
+ ;;
+ *-be)
+ os=beos
+@@ -1683,10 +1697,12 @@
+ os=uxpv
+ ;;
+ *-rom68k)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ *-*bug)
+- os=coff
++ os=
++ obj=coff
+ ;;
+ *-apple)
+ os=macos
+@@ -1704,10 +1720,11 @@
+
+ fi
+
+-# Now, validate our (potentially fixed-up) OS.
++# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ).
++
+ case $os in
+ # Sometimes we do "kernel-libc", so those need to count as OSes.
+- musl* | newlib* | relibc* | uclibc*)
++ llvm* | musl* | newlib* | relibc* | uclibc*)
+ ;;
+ # Likewise for "kernel-abi"
+ eabi* | gnueabi*)
+@@ -1715,6 +1732,9 @@
+ # VxWorks passes extra cpu info in the 4th filed.
+ simlinux | simwindows | spe)
+ ;;
++ # See `case $cpu-$os` validation below
++ ghcjs)
++ ;;
+ # Now accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST end in a * to match a version number.
+@@ -1723,7 +1743,7 @@
+ | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+ | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \
+ | hiux* | abug | nacl* | netware* | windows* \
+- | os9* | macos* | osx* | ios* \
++ | os9* | macos* | osx* | ios* | tvos* | watchos* \
+ | mpw* | magic* | mmixware* | mon960* | lnews* \
+ | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+ | aos* | aros* | cloudabi* | sortix* | twizzler* \
+@@ -1732,11 +1752,11 @@
+ | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+ | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
+ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+- | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+- | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
++ | bosx* | nextstep* | cxux* | oabi* \
++ | ptx* | ecoff* | winnt* | domain* | vsta* \
+ | udi* | lites* | ieee* | go32* | aux* | hcos* \
+ | chorusrdb* | cegcc* | glidix* | serenity* \
+- | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
++ | cygwin* | msys* | moss* | proelf* | rtems* \
+ | midipix* | mingw32* | mingw64* | mint* \
+ | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+ | interix* | uwin* | mks* | rhapsody* | darwin* \
+@@ -1748,49 +1768,119 @@
+ | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+ | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+- | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr*)
++ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \
++ | fiwix* | mlibc* | cos* | mbr* | ironclad* )
+ ;;
+ # This one is extra strict with allowed versions
+ sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ ;;
++ # This refers to builds using the UEFI calling convention
++ # (which depends on the architecture) and PE file format.
++ # Note that this is both a different calling convention and
++ # different file format than that of GNU-EFI
++ # (x86_64-w64-mingw32).
++ uefi)
++ ;;
+ none)
+ ;;
++ kernel* | msvc* )
++ # Restricted further below
++ ;;
++ '')
++ if test x"$obj" = x
++ then
++ echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2
++ fi
++ ;;
+ *)
+- echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
++ echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2
++ exit 1
++ ;;
++esac
++
++case $obj in
++ aout* | coff* | elf* | pe*)
++ ;;
++ '')
++ # empty is fine
++ ;;
++ *)
++ echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2
++ exit 1
++ ;;
++esac
++
++# Here we handle the constraint that a (synthetic) cpu and os are
++# valid only in combination with each other and nowhere else.
++case $cpu-$os in
++ # The "javascript-unknown-ghcjs" triple is used by GHC; we
++ # accept it here in order to tolerate that, but reject any
++ # variations.
++ javascript-ghcjs)
++ ;;
++ javascript-* | *-ghcjs)
++ echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # As a final step for OS-related things, validate the OS-kernel combination
+ # (given a valid OS), if there is a kernel.
+-case $kernel-$os in
+- linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \
+- | linux-musl* | linux-relibc* | linux-uclibc* )
++case $kernel-$os-$obj in
++ linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \
++ | linux-mlibc*- | linux-musl*- | linux-newlib*- \
++ | linux-relibc*- | linux-uclibc*- )
++ ;;
++ uclinux-uclibc*- )
+ ;;
+- uclinux-uclibc* )
++ managarm-mlibc*- | managarm-kernel*- )
+ ;;
+- -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* )
++ windows*-msvc*-)
++ ;;
++ -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \
++ | -uclibc*- )
+ # These are just libc implementations, not actual OSes, and thus
+ # require a kernel.
+- echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
++ echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2
+ exit 1
+ ;;
+- kfreebsd*-gnu* | kopensolaris*-gnu*)
++ -kernel*- )
++ echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2
++ exit 1
+ ;;
+- vxworks-simlinux | vxworks-simwindows | vxworks-spe)
++ *-kernel*- )
++ echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2
++ exit 1
+ ;;
+- nto-qnx*)
++ *-msvc*- )
++ echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2
++ exit 1
+ ;;
+- os2-emx)
++ kfreebsd*-gnu*- | kopensolaris*-gnu*-)
+ ;;
+- *-eabi* | *-gnueabi*)
++ vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-)
+ ;;
+- -*)
++ nto-qnx*-)
++ ;;
++ os2-emx-)
++ ;;
++ *-eabi*- | *-gnueabi*-)
++ ;;
++ ios*-simulator- | tvos*-simulator- | watchos*-simulator- )
++ ;;
++ none--*)
++ # None (no kernel, i.e. freestanding / bare metal),
++ # can be paired with an machine code file format
++ ;;
++ -*-)
+ # Blank kernel with real OS is always fine.
+ ;;
+- *-*)
+- echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
++ --*)
++ # Blank kernel and OS with real machine code file format is always fine.
++ ;;
++ *-*-*)
++ echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2
+ exit 1
+ ;;
+ esac
+@@ -1873,7 +1963,7 @@
+ ;;
+ esac
+
+-echo "$cpu-$vendor-${kernel:+$kernel-}$os"
++echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}"
+ exit
+
+ # Local variables:
+diff --git a/configure b/configure
+index 6dc8a66e487..50e1e7979e2 100755
+--- a/configure
++++ b/configure
+@@ -975,10 +975,14 @@
+ CFLAGS
+ CC
+ HAS_XCRUN
++WATCHOS_DEPLOYMENT_TARGET
++TVOS_DEPLOYMENT_TARGET
++IPHONEOS_DEPLOYMENT_TARGET
+ EXPORT_MACOSX_DEPLOYMENT_TARGET
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET
+ _PYTHON_HOST_PLATFORM
+-MACHDEP
++APP_STORE_COMPLIANCE_PATCH
++INSTALLTARGETS
+ FRAMEWORKINSTALLAPPSPREFIX
+ FRAMEWORKUNIXTOOLSPREFIX
+ FRAMEWORKPYTHONW
+@@ -986,6 +990,8 @@
+ FRAMEWORKALTINSTALLFIRST
+ FRAMEWORKINSTALLLAST
+ FRAMEWORKINSTALLFIRST
++RESSRCDIR
++PYTHONFRAMEWORKINSTALLNAMEPREFIX
+ PYTHONFRAMEWORKINSTALLDIR
+ PYTHONFRAMEWORKPREFIX
+ PYTHONFRAMEWORKDIR
+@@ -995,6 +1001,7 @@
+ LIPO_32BIT_FLAGS
+ ARCH_RUN_32BIT
+ UNIVERSALSDK
++MACHDEP
+ PKG_CONFIG_LIBDIR
+ PKG_CONFIG_PATH
+ PKG_CONFIG
+@@ -1070,6 +1077,7 @@
+ with_universal_archs
+ with_framework_name
+ enable_framework
++with_app_store_compliance
+ with_emscripten_target
+ enable_wasm_dynamic_linking
+ enable_wasm_pthreads
+@@ -1843,6 +1851,10 @@
+ specify the name for the python framework on macOS
+ only valid when --enable-framework is set. see
+ Mac/README.rst (default is 'Python')
++ --with-app-store-compliance=[PATCH-FILE]
++ Enable any patches required for compiliance with app
++ stores. Optional PATCH-FILE specifies the custom
++ patch to apply.
+ --with-emscripten-target=[browser|node]
+ Emscripten platform
+ --with-suffix=SUFFIX set executable suffix to SUFFIX (default is empty,
+@@ -4011,6 +4023,164 @@
+ as_fn_error $? "pkg-config is required" "$LINENO" 5]
+ fi
+
++# Set name for machine-dependent library files
++
++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5
++printf %s "checking MACHDEP... " >&6; }
++if test -z "$MACHDEP"
++then
++ # avoid using uname for cross builds
++ if test "$cross_compiling" = yes; then
++ # ac_sys_system and ac_sys_release are used for setting
++ # a lot of different things including 'define_xopen_source'
++ # in the case statement below.
++ case "$host" in
++ *-*-linux-android*)
++ ac_sys_system=Linux-android
++ ;;
++ *-*-linux*)
++ ac_sys_system=Linux
++ ;;
++ *-*-cygwin*)
++ ac_sys_system=Cygwin
++ ;;
++ *-apple-ios*)
++ ac_sys_system=iOS
++ ;;
++ *-apple-tvos*)
++ ac_sys_system=tvOS
++ ;;
++ *-apple-watchos*)
++ ac_sys_system=watchOS
++ ;;
++ *-*-vxworks*)
++ ac_sys_system=VxWorks
++ ;;
++ *-*-emscripten)
++ ac_sys_system=Emscripten
++ ;;
++ *-*-wasi)
++ ac_sys_system=WASI
++ ;;
++ *)
++ # for now, limit cross builds to known configurations
++ MACHDEP="unknown"
++ as_fn_error $? "cross build not supported for $host" "$LINENO" 5
++ esac
++ ac_sys_release=
++ else
++ ac_sys_system=`uname -s`
++ if test "$ac_sys_system" = "AIX" \
++ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
++ ac_sys_release=`uname -v`
++ else
++ ac_sys_release=`uname -r`
++ fi
++ fi
++ ac_md_system=`echo $ac_sys_system |
++ tr -d '/ ' | tr '[A-Z]' '[a-z]'`
++ ac_md_release=`echo $ac_sys_release |
++ tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'`
++ MACHDEP="$ac_md_system$ac_md_release"
++
++ case $MACHDEP in
++ aix*) MACHDEP="aix";;
++ linux*) MACHDEP="linux";;
++ cygwin*) MACHDEP="cygwin";;
++ darwin*) MACHDEP="darwin";;
++ '') MACHDEP="unknown";;
++ esac
++
++ if test "$ac_sys_system" = "SunOS"; then
++ # For Solaris, there isn't an OS version specific macro defined
++ # in most compilers, so we define one here.
++ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'`
++
++printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h
++
++ fi
++fi
++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5
++printf "%s\n" "\"$MACHDEP\"" >&6; }
++
++# On cross-compile builds, configure will look for a host-specific compiler by
++# prepending the user-provided host triple to the required binary name.
++#
++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
++# which isn't a binary that exists, and isn't very convenient, as it contains the
++# iOS version. As the default cross-compiler name won't exist, configure falls
++# back to gcc, which *definitely* won't work. We're providing wrapper scripts for
++# these tools; the binary names of these scripts are better defaults than "gcc".
++# This only requires that the user put the platform scripts folder (e.g.,
++# "iOS/Resources/bin") in their path, rather than defining platform-specific
++# names/paths for AR, CC, CPP, and CXX explicitly; and if the user forgets to
++# either put the platform scripts folder in the path, or specify CC etc,
++# configure will fail.
++if test -z "$AR"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;;
++ aarch64-apple-ios*) AR=arm64-apple-ios-ar ;;
++ x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;;
++
++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;;
++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;;
++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;;
++
++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;;
++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;;
++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;;
++ *)
++ esac
++fi
++if test -z "$CC"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;;
++ aarch64-apple-ios*) CC=arm64-apple-ios-clang ;;
++ x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;;
++ *)
++ esac
++fi
++if test -z "$CPP"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;;
++ aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;;
++ x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;;
++
++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;;
++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;;
++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;;
++
++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;;
++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;;
++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;;
++ *)
++ esac
++fi
++if test -z "$CXX"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang ;;
++ aarch64-apple-ios*) CXX=arm64-apple-ios-clang ;;
++ x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang ;;
++ *)
++ esac
++fi
++
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-universalsdk" >&5
+ printf %s "checking for --enable-universalsdk... " >&6; }
+ # Check whether --enable-universalsdk was given.
+@@ -4126,111 +4296,195 @@
+ enableval=$enable_framework;
+ case $enableval in
+ yes)
+- enableval=/Library/Frameworks
++ case $ac_sys_system in
++ Darwin) enableval=/Library/Frameworks ;;
++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;;
++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;;
++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;;
++ *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5
++ esac
+ esac
++
+ case $enableval in
+ no)
+- PYTHONFRAMEWORK=
+- PYTHONFRAMEWORKDIR=no-framework
+- PYTHONFRAMEWORKPREFIX=
+- PYTHONFRAMEWORKINSTALLDIR=
+- FRAMEWORKINSTALLFIRST=
+- FRAMEWORKINSTALLLAST=
+- FRAMEWORKALTINSTALLFIRST=
+- FRAMEWORKALTINSTALLLAST=
+- FRAMEWORKPYTHONW=
+- if test "x${prefix}" = "xNONE"; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+- enable_framework=
++ case $ac_sys_system in
++ iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;;
++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;;
++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;;
++ *)
++ PYTHONFRAMEWORK=
++ PYTHONFRAMEWORKDIR=no-framework
++ PYTHONFRAMEWORKPREFIX=
++ PYTHONFRAMEWORKINSTALLDIR=
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=
++ RESSRCDIR=
++ FRAMEWORKINSTALLFIRST=
++ FRAMEWORKINSTALLLAST=
++ FRAMEWORKALTINSTALLFIRST=
++ FRAMEWORKALTINSTALLLAST=
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++
++ if test "x${prefix}" = "xNONE"; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
++ enable_framework=
++ esac
+ ;;
+ *)
+ PYTHONFRAMEWORKPREFIX="${enableval}"
+ PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR
+- FRAMEWORKINSTALLFIRST="frameworkinstallstructure"
+- FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure "
+- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
+- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
+- FRAMEWORKPYTHONW="frameworkpythonw"
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+-
+- if test "x${prefix}" = "xNONE" ; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+-
+- case "${enableval}" in
+- /System*)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- if test "${prefix}" = "NONE" ; then
+- # See below
+- FRAMEWORKUNIXTOOLSPREFIX="/usr"
+- fi
+- ;;
++ case $ac_sys_system in #(
++ Darwin) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
++ FRAMEWORKPYTHONW="frameworkpythonw"
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++
++ if test "x${prefix}" = "xNONE" ; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
+
+- /Library*)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- ;;
++ case "${enableval}" in
++ /System*)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ if test "${prefix}" = "NONE" ; then
++ # See below
++ FRAMEWORKUNIXTOOLSPREFIX="/usr"
++ fi
++ ;;
++
++ /Library*)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ ;;
++
++ */Library/Frameworks)
++ MDIR="`dirname "${enableval}"`"
++ MDIR="`dirname "${MDIR}"`"
++ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications"
++
++ if test "${prefix}" = "NONE"; then
++ # User hasn't specified the
++ # --prefix option, but wants to install
++ # the framework in a non-default location,
++ # ensure that the compatibility links get
++ # installed relative to that prefix as well
++ # instead of in /usr/local.
++ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}"
++ fi
++ ;;
+
+- */Library/Frameworks)
+- MDIR="`dirname "${enableval}"`"
+- MDIR="`dirname "${MDIR}"`"
+- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications"
+-
+- if test "${prefix}" = "NONE"; then
+- # User hasn't specified the
+- # --prefix option, but wants to install
+- # the framework in a non-default location,
+- # ensure that the compatibility links get
+- # installed relative to that prefix as well
+- # instead of in /usr/local.
+- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}"
+- fi
+- ;;
++ *)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ ;;
++ esac
+
+- *)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- ;;
++ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix}
++ RESSRCDIR=Mac/Resources/framework
++
++ # Add files for Mac specific code to the list of output
++ # files:
++ ac_config_files="$ac_config_files Mac/Makefile"
++
++ ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile"
++
++ ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist"
++
++ ac_config_files="$ac_config_files Mac/Resources/app/Info.plist"
++
++ ;;
++ iOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=iOS/Resources
++
++ ac_config_files="$ac_config_files iOS/Resources/Info.plist"
++
++ ;;
++ tvOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=tvOS/Resources
++
++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist"
++
++ ;;
++ watchOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=watchOS/Resources
++
++ ac_config_files="$ac_config_files watchOS/Resources/Info.plist"
++
++ ;;
++ *)
++ as_fn_error $? "Unknown platform for framework build" "$LINENO" 5
++ ;;
++ esac
+ esac
+
+- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION
+-
+- # Add files for Mac specific code to the list of output
+- # files:
+- ac_config_files="$ac_config_files Mac/Makefile"
+-
+- ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile"
+-
+- ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist"
+-
+- ac_config_files="$ac_config_files Mac/Resources/app/Info.plist"
++else $as_nop
+
++ case $ac_sys_system in
++ iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;;
++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;;
++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;;
++ *)
++ PYTHONFRAMEWORK=
++ PYTHONFRAMEWORKDIR=no-framework
++ PYTHONFRAMEWORKPREFIX=
++ PYTHONFRAMEWORKINSTALLDIR=
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=
++ RESSRCDIR=
++ FRAMEWORKINSTALLFIRST=
++ FRAMEWORKINSTALLLAST=
++ FRAMEWORKALTINSTALLFIRST=
++ FRAMEWORKALTINSTALLLAST=
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++ if test "x${prefix}" = "xNONE" ; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
++ enable_framework=
+ esac
+
+-else $as_nop
++fi
+
+- PYTHONFRAMEWORK=
+- PYTHONFRAMEWORKDIR=no-framework
+- PYTHONFRAMEWORKPREFIX=
+- PYTHONFRAMEWORKINSTALLDIR=
+- FRAMEWORKINSTALLFIRST=
+- FRAMEWORKINSTALLLAST=
+- FRAMEWORKALTINSTALLFIRST=
+- FRAMEWORKALTINSTALLLAST=
+- FRAMEWORKPYTHONW=
+- if test "x${prefix}" = "xNONE" ; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+- enable_framework=
+
+
+-fi
+
+
+
+@@ -4249,76 +4503,52 @@
+ printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h
+
+
+-# Set name for machine-dependent library files
+-
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5
+-printf %s "checking MACHDEP... " >&6; }
+-if test -z "$MACHDEP"
+-then
+- # avoid using uname for cross builds
+- if test "$cross_compiling" = yes; then
+- # ac_sys_system and ac_sys_release are used for setting
+- # a lot of different things including 'define_xopen_source'
+- # in the case statement below.
+- case "$host" in
+- *-*-linux-android*)
+- ac_sys_system=Linux-android
+- ;;
+- *-*-linux*)
+- ac_sys_system=Linux
+- ;;
+- *-*-cygwin*)
+- ac_sys_system=Cygwin
+- ;;
+- *-*-vxworks*)
+- ac_sys_system=VxWorks
+- ;;
+- *-*-emscripten)
+- ac_sys_system=Emscripten
+- ;;
+- *-*-wasi)
+- ac_sys_system=WASI
+- ;;
+- *)
+- # for now, limit cross builds to known configurations
+- MACHDEP="unknown"
+- as_fn_error $? "cross build not supported for $host" "$LINENO" 5
+- esac
+- ac_sys_release=
+- else
+- ac_sys_system=`uname -s`
+- if test "$ac_sys_system" = "AIX" \
+- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
+- ac_sys_release=`uname -v`
+- else
+- ac_sys_release=`uname -r`
+- fi
+- fi
+- ac_md_system=`echo $ac_sys_system |
+- tr -d '/ ' | tr '[A-Z]' '[a-z]'`
+- ac_md_release=`echo $ac_sys_release |
+- tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'`
+- MACHDEP="$ac_md_system$ac_md_release"
++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-app-store-compliance" >&5
++printf %s "checking for --with-app-store-compliance... " >&6; }
+
+- case $MACHDEP in
+- aix*) MACHDEP="aix";;
+- linux*) MACHDEP="linux";;
+- cygwin*) MACHDEP="cygwin";;
+- darwin*) MACHDEP="darwin";;
+- '') MACHDEP="unknown";;
++# Check whether --with-app_store_compliance was given.
++if test ${with_app_store_compliance+y}
++then :
++ withval=$with_app_store_compliance;
++ case "$withval" in
++ yes)
++ case $ac_sys_system in
++ Darwin|iOS|tvOS|watchOS)
++ # iOS/tvOS/watchOS is able to share the macOS patch
++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
++ ;;
++ *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;;
++ esac
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5
++printf "%s\n" "applying default app store compliance patch" >&6; }
++ ;;
++ *)
++ APP_STORE_COMPLIANCE_PATCH="${withval}"
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying custom app store compliance patch" >&5
++printf "%s\n" "applying custom app store compliance patch" >&6; }
++ ;;
+ esac
+
+- if test "$ac_sys_system" = "SunOS"; then
+- # For Solaris, there isn't an OS version specific macro defined
+- # in most compilers, so we define one here.
+- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'`
++else $as_nop
+
+-printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h
++ case $ac_sys_system in
++ iOS|tvOS|watchOS)
++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch
++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5
++printf "%s\n" "applying default app store compliance patch" >&6; }
++ ;;
++ *)
++ # No default app compliance patching on any other platform
++ APP_STORE_COMPLIANCE_PATCH=
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not patching for app store compliance" >&5
++printf "%s\n" "not patching for app store compliance" >&6; }
++ ;;
++ esac
+
+- fi
+ fi
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5
+-printf "%s\n" "\"$MACHDEP\"" >&6; }
++
++
+
+
+ if test "$cross_compiling" = yes; then
+@@ -4326,27 +4556,93 @@
+ *-*-linux*)
+ case "$host_cpu" in
+ arm*)
+- _host_cpu=arm
++ _host_ident=arm
+ ;;
+ *)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ esac
+ ;;
+ *-*-cygwin*)
+- _host_cpu=
++ _host_ident=
++ ;;
++ *-apple-ios*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # IPHONEOS_DEPLOYMENT_TARGET is the minimum supported iOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking iOS deployment target" >&5
++printf %s "checking iOS deployment target... " >&6; }
++ IPHONEOS_DEPLOYMENT_TARGET=${_host_os:3}
++ IPHONEOS_DEPLOYMENT_TARGET=${IPHONEOS_DEPLOYMENT_TARGET:=13.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $IPHONEOS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$IPHONEOS_DEPLOYMENT_TARGET" >&6; }
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${IPHONEOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device}
++ ;;
++ *)
++ _host_ident=${IPHONEOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-tvos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5
++printf %s "checking tvOS deployment target... " >&6; }
++ TVOS_DEPLOYMENT_TARGET=${_host_os:4}
++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; }
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device}
++ ;;
++ *)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-watchos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5
++printf %s "checking watchOS deployment target... " >&6; }
++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7}
++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; }
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device}
++ ;;
++ *)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device}
++ ;;
++ esac
+ ;;
+ *-*-vxworks*)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ ;;
+ wasm32-*-* | wasm64-*-*)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ ;;
+ *)
+ # for now, limit cross builds to known configurations
+ MACHDEP="unknown"
+ as_fn_error $? "cross build not supported for $host" "$LINENO" 5
+ esac
+- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}"
++ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}"
+ fi
+
+ # Some systems cannot stand _XOPEN_SOURCE being defined at all; they
+@@ -4413,6 +4709,13 @@
+ define_xopen_source=no;;
+ Darwin/[12][0-9].*)
+ define_xopen_source=no;;
++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features.
++ iOS/*)
++ define_xopen_source=no;;
++ tvOS/*)
++ define_xopen_source=no;;
++ watchOS/*)
++ define_xopen_source=no;;
+ # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
+ # defining NI_NUMERICHOST.
+ QNX/6.3.2)
+@@ -4475,6 +4778,12 @@
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET=
+ EXPORT_MACOSX_DEPLOYMENT_TARGET='#'
+
++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET /
++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple.
++
++
++
++
+ # checks for alternative programs
+
+ # compiler flags are generated in two sets, BASECFLAGS and OPT. OPT is just
+@@ -4507,6 +4816,26 @@
+ ;;
+ esac
+
++case $ac_sys_system in #(
++ iOS) :
++
++ as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"
++ as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"
++ ;; #(
++ tvOS) :
++
++ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"
++ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"
++ ;; #(
++ watchOS) :
++
++ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"
++ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"
++ ;; #(
++ *) :
++ ;;
++esac
++
+ if test "$ac_sys_system" = "Darwin"
+ then
+ # Extract the first word of "xcrun", so it can be a program name with args.
+@@ -6904,7 +7233,42 @@
+ #elif defined(__gnu_hurd__)
+ i386-gnu
+ #elif defined(__APPLE__)
++# include "TargetConditionals.h"
++# if TARGET_OS_IOS
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-iphonesimulator
++# else
++ arm64-iphonesimulator
++# endif
++# else
++ arm64-iphoneos
++# endif
++# elif TARGET_OS_TV
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-appletvsimulator
++# else
++ arm64-appletvsimulator
++# endif
++# else
++ arm64-appletvos
++# endif
++# elif TARGET_OS_WATCH
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-watchsimulator
++# else
++ arm64-watchsimulator
++# endif
++# else
++ arm64_32-watchos
++# endif
++# elif TARGET_OS_OSX
+ darwin
++# else
++# error unknown Apple platform
++# endif
+ #elif defined(__VXWORKS__)
+ vxworks
+ #elif defined(__wasm32__)
+@@ -6953,6 +7317,12 @@
+ case $ac_sys_system in #(
+ Darwin*) :
+ MULTIARCH="" ;; #(
++ iOS) :
++ MULTIARCH="" ;; #(
++ tvOS) :
++ MULTIARCH="" ;; #(
++ watchOS) :
++ MULTIARCH="" ;; #(
+ FreeBSD*) :
+ MULTIARCH="" ;; #(
+ *) :
+@@ -6960,8 +7330,6 @@
+ ;;
+ esac
+
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5
+-printf "%s\n" "$MULTIARCH" >&6; }
+
+ if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then
+ if test x$PLATFORM_TRIPLET != x$MULTIARCH; then
+@@ -6971,6 +7339,16 @@
+ MULTIARCH=$PLATFORM_TRIPLET
+ fi
+
++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5
++printf "%s\n" "$MULTIARCH" >&6; }
++
++case $ac_sys_system in #(
++ iOS|tvOS|watchOS) :
++ SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #(
++ *) :
++ SOABI_PLATFORM=$PLATFORM_TRIPLET
++ ;;
++esac
+
+ if test x$MULTIARCH != x; then
+ MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\""
+@@ -7014,6 +7392,18 @@
+ PY_SUPPORT_TIER=3 ;; #(
+ x86_64-*-freebsd*/clang) :
+ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-ios*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-ios*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-tvos*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-tvos*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-watchos*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ arm64_32-apple-watchos*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
+ *) :
+ PY_SUPPORT_TIER=0
+ ;;
+@@ -7464,17 +7854,25 @@
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5
+ printf %s "checking LDLIBRARY... " >&6; }
+
+-# MacOSX framework builds need more magic. LDLIBRARY is the dynamic
++# Apple framework builds need more magic. LDLIBRARY is the dynamic
+ # library that we build, but we do not want to link against it (we
+ # will find it with a -framework option). For this reason there is an
+ # extra variable BLDLIBRARY against which Python and the extension
+ # modules are linked, BLDLIBRARY. This is normally the same as
+-# LDLIBRARY, but empty for MacOSX framework builds.
++# LDLIBRARY, but empty for MacOSX framework builds. iOS does the same,
++# but uses a non-versioned framework layout.
+ if test "$enable_framework"
+ then
+- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
+- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}}
++ case $ac_sys_system in
++ Darwin)
++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
++ iOS|tvOS|watchOS)
++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
++ *)
++ as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;;
++ esac
+ BLDLIBRARY=''
++ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}}
+ else
+ BLDLIBRARY='$(LDLIBRARY)'
+ fi
+@@ -7487,64 +7885,70 @@
+
+ case $ac_sys_system in
+ CYGWIN*)
+- LDLIBRARY='libpython$(LDVERSION).dll.a'
+- DLLLIBRARY='libpython$(LDVERSION).dll'
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).dll.a'
++ DLLLIBRARY='libpython$(LDVERSION).dll'
++ ;;
+ SunOS*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)'
+- RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+- INSTSONAME="$LDLIBRARY".$SOVERSION
+- if test "$with_pydebug" != yes
+- then
+- PY3LIBRARY=libpython3.so
+- fi
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)'
++ RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
++ INSTSONAME="$LDLIBRARY".$SOVERSION
++ if test "$with_pydebug" != yes
++ then
++ PY3LIBRARY=libpython3.so
++ fi
++ ;;
+ Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*|VxWorks*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- BLDLIBRARY='-L. -lpython$(LDVERSION)'
+- RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+- INSTSONAME="$LDLIBRARY".$SOVERSION
+- if test "$with_pydebug" != yes
+- then
+- PY3LIBRARY=libpython3.so
+- fi
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ BLDLIBRARY='-L. -lpython$(LDVERSION)'
++ RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
++ INSTSONAME="$LDLIBRARY".$SOVERSION
++ if test "$with_pydebug" != yes
++ then
++ PY3LIBRARY=libpython3.so
++ fi
++ ;;
+ hp*|HP*)
+- case `uname -m` in
+- ia64)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- ;;
+- *)
+- LDLIBRARY='libpython$(LDVERSION).sl'
+- ;;
+- esac
+- BLDLIBRARY='-Wl,+b,$(LIBDIR) -L. -lpython$(LDVERSION)'
+- RUNSHARED=SHLIB_PATH=`pwd`${SHLIB_PATH:+:${SHLIB_PATH}}
+- ;;
++ case `uname -m` in
++ ia64)
++ LDLIBRARY='libpython$(LDVERSION).so'
++ ;;
++ *)
++ LDLIBRARY='libpython$(LDVERSION).sl'
++ ;;
++ esac
++ BLDLIBRARY='-Wl,+b,$(LIBDIR) -L. -lpython$(LDVERSION)'
++ RUNSHARED=SHLIB_PATH=`pwd`${SHLIB_PATH:+:${SHLIB_PATH}}
++ ;;
+ Darwin*)
+- LDLIBRARY='libpython$(LDVERSION).dylib'
+- BLDLIBRARY='-L. -lpython$(LDVERSION)'
+- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).dylib'
++ BLDLIBRARY='-L. -lpython$(LDVERSION)'
++ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
++ ;;
++ iOS|tvOS|watchOS)
++ LDLIBRARY='libpython$(LDVERSION).dylib'
++ ;;
+ AIX*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
++ ;;
+
+ esac
+ else # shared is disabled
+ PY_ENABLE_SHARED=0
+ case $ac_sys_system in
+ CYGWIN*)
+- BLDLIBRARY='$(LIBRARY)'
+- LDLIBRARY='libpython$(LDVERSION).dll.a'
+- ;;
++ BLDLIBRARY='$(LIBRARY)'
++ LDLIBRARY='libpython$(LDVERSION).dll.a'
++ ;;
+ esac
+ fi
+
++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5
++printf "%s\n" "$LDLIBRARY" >&6; }
++
+ if test "$cross_compiling" = yes; then
+- RUNSHARED=
++ RUNSHARED=
+ fi
+
+
+@@ -7739,9 +8143,6 @@
+ PYTHON_FOR_BUILD="_PYTHON_HOSTRUNNER='$HOSTRUNNER' $PYTHON_FOR_BUILD"
+ fi
+
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDLIBRARY" >&5
+-printf "%s\n" "$LDLIBRARY" >&6; }
+-
+ # LIBRARY_DEPS, LINK_PYTHON_OBJS and LINK_PYTHON_DEPS variable
+ case $ac_sys_system/$ac_sys_emscripten_target in #(
+ Emscripten/browser*) :
+@@ -12789,6 +13190,11 @@
+ BLDSHARED="$LDSHARED"
+ fi
+ ;;
++ iOS/*|tvOS/*|watchOS/*)
++ LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
++ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
++ BLDSHARED="$LDSHARED"
++ ;;
+ Emscripten|WASI)
+ LDSHARED='$(CC) -shared'
+ LDCXXSHARED='$(CXX) -shared';;
+@@ -12918,30 +13324,34 @@
+ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
+ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
+ # -u libsys_s pulls in all symbols in libsys
+- Darwin/*)
++ Darwin/*|iOS/*|tvOS/*|watchOS/*)
+ LINKFORSHARED="$extra_undefs -framework CoreFoundation"
+
+ # Issue #18075: the default maximum stack size (8MBytes) is too
+ # small for the default recursion limit. Increase the stack size
+ # to ensure that tests don't crash
+- stack_size="1000000" # 16 MB
+- if test "$with_ubsan" = "yes"
+- then
+- # Undefined behavior sanitizer requires an even deeper stack
+- stack_size="4000000" # 64 MB
+- fi
+-
+- LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
++ stack_size="1000000" # 16 MB
++ if test "$with_ubsan" = "yes"
++ then
++ # Undefined behavior sanitizer requires an even deeper stack
++ stack_size="4000000" # 64 MB
++ fi
+
+
+ printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h
+
+
+- if test "$enable_framework"
+- then
+- LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
++ if test $ac_sys_system = "Darwin"; then
++ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
++
++ if test "$enable_framework"; then
++ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
++ fi
++ LINKFORSHARED="$LINKFORSHARED"
++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then
++ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
+ fi
+- LINKFORSHARED="$LINKFORSHARED";;
++ ;;
+ OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";;
+ SCO_SV*) LINKFORSHARED="-Wl,-Bexport";;
+ ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";;
+@@ -14330,6 +14740,10 @@
+
+ ctypes_malloc_closure=yes
+ ;; #(
++ iOS|tvOS|watchOS) :
++
++ ctypes_malloc_closure=yes
++ ;; #(
+ sunos5) :
+ as_fn_append LIBFFI_LIBS " -mimpure-text"
+ ;; #(
+@@ -17599,12 +18013,6 @@
+ then :
+ printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv"
+-if test "x$ac_cv_func_execv" = xyes
+-then :
+- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
+ if test "x$ac_cv_func_explicit_bzero" = xyes
+@@ -17665,18 +18073,6 @@
+ then :
+ printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork"
+-if test "x$ac_cv_func_fork" = xyes
+-then :
+- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h
+-
+-fi
+-ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1"
+-if test "x$ac_cv_func_fork1" = xyes
+-then :
+- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf"
+ if test "x$ac_cv_func_fpathconf" = xyes
+@@ -17731,12 +18127,6 @@
+ then :
+ printf "%s\n" "#define HAVE_GETEGID 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+-if test "x$ac_cv_func_getentropy" = xyes
+-then :
+- printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid"
+ if test "x$ac_cv_func_geteuid" = xyes
+@@ -17773,12 +18163,6 @@
+ then :
+ printf "%s\n" "#define HAVE_GETGROUPLIST 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
+-if test "x$ac_cv_func_getgroups" = xyes
+-then :
+- printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname"
+ if test "x$ac_cv_func_gethostname" = xyes
+@@ -18097,18 +18481,6 @@
+ then :
+ printf "%s\n" "#define HAVE_POSIX_FALLOCATE 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
+-if test "x$ac_cv_func_posix_spawn" = xyes
+-then :
+- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h
+-
+-fi
+-ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp"
+-if test "x$ac_cv_func_posix_spawnp" = xyes
+-then :
+- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
+ if test "x$ac_cv_func_pread" = xyes
+@@ -18373,12 +18745,6 @@
+ then :
+ printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack"
+-if test "x$ac_cv_func_sigaltstack" = xyes
+-then :
+- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset"
+ if test "x$ac_cv_func_sigfillset" = xyes
+@@ -18469,12 +18835,6 @@
+ then :
+ printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system"
+-if test "x$ac_cv_func_system" = xyes
+-then :
+- printf "%s\n" "#define HAVE_SYSTEM 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp"
+ if test "x$ac_cv_func_tcgetpgrp" = xyes
+@@ -18647,6 +19007,73 @@
+
+ fi
+
++# iOS/tvOS/watchOS define some system methods that can be linked (so they are
++# found by configure), but either raise a compilation error (because the
++# header definition prevents usage - autoconf doesn't use the headers), or
++# raise an error if used at runtime. Force these symbols off.
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
++if test "x$ac_cv_func_getentropy" = xyes
++then :
++ printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
++if test "x$ac_cv_func_getgroups" = xyes
++then :
++ printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system"
++if test "x$ac_cv_func_system" = xyes
++then :
++ printf "%s\n" "#define HAVE_SYSTEM 1" >>confdefs.h
++
++fi
++
++fi
++
++# tvOS/watchOS have some additional methods that can be found, but not used.
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv"
++if test "x$ac_cv_func_execv" = xyes
++then :
++ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork"
++if test "x$ac_cv_func_fork" = xyes
++then :
++ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1"
++if test "x$ac_cv_func_fork1" = xyes
++then :
++ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
++if test "x$ac_cv_func_posix_spawn" = xyes
++then :
++ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp"
++if test "x$ac_cv_func_posix_spawnp" = xyes
++then :
++ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack"
++if test "x$ac_cv_func_sigaltstack" = xyes
++then :
++ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h
++
++fi
++
++fi
++
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
+ printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
+ if test ${ac_cv_c_undeclared_builtin_options+y}
+@@ -21399,7 +21826,8 @@
+
+
+ # check for openpty, login_tty, and forkpty
+-
++# tvOS/watchOS have functions for tty, but can't use them
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
+
+ for ac_func in openpty
+ do :
+@@ -21495,7 +21923,7 @@
+ fi
+
+ done
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5
+ printf %s "checking for library containing login_tty... " >&6; }
+ if test ${ac_cv_search_login_tty+y}
+ then :
+@@ -21652,6 +22080,7 @@
+ fi
+
+ done
++fi
+
+ # check for long file support functions
+ ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64"
+@@ -22197,6 +22626,11 @@
+
+ done
+
++# On iOS, tvOS and watchOS, clock_settime can be linked (so it is found by
++# configure), but when used in an unprivileged process, it crashes rather than
++# returning an error. Force the symbol off.
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS"
++then
+
+ for ac_func in clock_settime
+ do :
+@@ -22207,7 +22641,7 @@
+
+ else $as_nop
+
+- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5
+ printf %s "checking for clock_settime in -lrt... " >&6; }
+ if test ${ac_cv_lib_rt_clock_settime+y}
+ then :
+@@ -22245,7 +22679,7 @@
+ if test "x$ac_cv_lib_rt_clock_settime" = xyes
+ then :
+
+- printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h
++ printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h
+
+
+ fi
+@@ -22254,6 +22688,7 @@
+ fi
+
+ done
++fi
+
+
+ for ac_func in clock_nanosleep
+@@ -22475,7 +22910,9 @@
+ if test "$cross_compiling" = yes
+ then :
+
+-if test "${enable_ipv6+set}" = set; then
++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then
++ ac_cv_buggy_getaddrinfo="no"
++elif test "${enable_ipv6+set}" = set; then
+ ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6"
+ else
+ ac_cv_buggy_getaddrinfo=yes
+@@ -24377,7 +24814,7 @@
+ printf "%s\n" "$ABIFLAGS" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5
+ printf %s "checking SOABI... " >&6; }
+-SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
++SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5
+ printf "%s\n" "$SOABI" >&6; }
+
+@@ -24385,7 +24822,7 @@
+ if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then
+ # Similar to SOABI but remove "d" flag from ABIFLAGS
+
+- ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
++ ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${SOABI_PLATFORM:+-$SOABI_PLATFORM}
+
+ printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h
+
+@@ -27136,24 +27573,28 @@
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5
+ printf "%s\n" "$as_me: checking for device files" >&6;}
+
+-if test "x$cross_compiling" = xyes; then
+- if test "${ac_cv_file__dev_ptmx+set}" != set; then
+- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
++if test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then
++ ac_cv_file__dev_ptmx=no
++ ac_cv_file__dev_ptc=no
++else
++ if test "x$cross_compiling" = xyes; then
++ if test "${ac_cv_file__dev_ptmx+set}" != set; then
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
+ printf %s "checking for /dev/ptmx... " >&6; }
+- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5
+ printf "%s\n" "not set" >&6; }
+- as_fn_error $? "set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5
+- fi
+- if test "${ac_cv_file__dev_ptc+set}" != set; then
+- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
++ as_fn_error $? "set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5
++ fi
++ if test "${ac_cv_file__dev_ptc+set}" != set; then
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
+ printf %s "checking for /dev/ptc... " >&6; }
+- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5
+ printf "%s\n" "not set" >&6; }
+- as_fn_error $? "set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5
++ as_fn_error $? "set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5
++ fi
+ fi
+-fi
+
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
+ printf %s "checking for /dev/ptmx... " >&6; }
+ if test ${ac_cv_file__dev_ptmx+y}
+ then :
+@@ -27174,12 +27615,12 @@
+
+ fi
+
+-if test "x$ac_cv_file__dev_ptmx" = xyes; then
++ if test "x$ac_cv_file__dev_ptmx" = xyes; then
+
+ printf "%s\n" "#define HAVE_DEV_PTMX 1" >>confdefs.h
+
+-fi
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
++ fi
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
+ printf %s "checking for /dev/ptc... " >&6; }
+ if test ${ac_cv_file__dev_ptc+y}
+ then :
+@@ -27200,10 +27641,11 @@
+
+ fi
+
+-if test "x$ac_cv_file__dev_ptc" = xyes; then
++ if test "x$ac_cv_file__dev_ptc" = xyes; then
+
+ printf "%s\n" "#define HAVE_DEV_PTC 1" >>confdefs.h
+
++ fi
+ fi
+
+ if test $ac_sys_system = Darwin
+@@ -27645,6 +28087,8 @@
+ with_ensurepip=no ;; #(
+ WASI) :
+ with_ensurepip=no ;; #(
++ iOS|tvOS|watchOS) :
++ with_ensurepip=no ;; #(
+ *) :
+ with_ensurepip=upgrade
+ ;;
+@@ -28586,6 +29030,27 @@
+ py_cv_module_ossaudiodev=n/a
+ py_cv_module_spwd=n/a
+ ;; #(
++ iOS|tvOS|watchOS) :
++
++
++
++ py_cv_module__curses=n/a
++ py_cv_module__curses_panel=n/a
++ py_cv_module__gdbm=n/a
++ py_cv_module__multiprocessing=n/a
++ py_cv_module__posixshmem=n/a
++ py_cv_module__posixsubprocess=n/a
++ py_cv_module__scproxy=n/a
++ py_cv_module__tkinter=n/a
++ py_cv_module_grp=n/a
++ py_cv_module_nis=n/a
++ py_cv_module_readline=n/a
++ py_cv_module_pwd=n/a
++ py_cv_module_spwd=n/a
++ py_cv_module_syslog=n/a
++ py_cv_module_=n/a
++
++ ;; #(
+ CYGWIN*) :
+
+
+@@ -32326,6 +32791,9 @@
+ "Mac/PythonLauncher/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/PythonLauncher/Makefile" ;;
+ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;;
+ "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;;
++ "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;;
++ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;;
++ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;;
+ "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;;
+ "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;;
+ "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;;
+diff --git a/configure.ac b/configure.ac
+index 8a32cb58f4e..313053bc023 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -307,6 +307,161 @@
+ AC_MSG_ERROR([pkg-config is required])]
+ fi
+
++# Set name for machine-dependent library files
++AC_ARG_VAR([MACHDEP], [name for machine-dependent library files])
++AC_MSG_CHECKING([MACHDEP])
++if test -z "$MACHDEP"
++then
++ # avoid using uname for cross builds
++ if test "$cross_compiling" = yes; then
++ # ac_sys_system and ac_sys_release are used for setting
++ # a lot of different things including 'define_xopen_source'
++ # in the case statement below.
++ case "$host" in
++ *-*-linux-android*)
++ ac_sys_system=Linux-android
++ ;;
++ *-*-linux*)
++ ac_sys_system=Linux
++ ;;
++ *-*-cygwin*)
++ ac_sys_system=Cygwin
++ ;;
++ *-apple-ios*)
++ ac_sys_system=iOS
++ ;;
++ *-apple-tvos*)
++ ac_sys_system=tvOS
++ ;;
++ *-apple-watchos*)
++ ac_sys_system=watchOS
++ ;;
++ *-*-vxworks*)
++ ac_sys_system=VxWorks
++ ;;
++ *-*-emscripten)
++ ac_sys_system=Emscripten
++ ;;
++ *-*-wasi)
++ ac_sys_system=WASI
++ ;;
++ *)
++ # for now, limit cross builds to known configurations
++ MACHDEP="unknown"
++ AC_MSG_ERROR([cross build not supported for $host])
++ esac
++ ac_sys_release=
++ else
++ ac_sys_system=`uname -s`
++ if test "$ac_sys_system" = "AIX" \
++ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
++ ac_sys_release=`uname -v`
++ else
++ ac_sys_release=`uname -r`
++ fi
++ fi
++ ac_md_system=`echo $ac_sys_system |
++ tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'`
++ ac_md_release=`echo $ac_sys_release |
++ tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'`
++ MACHDEP="$ac_md_system$ac_md_release"
++
++ case $MACHDEP in
++ aix*) MACHDEP="aix";;
++ linux*) MACHDEP="linux";;
++ cygwin*) MACHDEP="cygwin";;
++ darwin*) MACHDEP="darwin";;
++ '') MACHDEP="unknown";;
++ esac
++
++ if test "$ac_sys_system" = "SunOS"; then
++ # For Solaris, there isn't an OS version specific macro defined
++ # in most compilers, so we define one here.
++ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'`
++ AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION],
++ [The version of SunOS/Solaris as reported by `uname -r' without the dot.])
++ fi
++fi
++AC_MSG_RESULT(["$MACHDEP"])
++
++# On cross-compile builds, configure will look for a host-specific compiler by
++# prepending the user-provided host triple to the required binary name.
++#
++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
++# which isn't a binary that exists, and isn't very convenient, as it contains the
++# iOS version. As the default cross-compiler name won't exist, configure falls
++# back to gcc, which *definitely* won't work. We're providing wrapper scripts for
++# these tools; the binary names of these scripts are better defaults than "gcc".
++# This only requires that the user put the platform scripts folder (e.g.,
++# "iOS/Resources/bin") in their path, rather than defining platform-specific
++# names/paths for AR, CC, CPP, and CXX explicitly; and if the user forgets to
++# either put the platform scripts folder in the path, or specify CC etc,
++# configure will fail.
++if test -z "$AR"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;;
++ aarch64-apple-ios*) AR=arm64-apple-ios-ar ;;
++ x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;;
++
++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;;
++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;;
++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;;
++
++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;;
++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;;
++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;;
++ *)
++ esac
++fi
++if test -z "$CC"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;;
++ aarch64-apple-ios*) CC=arm64-apple-ios-clang ;;
++ x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;;
++ *)
++ esac
++fi
++if test -z "$CPP"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;;
++ aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;;
++ x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;;
++
++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;;
++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;;
++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;;
++
++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;;
++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;;
++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;;
++ *)
++ esac
++fi
++if test -z "$CXX"; then
++ case "$host" in
++ aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang ;;
++ aarch64-apple-ios*) CXX=arm64-apple-ios-clang ;;
++ x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang ;;
++ *)
++ esac
++fi
++
+ AC_MSG_CHECKING([for --enable-universalsdk])
+ AC_ARG_ENABLE([universalsdk],
+ AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@],
+@@ -416,109 +571,189 @@
+ [
+ case $enableval in
+ yes)
+- enableval=/Library/Frameworks
++ case $ac_sys_system in
++ Darwin) enableval=/Library/Frameworks ;;
++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;;
++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;;
++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;;
++ *) AC_MSG_ERROR([Unknown platform for framework build])
++ esac
+ esac
++
+ case $enableval in
+ no)
+- PYTHONFRAMEWORK=
+- PYTHONFRAMEWORKDIR=no-framework
+- PYTHONFRAMEWORKPREFIX=
+- PYTHONFRAMEWORKINSTALLDIR=
+- FRAMEWORKINSTALLFIRST=
+- FRAMEWORKINSTALLLAST=
+- FRAMEWORKALTINSTALLFIRST=
+- FRAMEWORKALTINSTALLLAST=
+- FRAMEWORKPYTHONW=
+- if test "x${prefix}" = "xNONE"; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+- enable_framework=
++ case $ac_sys_system in
++ iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;;
++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;;
++ *)
++ PYTHONFRAMEWORK=
++ PYTHONFRAMEWORKDIR=no-framework
++ PYTHONFRAMEWORKPREFIX=
++ PYTHONFRAMEWORKINSTALLDIR=
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=
++ RESSRCDIR=
++ FRAMEWORKINSTALLFIRST=
++ FRAMEWORKINSTALLLAST=
++ FRAMEWORKALTINSTALLFIRST=
++ FRAMEWORKALTINSTALLLAST=
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++
++ if test "x${prefix}" = "xNONE"; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
++ enable_framework=
++ esac
+ ;;
+ *)
+ PYTHONFRAMEWORKPREFIX="${enableval}"
+ PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR
+- FRAMEWORKINSTALLFIRST="frameworkinstallstructure"
+- FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure "
+- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
+- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
+- FRAMEWORKPYTHONW="frameworkpythonw"
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+-
+- if test "x${prefix}" = "xNONE" ; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+-
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+
+- case "${enableval}" in
+- /System*)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- if test "${prefix}" = "NONE" ; then
+- # See below
+- FRAMEWORKUNIXTOOLSPREFIX="/usr"
+- fi
+- ;;
++ case $ac_sys_system in #(
++ Darwin) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
++ FRAMEWORKPYTHONW="frameworkpythonw"
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++
++ if test "x${prefix}" = "xNONE" ; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
+
+- /Library*)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- ;;
++ case "${enableval}" in
++ /System*)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ if test "${prefix}" = "NONE" ; then
++ # See below
++ FRAMEWORKUNIXTOOLSPREFIX="/usr"
++ fi
++ ;;
++
++ /Library*)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ ;;
++
++ */Library/Frameworks)
++ MDIR="`dirname "${enableval}"`"
++ MDIR="`dirname "${MDIR}"`"
++ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications"
++
++ if test "${prefix}" = "NONE"; then
++ # User hasn't specified the
++ # --prefix option, but wants to install
++ # the framework in a non-default location,
++ # ensure that the compatibility links get
++ # installed relative to that prefix as well
++ # instead of in /usr/local.
++ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}"
++ fi
++ ;;
+
+- */Library/Frameworks)
+- MDIR="`dirname "${enableval}"`"
+- MDIR="`dirname "${MDIR}"`"
+- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications"
+-
+- if test "${prefix}" = "NONE"; then
+- # User hasn't specified the
+- # --prefix option, but wants to install
+- # the framework in a non-default location,
+- # ensure that the compatibility links get
+- # installed relative to that prefix as well
+- # instead of in /usr/local.
+- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}"
+- fi
+- ;;
++ *)
++ FRAMEWORKINSTALLAPPSPREFIX="/Applications"
++ ;;
++ esac
+
+- *)
+- FRAMEWORKINSTALLAPPSPREFIX="/Applications"
+- ;;
++ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix}
++ RESSRCDIR=Mac/Resources/framework
++
++ # Add files for Mac specific code to the list of output
++ # files:
++ AC_CONFIG_FILES([Mac/Makefile])
++ AC_CONFIG_FILES([Mac/PythonLauncher/Makefile])
++ AC_CONFIG_FILES([Mac/Resources/framework/Info.plist])
++ AC_CONFIG_FILES([Mac/Resources/app/Info.plist])
++ ;;
++ iOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=iOS/Resources
++
++ AC_CONFIG_FILES([iOS/Resources/Info.plist])
++ ;;
++ tvOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=tvOS/Resources
++
++ AC_CONFIG_FILES([tvOS/Resources/Info.plist])
++ ;;
++ watchOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=watchOS/Resources
++
++ AC_CONFIG_FILES([watchOS/Resources/Info.plist])
++ ;;
++ *)
++ AC_MSG_ERROR([Unknown platform for framework build])
++ ;;
++ esac
+ esac
+-
+- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION
+-
+- # Add files for Mac specific code to the list of output
+- # files:
+- AC_CONFIG_FILES([Mac/Makefile])
+- AC_CONFIG_FILES([Mac/PythonLauncher/Makefile])
+- AC_CONFIG_FILES([Mac/Resources/framework/Info.plist])
+- AC_CONFIG_FILES([Mac/Resources/app/Info.plist])
+- esac
+ ],[
+- PYTHONFRAMEWORK=
+- PYTHONFRAMEWORKDIR=no-framework
+- PYTHONFRAMEWORKPREFIX=
+- PYTHONFRAMEWORKINSTALLDIR=
+- FRAMEWORKINSTALLFIRST=
+- FRAMEWORKINSTALLLAST=
+- FRAMEWORKALTINSTALLFIRST=
+- FRAMEWORKALTINSTALLLAST=
+- FRAMEWORKPYTHONW=
+- if test "x${prefix}" = "xNONE" ; then
+- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
+- else
+- FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
+- fi
+- enable_framework=
+-
++ case $ac_sys_system in
++ iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;;
++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;;
++ *)
++ PYTHONFRAMEWORK=
++ PYTHONFRAMEWORKDIR=no-framework
++ PYTHONFRAMEWORKPREFIX=
++ PYTHONFRAMEWORKINSTALLDIR=
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=
++ RESSRCDIR=
++ FRAMEWORKINSTALLFIRST=
++ FRAMEWORKINSTALLLAST=
++ FRAMEWORKALTINSTALLFIRST=
++ FRAMEWORKALTINSTALLLAST=
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="commoninstall bininstall maninstall"
++ if test "x${prefix}" = "xNONE" ; then
++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}"
++ else
++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}"
++ fi
++ enable_framework=
++ esac
+ ])
+ AC_SUBST([PYTHONFRAMEWORK])
+ AC_SUBST([PYTHONFRAMEWORKIDENTIFIER])
+ AC_SUBST([PYTHONFRAMEWORKDIR])
+ AC_SUBST([PYTHONFRAMEWORKPREFIX])
+ AC_SUBST([PYTHONFRAMEWORKINSTALLDIR])
++AC_SUBST([PYTHONFRAMEWORKINSTALLNAMEPREFIX])
++AC_SUBST([RESSRCDIR])
+ AC_SUBST([FRAMEWORKINSTALLFIRST])
+ AC_SUBST([FRAMEWORKINSTALLLAST])
+ AC_SUBST([FRAMEWORKALTINSTALLFIRST])
+@@ -526,77 +761,51 @@
+ AC_SUBST([FRAMEWORKPYTHONW])
+ AC_SUBST([FRAMEWORKUNIXTOOLSPREFIX])
+ AC_SUBST([FRAMEWORKINSTALLAPPSPREFIX])
++AC_SUBST([INSTALLTARGETS])
+
+ AC_DEFINE_UNQUOTED([_PYTHONFRAMEWORK], ["${PYTHONFRAMEWORK}"],
+ [framework name])
+
+-# Set name for machine-dependent library files
+-AC_ARG_VAR([MACHDEP], [name for machine-dependent library files])
+-AC_MSG_CHECKING([MACHDEP])
+-if test -z "$MACHDEP"
+-then
+- # avoid using uname for cross builds
+- if test "$cross_compiling" = yes; then
+- # ac_sys_system and ac_sys_release are used for setting
+- # a lot of different things including 'define_xopen_source'
+- # in the case statement below.
+- case "$host" in
+- *-*-linux-android*)
+- ac_sys_system=Linux-android
+- ;;
+- *-*-linux*)
+- ac_sys_system=Linux
+- ;;
+- *-*-cygwin*)
+- ac_sys_system=Cygwin
+- ;;
+- *-*-vxworks*)
+- ac_sys_system=VxWorks
+- ;;
+- *-*-emscripten)
+- ac_sys_system=Emscripten
+- ;;
+- *-*-wasi)
+- ac_sys_system=WASI
+- ;;
+- *)
+- # for now, limit cross builds to known configurations
+- MACHDEP="unknown"
+- AC_MSG_ERROR([cross build not supported for $host])
+- esac
+- ac_sys_release=
+- else
+- ac_sys_system=`uname -s`
+- if test "$ac_sys_system" = "AIX" \
+- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then
+- ac_sys_release=`uname -v`
+- else
+- ac_sys_release=`uname -r`
+- fi
+- fi
+- ac_md_system=`echo $ac_sys_system |
+- tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'`
+- ac_md_release=`echo $ac_sys_release |
+- tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'`
+- MACHDEP="$ac_md_system$ac_md_release"
+-
+- case $MACHDEP in
+- aix*) MACHDEP="aix";;
+- linux*) MACHDEP="linux";;
+- cygwin*) MACHDEP="cygwin";;
+- darwin*) MACHDEP="darwin";;
+- '') MACHDEP="unknown";;
++dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output
++AC_MSG_CHECKING([for --with-app-store-compliance])
++AC_ARG_WITH(
++ [app_store_compliance],
++ [AS_HELP_STRING(
++ [--with-app-store-compliance=@<:@PATCH-FILE@:>@],
++ [Enable any patches required for compiliance with app stores.
++ Optional PATCH-FILE specifies the custom patch to apply.]
++ )],[
++ case "$withval" in
++ yes)
++ case $ac_sys_system in
++ Darwin|iOS|tvOS|watchOS)
++ # iOS/tvOS/watchOS is able to share the macOS patch
++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
++ ;;
++ *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;;
++ esac
++ AC_MSG_RESULT([applying default app store compliance patch])
++ ;;
++ *)
++ APP_STORE_COMPLIANCE_PATCH="${withval}"
++ AC_MSG_RESULT([applying custom app store compliance patch])
++ ;;
+ esac
+-
+- if test "$ac_sys_system" = "SunOS"; then
+- # For Solaris, there isn't an OS version specific macro defined
+- # in most compilers, so we define one here.
+- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'`
+- AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION],
+- [The version of SunOS/Solaris as reported by `uname -r' without the dot.])
+- fi
+-fi
+-AC_MSG_RESULT(["$MACHDEP"])
++ ],[
++ case $ac_sys_system in
++ iOS|tvOS|watchOS)
++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch
++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
++ AC_MSG_RESULT([applying default app store compliance patch])
++ ;;
++ *)
++ # No default app compliance patching on any other platform
++ APP_STORE_COMPLIANCE_PATCH=
++ AC_MSG_RESULT([not patching for app store compliance])
++ ;;
++ esac
++])
++AC_SUBST([APP_STORE_COMPLIANCE_PATCH])
+
+ AC_SUBST([_PYTHON_HOST_PLATFORM])
+ if test "$cross_compiling" = yes; then
+@@ -604,27 +813,87 @@
+ *-*-linux*)
+ case "$host_cpu" in
+ arm*)
+- _host_cpu=arm
++ _host_ident=arm
+ ;;
+ *)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ esac
+ ;;
+ *-*-cygwin*)
+- _host_cpu=
++ _host_ident=
++ ;;
++ *-apple-ios*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # IPHONEOS_DEPLOYMENT_TARGET is the minimum supported iOS version
++ AC_MSG_CHECKING([iOS deployment target])
++ IPHONEOS_DEPLOYMENT_TARGET=${_host_os:3}
++ IPHONEOS_DEPLOYMENT_TARGET=${IPHONEOS_DEPLOYMENT_TARGET:=13.0}
++ AC_MSG_RESULT([$IPHONEOS_DEPLOYMENT_TARGET])
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${IPHONEOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device}
++ ;;
++ *)
++ _host_ident=${IPHONEOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-tvos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version
++ AC_MSG_CHECKING([tvOS deployment target])
++ TVOS_DEPLOYMENT_TARGET=${_host_os:4}
++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0}
++ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET])
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device}
++ ;;
++ *)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-watchos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version
++ AC_MSG_CHECKING([watchOS deployment target])
++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7}
++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0}
++ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET])
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device}
++ ;;
++ *)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device}
++ ;;
++ esac
+ ;;
+ *-*-vxworks*)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ ;;
+ wasm32-*-* | wasm64-*-*)
+- _host_cpu=$host_cpu
++ _host_ident=$host_cpu
+ ;;
+ *)
+ # for now, limit cross builds to known configurations
+ MACHDEP="unknown"
+ AC_MSG_ERROR([cross build not supported for $host])
+ esac
+- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}"
++ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}"
+ fi
+
+ # Some systems cannot stand _XOPEN_SOURCE being defined at all; they
+@@ -690,6 +959,13 @@
+ define_xopen_source=no;;
+ Darwin/@<:@[12]@:>@@<:@0-9@:>@.*)
+ define_xopen_source=no;;
++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features.
++ iOS/*)
++ define_xopen_source=no;;
++ tvOS/*)
++ define_xopen_source=no;;
++ watchOS/*)
++ define_xopen_source=no;;
+ # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
+ # defining NI_NUMERICHOST.
+ QNX/6.3.2)
+@@ -748,6 +1024,12 @@
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET=
+ EXPORT_MACOSX_DEPLOYMENT_TARGET='#'
+
++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET /
++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple.
++AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET])
++AC_SUBST([TVOS_DEPLOYMENT_TARGET])
++AC_SUBST([WATCHOS_DEPLOYMENT_TARGET])
++
+ # checks for alternative programs
+
+ # compiler flags are generated in two sets, BASECFLAGS and OPT. OPT is just
+@@ -780,6 +1062,20 @@
+ ],
+ )
+
++dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version.
++AS_CASE([$ac_sys_system],
++ [iOS], [
++ AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
++ AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
++ ],[tvOS], [
++ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"])
++ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"])
++ ],[watchOS], [
++ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"])
++ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"])
++ ],
++)
++
+ if test "$ac_sys_system" = "Darwin"
+ then
+ dnl look for SDKROOT
+@@ -1077,7 +1373,42 @@
+ #elif defined(__gnu_hurd__)
+ i386-gnu
+ #elif defined(__APPLE__)
++# include "TargetConditionals.h"
++# if TARGET_OS_IOS
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-iphonesimulator
++# else
++ arm64-iphonesimulator
++# endif
++# else
++ arm64-iphoneos
++# endif
++# elif TARGET_OS_TV
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-appletvsimulator
++# else
++ arm64-appletvsimulator
++# endif
++# else
++ arm64-appletvos
++# endif
++# elif TARGET_OS_WATCH
++# if TARGET_OS_SIMULATOR
++# if __x86_64__
++ x86_64-watchsimulator
++# else
++ arm64-watchsimulator
++# endif
++# else
++ arm64_32-watchos
++# endif
++# elif TARGET_OS_OSX
+ darwin
++# else
++# error unknown Apple platform
++# endif
+ #elif defined(__VXWORKS__)
+ vxworks
+ #elif defined(__wasm32__)
+@@ -1119,14 +1450,24 @@
+ fi
+ rm -f conftest.c conftest.out
+
++dnl On some platforms, using a true "triplet" for MULTIARCH would be redundant.
++dnl For example, `arm64-apple-darwin` is redundant, because there isn't a
++dnl non-Apple Darwin. Including the CPU architecture can also be potentially
++dnl redundant - on macOS, for example, it's possible to do a single compile
++dnl pass that includes multiple architectures, so it would be misleading for
++dnl MULTIARCH (and thus the sysconfigdata module name) to include a single CPU
++dnl architecture. PLATFORM_TRIPLET will be a pair or single value for these
++dnl platforms.
+ AC_MSG_CHECKING([for multiarch])
+ AS_CASE([$ac_sys_system],
+ [Darwin*], [MULTIARCH=""],
++ [iOS], [MULTIARCH=""],
++ [tvOS], [MULTIARCH=""],
++ [watchOS], [MULTIARCH=""],
+ [FreeBSD*], [MULTIARCH=""],
+ [MULTIARCH=$($CC --print-multiarch 2>/dev/null)]
+ )
+ AC_SUBST([MULTIARCH])
+-AC_MSG_RESULT([$MULTIARCH])
+
+ if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then
+ if test x$PLATFORM_TRIPLET != x$MULTIARCH; then
+@@ -1136,6 +1477,17 @@
+ MULTIARCH=$PLATFORM_TRIPLET
+ fi
+ AC_SUBST([PLATFORM_TRIPLET])
++AC_MSG_RESULT([$MULTIARCH])
++
++dnl Even if we *do* include the CPU architecture in the MULTIARCH value, some
++dnl platforms don't need the CPU architecture in the SOABI tag. These platforms
++dnl will have multiple sysconfig modules (one for each CPU architecture), but
++dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of
++dnl the PLATFORM_TRIPLET that will be used in binary module extensions.
++AS_CASE([$ac_sys_system],
++ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`],
++ [SOABI_PLATFORM=$PLATFORM_TRIPLET]
++)
+
+ if test x$MULTIARCH != x; then
+ MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\""
+@@ -1166,6 +1518,12 @@
+ [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten
+ [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface
+ [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
++ [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
++ [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
++ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64
++ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64
++ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64
++ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64
+ [PY_SUPPORT_TIER=0]
+ )
+
+@@ -1479,17 +1837,25 @@
+
+ AC_MSG_CHECKING([LDLIBRARY])
+
+-# MacOSX framework builds need more magic. LDLIBRARY is the dynamic
++# Apple framework builds need more magic. LDLIBRARY is the dynamic
+ # library that we build, but we do not want to link against it (we
+ # will find it with a -framework option). For this reason there is an
+ # extra variable BLDLIBRARY against which Python and the extension
+ # modules are linked, BLDLIBRARY. This is normally the same as
+-# LDLIBRARY, but empty for MacOSX framework builds.
++# LDLIBRARY, but empty for MacOSX framework builds. iOS does the same,
++# but uses a non-versioned framework layout.
+ if test "$enable_framework"
+ then
+- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
+- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}}
++ case $ac_sys_system in
++ Darwin)
++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
++ iOS|tvOS|watchOS)
++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
++ *)
++ AC_MSG_ERROR([Unknown platform for framework build]);;
++ esac
+ BLDLIBRARY=''
++ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}}
+ else
+ BLDLIBRARY='$(LDLIBRARY)'
+ fi
+@@ -1501,64 +1867,69 @@
+ [Defined if Python is built as a shared library.])
+ case $ac_sys_system in
+ CYGWIN*)
+- LDLIBRARY='libpython$(LDVERSION).dll.a'
+- DLLLIBRARY='libpython$(LDVERSION).dll'
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).dll.a'
++ DLLLIBRARY='libpython$(LDVERSION).dll'
++ ;;
+ SunOS*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)'
+- RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+- INSTSONAME="$LDLIBRARY".$SOVERSION
+- if test "$with_pydebug" != yes
+- then
+- PY3LIBRARY=libpython3.so
+- fi
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)'
++ RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
++ INSTSONAME="$LDLIBRARY".$SOVERSION
++ if test "$with_pydebug" != yes
++ then
++ PY3LIBRARY=libpython3.so
++ fi
++ ;;
+ Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*|OpenBSD*|VxWorks*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- BLDLIBRARY='-L. -lpython$(LDVERSION)'
+- RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
+- INSTSONAME="$LDLIBRARY".$SOVERSION
+- if test "$with_pydebug" != yes
+- then
+- PY3LIBRARY=libpython3.so
+- fi
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ BLDLIBRARY='-L. -lpython$(LDVERSION)'
++ RUNSHARED=LD_LIBRARY_PATH=`pwd`${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
++ INSTSONAME="$LDLIBRARY".$SOVERSION
++ if test "$with_pydebug" != yes
++ then
++ PY3LIBRARY=libpython3.so
++ fi
++ ;;
+ hp*|HP*)
+- case `uname -m` in
+- ia64)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- ;;
+- *)
+- LDLIBRARY='libpython$(LDVERSION).sl'
+- ;;
+- esac
+- BLDLIBRARY='-Wl,+b,$(LIBDIR) -L. -lpython$(LDVERSION)'
+- RUNSHARED=SHLIB_PATH=`pwd`${SHLIB_PATH:+:${SHLIB_PATH}}
+- ;;
++ case `uname -m` in
++ ia64)
++ LDLIBRARY='libpython$(LDVERSION).so'
++ ;;
++ *)
++ LDLIBRARY='libpython$(LDVERSION).sl'
++ ;;
++ esac
++ BLDLIBRARY='-Wl,+b,$(LIBDIR) -L. -lpython$(LDVERSION)'
++ RUNSHARED=SHLIB_PATH=`pwd`${SHLIB_PATH:+:${SHLIB_PATH}}
++ ;;
+ Darwin*)
+- LDLIBRARY='libpython$(LDVERSION).dylib'
+- BLDLIBRARY='-L. -lpython$(LDVERSION)'
+- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).dylib'
++ BLDLIBRARY='-L. -lpython$(LDVERSION)'
++ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
++ ;;
++ iOS|tvOS|watchOS)
++ LDLIBRARY='libpython$(LDVERSION).dylib'
++ ;;
+ AIX*)
+- LDLIBRARY='libpython$(LDVERSION).so'
+- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
+- ;;
++ LDLIBRARY='libpython$(LDVERSION).so'
++ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
++ ;;
+
+ esac
+ else # shared is disabled
+ PY_ENABLE_SHARED=0
+ case $ac_sys_system in
+ CYGWIN*)
+- BLDLIBRARY='$(LIBRARY)'
+- LDLIBRARY='libpython$(LDVERSION).dll.a'
+- ;;
++ BLDLIBRARY='$(LIBRARY)'
++ LDLIBRARY='libpython$(LDVERSION).dll.a'
++ ;;
+ esac
+ fi
+
++AC_MSG_RESULT([$LDLIBRARY])
++
+ if test "$cross_compiling" = yes; then
+- RUNSHARED=
++ RUNSHARED=
+ fi
+
+ AC_ARG_VAR([HOSTRUNNER], [Program to run CPython for the host platform])
+@@ -1614,8 +1985,6 @@
+ PYTHON_FOR_BUILD="_PYTHON_HOSTRUNNER='$HOSTRUNNER' $PYTHON_FOR_BUILD"
+ fi
+
+-AC_MSG_RESULT([$LDLIBRARY])
+-
+ # LIBRARY_DEPS, LINK_PYTHON_OBJS and LINK_PYTHON_DEPS variable
+ AS_CASE([$ac_sys_system/$ac_sys_emscripten_target],
+ [Emscripten/browser*], [LIBRARY_DEPS='$(PY3LIBRARY) $(WASM_STDLIB) python.html python.worker.js'],
+@@ -3356,6 +3725,11 @@
+ BLDSHARED="$LDSHARED"
+ fi
+ ;;
++ iOS/*|tvOS/*|watchOS/*)
++ LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
++ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
++ BLDSHARED="$LDSHARED"
++ ;;
+ Emscripten|WASI)
+ LDSHARED='$(CC) -shared'
+ LDCXXSHARED='$(CXX) -shared';;
+@@ -3476,30 +3850,34 @@
+ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
+ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
+ # -u libsys_s pulls in all symbols in libsys
+- Darwin/*)
++ Darwin/*|iOS/*|tvOS/*|watchOS/*)
+ LINKFORSHARED="$extra_undefs -framework CoreFoundation"
+
+ # Issue #18075: the default maximum stack size (8MBytes) is too
+ # small for the default recursion limit. Increase the stack size
+ # to ensure that tests don't crash
+- stack_size="1000000" # 16 MB
+- if test "$with_ubsan" = "yes"
+- then
+- # Undefined behavior sanitizer requires an even deeper stack
+- stack_size="4000000" # 64 MB
+- fi
++ stack_size="1000000" # 16 MB
++ if test "$with_ubsan" = "yes"
++ then
++ # Undefined behavior sanitizer requires an even deeper stack
++ stack_size="4000000" # 64 MB
++ fi
+
+- LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
++ AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE],
++ [0x$stack_size],
++ [Custom thread stack size depending on chosen sanitizer runtimes.])
+
+- AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE],
+- [0x$stack_size],
+- [Custom thread stack size depending on chosen sanitizer runtimes.])
++ if test $ac_sys_system = "Darwin"; then
++ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
+
+- if test "$enable_framework"
+- then
+- LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
++ if test "$enable_framework"; then
++ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
++ fi
++ LINKFORSHARED="$LINKFORSHARED"
++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then
++ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
+ fi
+- LINKFORSHARED="$LINKFORSHARED";;
++ ;;
+ OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";;
+ SCO_SV*) LINKFORSHARED="-Wl,-Bexport";;
+ ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";;
+@@ -3873,6 +4251,9 @@
+ dnl when do we need USING_APPLE_OS_LIBFFI?
+ ctypes_malloc_closure=yes
+ ],
++ [iOS|tvOS|watchOS], [
++ ctypes_malloc_closure=yes
++ ],
+ [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])]
+ )
+ AS_VAR_IF([ctypes_malloc_closure], [yes], [
+@@ -4896,27 +5277,27 @@
+ # checks for library functions
+ AC_CHECK_FUNCS([ \
+ accept4 alarm bind_textdomain_codeset chmod chown clock close_range confstr \
+- copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \
++ copy_file_range ctermid dup dup3 explicit_bzero explicit_memset \
+ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \
+- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \
+- gai_strerror getegid getentropy geteuid getgid getgrgid getgrgid_r \
+- getgrnam_r getgrouplist getgroups gethostname getitimer getloadavg getlogin \
++ fpathconf fstatat ftime ftruncate futimens futimes futimesat \
++ gai_strerror getegid geteuid getgid getgrgid getgrgid_r \
++ getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \
+ getpeername getpgid getpid getppid getpriority _getpty \
+ getpwent getpwnam_r getpwuid getpwuid_r getresgid getresuid getrusage getsid getspent \
+ getspnam getuid getwd if_nameindex initgroups kill killpg lchown linkat \
+ lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \
+ mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \
+- pipe2 plock poll posix_fadvise posix_fallocate posix_spawn posix_spawnp \
++ pipe2 plock poll posix_fadvise posix_fallocate \
+ pread preadv preadv2 pthread_condattr_setclock pthread_init pthread_kill \
+ pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \
+ rtpSpawn sched_get_priority_max sched_rr_get_interval sched_setaffinity \
+ sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \
+ sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \
+ setitimer setlocale setpgid setpgrp setpriority setregid setresgid \
+- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \
++ setresuid setreuid setsid setuid setvbuf shutdown sigaction \
+ sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \
+ sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \
+- sysconf system tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
++ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
+ tmpnam tmpnam_r truncate ttyname umask uname unlinkat utimensat utimes vfork \
+ wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \
+ ])
+@@ -4928,6 +5309,22 @@
+ AC_CHECK_FUNCS([lchmod])
+ fi
+
++# iOS/tvOS/watchOS define some system methods that can be linked (so they are
++# found by configure), but either raise a compilation error (because the
++# header definition prevents usage - autoconf doesn't use the headers), or
++# raise an error if used at runtime. Force these symbols off.
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([ getentropy getgroups system ])
++fi
++
++# tvOS/watchOS have some additional methods that can be found, but not used.
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([ \
++ execv fork fork1 posix_spawn posix_spawnp \
++ sigaltstack \
++ ])
++fi
++
+ AC_CHECK_DECL([dirfd],
+ [AC_DEFINE([HAVE_DIRFD], [1],
+ [Define if you have the 'dirfd' function or macro.])],
+@@ -5169,20 +5566,22 @@
+ ])
+
+ # check for openpty, login_tty, and forkpty
+-
+-AC_CHECK_FUNCS([openpty], [],
+- [AC_CHECK_LIB([util], [openpty],
+- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"],
+- [AC_CHECK_LIB([bsd], [openpty],
+- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])])
+-AC_SEARCH_LIBS([login_tty], [util],
+- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])]
+-)
+-AC_CHECK_FUNCS([forkpty], [],
+- [AC_CHECK_LIB([util], [forkpty],
+- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"],
+- [AC_CHECK_LIB([bsd], [forkpty],
+- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])])
++# tvOS/watchOS have functions for tty, but can't use them
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([openpty], [],
++ [AC_CHECK_LIB([util], [openpty],
++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"],
++ [AC_CHECK_LIB([bsd], [openpty],
++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])])
++ AC_SEARCH_LIBS([login_tty], [util],
++ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])]
++ )
++ AC_CHECK_FUNCS([forkpty], [],
++ [AC_CHECK_LIB([util], [forkpty],
++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"],
++ [AC_CHECK_LIB([bsd], [forkpty],
++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])])
++fi
+
+ # check for long file support functions
+ AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs])
+@@ -5263,11 +5662,17 @@
+ ])
+ ])
+
+-AC_CHECK_FUNCS([clock_settime], [], [
+- AC_CHECK_LIB([rt], [clock_settime], [
+- AC_DEFINE([HAVE_CLOCK_SETTIME], [1])
+- ])
+-])
++# On iOS, tvOS and watchOS, clock_settime can be linked (so it is found by
++# configure), but when used in an unprivileged process, it crashes rather than
++# returning an error. Force the symbol off.
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS"
++then
++ AC_CHECK_FUNCS([clock_settime], [], [
++ AC_CHECK_LIB([rt], [clock_settime], [
++ AC_DEFINE([HAVE_CLOCK_SETTIME], [1])
++ ])
++ ])
++fi
+
+ AC_CHECK_FUNCS([clock_nanosleep], [], [
+ AC_CHECK_LIB([rt], [clock_nanosleep], [
+@@ -5413,7 +5818,9 @@
+ [ac_cv_buggy_getaddrinfo=no],
+ [ac_cv_buggy_getaddrinfo=yes],
+ [
+-if test "${enable_ipv6+set}" = set; then
++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then
++ ac_cv_buggy_getaddrinfo="no"
++elif test "${enable_ipv6+set}" = set; then
+ ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6"
+ else
+ ac_cv_buggy_getaddrinfo=yes
+@@ -5968,14 +6375,14 @@
+ AC_MSG_CHECKING([ABIFLAGS])
+ AC_MSG_RESULT([$ABIFLAGS])
+ AC_MSG_CHECKING([SOABI])
+-SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
++SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM}
+ AC_MSG_RESULT([$SOABI])
+
+ # Release and debug (Py_DEBUG) ABI are compatible, but not Py_TRACE_REFS ABI
+ if test "$Py_DEBUG" = 'true' -a "$with_trace_refs" != "yes"; then
# Similar to SOABI but remove "d" flag from ABIFLAGS
AC_SUBST([ALT_SOABI])
- ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET}
@@ -2234,14 +7452,78 @@ index ba768aea93..98d9a48918 100644
AC_DEFINE_UNQUOTED([ALT_SOABI], ["${ALT_SOABI}"],
[Alternative SOABI used in debug build to load C extensions built in release mode])
fi
-@@ -7208,6 +7352,30 @@
+@@ -6624,28 +7031,35 @@
+ AC_MSG_NOTICE([checking for device files])
+
+ dnl NOTE: Inform user how to proceed with files when cross compiling.
+-if test "x$cross_compiling" = xyes; then
+- if test "${ac_cv_file__dev_ptmx+set}" != set; then
+- AC_MSG_CHECKING([for /dev/ptmx])
+- AC_MSG_RESULT([not set])
+- AC_MSG_ERROR([set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling])
+- fi
+- if test "${ac_cv_file__dev_ptc+set}" != set; then
+- AC_MSG_CHECKING([for /dev/ptc])
+- AC_MSG_RESULT([not set])
+- AC_MSG_ERROR([set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling])
++dnl iOS cross-compile builds are predictable; they won't ever
++dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly.
++if test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then
++ ac_cv_file__dev_ptmx=no
++ ac_cv_file__dev_ptc=no
++else
++ if test "x$cross_compiling" = xyes; then
++ if test "${ac_cv_file__dev_ptmx+set}" != set; then
++ AC_MSG_CHECKING([for /dev/ptmx])
++ AC_MSG_RESULT([not set])
++ AC_MSG_ERROR([set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling])
++ fi
++ if test "${ac_cv_file__dev_ptc+set}" != set; then
++ AC_MSG_CHECKING([for /dev/ptc])
++ AC_MSG_RESULT([not set])
++ AC_MSG_ERROR([set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling])
++ fi
+ fi
+-fi
+
+-AC_CHECK_FILE([/dev/ptmx], [], [])
+-if test "x$ac_cv_file__dev_ptmx" = xyes; then
+- AC_DEFINE([HAVE_DEV_PTMX], [1],
+- [Define to 1 if you have the /dev/ptmx device file.])
+-fi
+-AC_CHECK_FILE([/dev/ptc], [], [])
+-if test "x$ac_cv_file__dev_ptc" = xyes; then
+- AC_DEFINE([HAVE_DEV_PTC], [1],
+- [Define to 1 if you have the /dev/ptc device file.])
++ AC_CHECK_FILE([/dev/ptmx], [], [])
++ if test "x$ac_cv_file__dev_ptmx" = xyes; then
++ AC_DEFINE([HAVE_DEV_PTMX], [1],
++ [Define to 1 if you have the /dev/ptmx device file.])
++ fi
++ AC_CHECK_FILE([/dev/ptc], [], [])
++ if test "x$ac_cv_file__dev_ptc" = xyes; then
++ AC_DEFINE([HAVE_DEV_PTC], [1],
++ [Define to 1 if you have the /dev/ptc device file.])
++ fi
+ fi
+
+ if test $ac_sys_system = Darwin
+@@ -6917,6 +7331,7 @@
+ AS_CASE([$ac_sys_system],
+ [Emscripten], [with_ensurepip=no],
+ [WASI], [with_ensurepip=no],
++ [iOS|tvOS|watchOS], [with_ensurepip=no],
+ [with_ensurepip=upgrade]
+ )
+ ])
+@@ -7259,6 +7674,28 @@
[AIX], [PY_STDLIB_MOD_SET_NA([_scproxy], [spwd])],
[VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [_crypt], [termios], [grp])],
[Darwin], [PY_STDLIB_MOD_SET_NA([ossaudiodev], [spwd])],
+ [iOS|tvOS|watchOS], [
+ dnl subprocess and multiprocessing are not supported (no fork syscall).
+ dnl curses and tkinter user interface are not available.
-+ dnl gdbm, and nis aren't available
++ dnl gdbm and nis aren't available
+ dnl Stub implementations are provided for pwd, grp etc APIs
+ PY_STDLIB_MOD_SET_NA(
+ [_curses],
@@ -2252,16 +7534,1931 @@ index ba768aea93..98d9a48918 100644
+ [_posixsubprocess],
+ [_scproxy],
+ [_tkinter],
-+ [_xxsubinterpreters],
+ [grp],
+ [nis],
-+ [ossaudiodev],
+ [readline],
+ [pwd],
+ [spwd],
+ [syslog],
+ )
+ ],
- [CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
- [QNX*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
- [FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy], [spwd])],
+ [CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
+ [QNX*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
+ [FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy], [spwd])],
+--- /dev/null
++++ b/iOS/README.rst
+@@ -0,0 +1,385 @@
++====================
++Python on iOS README
++====================
++
++:Authors:
++ Russell Keith-Magee (2023-11)
++
++This document provides a quick overview of some iOS specific features in the
++Python distribution.
++
++These instructions are only needed if you're planning to compile Python for iOS
++yourself. Most users should *not* need to do this. If you're looking to
++experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase
++`__ and `Kivy's Buildozer
++`__ will provide a much more approachable
++user experience.
++
++Compilers for building on iOS
++=============================
++
++Building for iOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode. This will
++require the use of the most (or second-most) recently released macOS version,
++as Apple does not maintain Xcode for older macOS versions. The Xcode Command
++Line Tools are not sufficient for iOS development; you need a *full* Xcode
++install.
++
++If you want to run your code on the iOS simulator, you'll also need to install
++an iOS Simulator Platform. You should be prompted to select an iOS Simulator
++Platform when you first run Xcode. Alternatively, you can add an iOS Simulator
++Platform by selecting an open the Platforms tab of the Xcode Settings panel.
++
++iOS specific arguments to configure
++===================================
++
++* ``--enable-framework[=DIR]``
++
++ This argument specifies the location where the Python.framework will be
++ installed. If ``DIR`` is not specified, the framework will be installed into
++ a subdirectory of the ``iOS/Frameworks`` folder.
++
++ This argument *must* be provided when configuring iOS builds. iOS does not
++ support non-framework builds.
++
++* ``--with-framework-name=NAME``
++
++ Specify the name for the Python framework; defaults to ``Python``.
++
++ .. admonition:: Use this option with care!
++
++ Unless you know what you're doing, changing the name of the Python
++ framework on iOS is not advised. If you use this option, you won't be able
++ to run the ``make testios`` target without making signficant manual
++ alterations, and you won't be able to use any binary packages unless you
++ compile them yourself using your own framework name.
++
++Building Python on iOS
++======================
++
++ABIs and Architectures
++----------------------
++
++iOS apps can be deployed on physical devices, and on the iOS simulator. Although
++the API used on these devices is identical, the ABI is different - you need to
++link against different libraries for an iOS device build (``iphoneos``) or an
++iOS simulator build (``iphonesimulator``).
++
++Apple uses the ``XCframework`` format to allow specifying a single dependency
++that supports multiple ABIs. An ``XCframework`` is a wrapper around multiple
++ABI-specific frameworks that share a common API.
++
++iOS can also support different CPU architectures within each ABI. At present,
++there is only a single supported architecture on physical devices - ARM64.
++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
++Silicon machines), and x86_64 (for running on older Intel-based machines).
++
++To support multiple CPU architectures on a single platform, Apple uses a "fat
++binary" format - a single physical file that contains support for multiple
++architectures. It is possible to compile and use a "thin" single architecture
++version of a binary for testing purposes; however, the "thin" binary will not be
++portable to machines using other architectures.
++
++Building a single-architecture framework
++----------------------------------------
++
++The Python build system will create a ``Python.framework`` that supports a
++*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a
++framework to contain non-library content, so the iOS build will produce a
++``bin`` and ``lib`` folder in the same output folder as ``Python.framework``.
++The ``lib`` folder will be needed at runtime to support the Python library.
++
++If you want to use Python in a real iOS project, you need to produce multiple
++``Python.framework`` builds, one for each ABI and architecture. iOS builds of
++Python *must* be constructed as framework builds. To support this, you must
++provide the ``--enable-framework`` flag when configuring the build. The build
++also requires the use of cross-compilation. The minimal commands for building
++Python for the ARM64 iOS simulator will look something like::
++
++ $ export PATH="$(pwd)/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
++ $ ./configure \
++ --enable-framework \
++ --host=arm64-apple-ios-simulator \
++ --build=arm64-apple-darwin \
++ --with-build-python=/path/to/python.exe
++ $ make
++ $ make install
++
++In this invocation:
++
++* ``iOS/Resources/bin`` has been added to the path, providing some shims for the
++ compilers and linkers needed by the build. Xcode requires the use of ``xcrun``
++ to invoke compiler tooling. However, if ``xcrun`` is pre-evaluated and the
++ result passed to ``configure``, these results can embed user- and
++ version-specific paths into the sysconfig data, which limits the portability
++ of the compiled Python. Alternatively, if ``xcrun`` is used *as* the compiler,
++ it requires that compiler variables like ``CC`` include spaces, which can
++ cause significant problems with many C configuration systems which assume that
++ ``CC`` will be a single executable.
++
++ To work around this problem, the ``iOS/Resources/bin`` folder contains some
++ wrapper scripts that present as simple compilers and linkers, but wrap
++ underlying calls to ``xcrun``. This allows configure to use a ``CC``
++ definition without spaces, and without user- or version-specific paths, while
++ retaining the ability to adapt to the local Xcode install. These scripts are
++ included in the ``bin`` directory of an iOS install.
++
++ These scripts will, by default, use the currently active Xcode installation.
++ If you want to use a different Xcode installation, you can use
++ ``xcode-select`` to set a new default Xcode globally, or you can use the
++ ``DEVELOPER_DIR`` environment variable to specify an Xcode install. The
++ scripts will use the default ``iphoneos``/``iphonesimulator`` SDK version for
++ the select Xcode install; if you want to use a different SDK, you can set the
++ ``IOS_SDK_VERSION`` environment variable. (e.g, setting
++ ``IOS_SDK_VERSION=17.1`` would cause the scripts to use the ``iphoneos17.1``
++ and ``iphonesimulator17.1`` SDKs, regardless of the Xcode default.)
++
++ The path has also been cleared of any user customizations. A common source of
++ bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS
++ build. Resetting the path to a known "bare bones" value is the easiest way to
++ avoid these problems.
++
++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
++ triple format. This will be one of:
++
++ - ``arm64-apple-ios`` for ARM64 iOS devices.
++ - ``arm64-apple-ios-simulator`` for the iOS simulator running on Apple
++ Silicon devices.
++ - ``x86_64-apple-ios-simulator`` for the iOS simulator running on Intel
++ devices.
++
++* ``--build`` is the GNU compiler triple for the machine that will be running
++ the compiler. This is one of:
++
++ - ``arm64-apple-darwin`` for Apple Silicon devices.
++ - ``x86_64-apple-darwin`` for Intel devices.
++
++* ``/path/to/python.exe`` is the path to a Python binary on the machine that
++ will be running the compiler. This is needed because the Python compilation
++ process involves running some Python code. On a normal desktop build of
++ Python, you can compile a python interpreter and then use that interpreter to
++ run Python code. However, the binaries produced for iOS won't run on macOS, so
++ you need to provide an external Python interpreter. This interpreter must be
++ the same version as the Python that is being compiled. To be completely safe,
++ this should be the *exact* same commit hash. However, the longer a Python
++ release has been stable, the more likely it is that this constraint can be
++ relaxed - the same micro version will often be sufficient.
++
++* The ``install`` target for iOS builds is slightly different to other
++ platforms. On most platforms, ``make install`` will install the build into
++ the final runtime location. This won't be the case for iOS, as the final
++ runtime location will be on a physical device.
++
++ However, you still need to run the ``install`` target for iOS builds, as it
++ performs some final framework assembly steps. The location specified with
++ ``--enable-framework`` will be the location where ``make install`` will
++ assemble the complete iOS framework. This completed framework can then
++ be copied and relocated as required.
++
++For a full CPython build, you also need to specify the paths to iOS builds of
++the binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL).
++This can be done by defining the ``LIBLZMA_CFLAGS``, ``LIBLZMA_LIBS``,
++``BZIP2_CFLAGS``, ``BZIP2_LIBS``, ``LIBFFI_CFLAGS``, and ``LIBFFI_LIBS``
++environment variables, and the ``--with-openssl`` configure option. Versions of
++these libraries pre-compiled for iOS can be found in `this repository
++`__. LibFFI is
++especially important, as many parts of the standard library (including the
++``platform``, ``sysconfig`` and ``webbrowser`` modules) require the use of the
++``ctypes`` module at runtime.
++
++By default, Python will be compiled with an iOS deployment target (i.e., the
++minimum supported iOS version) of 13.0. To specify a different deployment
++target, provide the version number as part of the ``--host`` argument - for
++example, ``--host=arm64-apple-ios15.4-simulator`` would compile an ARM64
++simulator build with a deployment target of 15.4.
++
++Merge thin frameworks into fat frameworks
++-----------------------------------------
++
++Once you've built a ``Python.framework`` for each ABI and and architecture, you
++must produce a "fat" framework for each ABI that contains all the architectures
++for that ABI.
++
++The ``iphoneos`` build only needs to support a single architecture, so it can be
++used without modification.
++
++If you only want to support a single simulator architecture, (e.g., only support
++ARM64 simulators), you can use a single architecture ``Python.framework`` build.
++However, if you want to create ``Python.xcframework`` that supports *all*
++architectures, you'll need to merge the ``iphonesimulator`` builds for ARM64 and
++x86_64 into a single "fat" framework.
++
++The "fat" framework can be constructed by performing a directory merge of the
++content of the two "thin" ``Python.framework`` directories, plus the ``bin`` and
++``lib`` folders for each thin framework. When performing this merge:
++
++* The pure Python standard library content is identical for each architecture,
++ except for a handful of platform-specific files (such as the ``sysconfig``
++ module). Ensure that the "fat" framework has the union of all standard library
++ files.
++
++* Any binary files in the standard library, plus the main
++ ``libPython3.X.dylib``, can be merged using the ``lipo`` tool, provide by
++ Xcode::
++
++ $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib
++
++* The header files will be indentical on both architectures, except for
++ ``pyconfig.h``. Copy all the headers from one platform (say, arm64), rename
++ ``pyconfig.h`` to ``pyconfig-arm64.h``, and copy the ``pyconfig.h`` for the
++ other architecture into the merged header folder as ``pyconfig-x86_64.h``.
++ Then copy the ``iOS/Resources/pyconfig.h`` file from the CPython sources into
++ the merged headers folder. This will allow the two Python architectures to
++ share a common ``pyconfig.h`` header file.
++
++At this point, you should have 2 Python.framework folders - one for ``iphoneos``,
++and one for ``iphonesimulator`` that is a merge of x86+64 and ARM64 content.
++
++Merge frameworks into an XCframework
++------------------------------------
++
++Now that we have 2 (potentially fat) ABI-specific frameworks, we can merge those
++frameworks into a single ``XCframework``.
++
++The initial skeleton of an ``XCframework`` is built using::
++
++ xcodebuild -create-xcframework -output Python.xcframework -framework path/to/iphoneos/Python.framework -framework path/to/iphonesimulator/Python.framework
++
++Then, copy the ``bin`` and ``lib`` folders into the architecture-specific slices of
++the XCframework::
++
++ cp path/to/iphoneos/bin Python.xcframework/ios-arm64
++ cp path/to/iphoneos/lib Python.xcframework/ios-arm64
++
++ cp path/to/iphonesimulator/bin Python.xcframework/ios-arm64_x86_64-simulator
++ cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64_x86_64-simulator
++
++Note that the name of the architecture-specific slice for the simulator will
++depend on the CPU architecture(s) that you build.
++
++You now have a Python.xcframework that can be used in a project.
++
++Testing Python on iOS
++=====================
++
++The ``iOS/testbed`` folder that contains an Xcode project that is able to run
++the iOS test suite. This project converts the Python test suite into a single
++test case in Xcode's XCTest framework. The single XCTest passes if the test
++suite passes.
++
++To run the test suite, configure a Python build for an iOS simulator (i.e.,
++``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator``
++), specifying a framework build (i.e. ``--enable-framework``). Ensure that your
++``PATH`` has been configured to include the ``iOS/Resources/bin`` folder and
++exclude any non-iOS tools, then run::
++
++ $ make all
++ $ make install
++ $ make testios
++
++This will:
++
++* Build an iOS framework for your chosen architecture;
++* Finalize the single-platform framework;
++* Make a clean copy of the testbed project;
++* Install the Python iOS framework into the copy of the testbed project; and
++* Run the test suite on an "iPhone SE (3rd generation)" simulator.
++
++While the test suite is running, Xcode does not display any console output.
++After showing some Xcode build commands, the console output will print ``Testing
++started``, and then appear to stop. It will remain in this state until the test
++suite completes. On a 2022 M1 MacBook Pro, the test suite takes approximately 12
++minutes to run; a couple of extra minutes is required to boot and prepare the
++iOS simulator.
++
++On success, the test suite will exit and report successful completion of the
++test suite. No output of the Python test suite will be displayed.
++
++On failure, the output of the Python test suite *will* be displayed. This will
++show the details of the tests that failed.
++
++Debugging test failures
++-----------------------
++
++The easiest way to diagnose a single test failure is to open the testbed project
++in Xcode and run the tests from there using the "Product > Test" menu item.
++
++To test in Xcode, you must ensure the testbed project has a copy of a compiled
++framework. If you've configured your build with the default install location of
++``iOS/Frameworks``, you can copy from that location into the test project. To
++test on an ARM64 simulator, run::
++
++ $ rm -rf iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator/*
++ $ cp -r iOS/Frameworks/arm64-iphonesimulator/* iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator
++
++To test on an x86-64 simulator, run::
++
++ $ rm -rf iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator/*
++ $ cp -r iOS/Frameworks/x86_64-iphonesimulator/* iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator
++
++To test on a physical device::
++
++ $ rm -rf iOS/testbed/Python.xcframework/ios-arm64/*
++ $ cp -r iOS/Frameworks/arm64-iphoneos/* iOS/testbed/Python.xcframework/ios-arm64
++
++Alternatively, you can configure your build to install directly into the
++testbed project. For a simulator, use::
++
++ --enable-framework=$(pwd)/iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator
++
++For a physical device, use::
++
++ --enable-framework=$(pwd)/iOS/testbed/Python.xcframework/ios-arm64
++
++
++Testing on an iOS device
++^^^^^^^^^^^^^^^^^^^^^^^^
++
++To test on an iOS device, the app needs to be signed with known developer
++credentials. To obtain these credentials, you must have an iOS Developer
++account, and your Xcode install will need to be logged into your account (see
++the Accounts tab of the Preferences dialog).
++
++Once the project is open, and you're signed into your Apple Developer account,
++select the root node of the project tree (labeled "iOSTestbed"), then the
++"Signing & Capabilities" tab in the details page. Select a development team
++(this will likely be your own name), and plug in a physical device to your
++macOS machine with a USB cable. You should then be able to select your physical
++device from the list of targets in the pulldown in the Xcode titlebar.
++
++Running specific tests
++^^^^^^^^^^^^^^^^^^^^^^
++
++As the test suite is being executed on an iOS simulator, it is not possible to
++pass in command line arguments to configure test suite operation. To work around
++this limitation, the arguments that would normally be passed as command line
++arguments are configured as a static string at the start of the XCTest method
++``- (void)testPython`` in ``iOSTestbedTests.m``. To pass an argument to the test
++suite, add a a string to the ``argv`` defintion. These arguments will be passed
++to the test suite as if they had been passed to ``python -m test`` at the
++command line.
++
++Disabling automated breakpoints
++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++
++By default, Xcode will inserts an automatic breakpoint whenever a signal is
++raised. The Python test suite raises many of these signals as part of normal
++operation; unless you are trying to diagnose an issue with signals, the
++automatic breakpoints can be inconvenient. However, they can be disabled by
++creating a symbolic breakpoint that is triggered at the start of the test run.
++
++Select "Debug > Breakpoints > Create Symbolic Breakpoint" from the Xcode menu, and
++populate the new brewpoint with the following details:
++
++* **Name**: IgnoreSignals
++* **Symbol**: UIApplicationMain
++* **Action**: Add debugger commands for:
++ - ``process handle SIGINT -n true -p true -s false``
++ - ``process handle SIGUSR1 -n true -p true -s false``
++ - ``process handle SIGUSR2 -n true -p true -s false``
++ - ``process handle SIGXFSZ -n true -p true -s false``
++* Check the "Automatically continue after evaluating" box.
++
++All other details can be left blank. When the process executes the
++``UIApplicationMain`` entry point, the breakpoint will trigger, run the debugger
++commands to disable the automatic breakpoints, and automatically resume.
+--- /dev/null
++++ b/iOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2024 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ %VERSION%
++ CFBundleSupportedPlatforms
++
++ iPhoneOS
++
++ MinimumOSVersion
++ @IPHONEOS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-ar
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphoneos${IOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-clang
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios $@
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-cpp
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios -E $@
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator $@
+--- /dev/null
++++ b/iOS/Resources/bin/arm64-apple-ios-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator -E $@
+--- /dev/null
++++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator $@
+--- /dev/null
++++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator -E $@
+--- /dev/null
++++ b/iOS/Resources/dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ iPhoneOS
++
++ MinimumOSVersion
++ 12.0
++ CFBundleVersion
++ 1
++
++
+--- /dev/null
++++ b/iOS/Resources/pyconfig.h
+@@ -0,0 +1,7 @@
++#ifdef __arm64__
++#include "pyconfig-arm64.h"
++#endif
++
++#ifdef __x86_64__
++#include "pyconfig-x86_64.h"
++#endif
+--- /dev/null
++++ b/iOS/testbed/Python.xcframework/Info.plist
+@@ -0,0 +1,44 @@
++
++
++
++
++ AvailableLibraries
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ ios-arm64
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++
++ SupportedPlatform
++ ios
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ ios-arm64_x86_64-simulator
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++ x86_64
++
++ SupportedPlatform
++ ios
++ SupportedPlatformVariant
++ simulator
++
++
++ CFBundlePackageType
++ XFWK
++ XCFrameworkFormatVersion
++ 1.0
++
++
+--- /dev/null
++++ b/iOS/testbed/Python.xcframework/ios-arm64/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling an iOS on-device
++build for testing purposes.
+--- /dev/null
++++ b/iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling an iOS simulator
++build for testing purposes (either x86_64 or ARM64).
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed.xcodeproj/project.pbxproj
+@@ -0,0 +1,570 @@
++// !$*UTF8*$!
++{
++ archiveVersion = 1;
++ classes = {
++ };
++ objectVersion = 56;
++ objects = {
++
++/* Begin PBXBuildFile section */
++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; };
++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; };
++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; };
++ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; };
++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; };
++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; };
++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; };
++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; };
++/* End PBXBuildFile section */
++
++/* Begin PBXContainerItemProxy section */
++ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = {
++ isa = PBXContainerItemProxy;
++ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */;
++ proxyType = 1;
++ remoteGlobalIDString = 607A66112B0EFA380010BFC8;
++ remoteInfo = iOSTestbed;
++ };
++/* End PBXContainerItemProxy section */
++
++/* Begin PBXCopyFilesBuildPhase section */
++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = {
++ isa = PBXCopyFilesBuildPhase;
++ buildActionMask = 2147483647;
++ dstPath = "";
++ dstSubfolderSpec = 10;
++ files = (
++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */,
++ );
++ name = "Embed Frameworks";
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = {
++ isa = PBXCopyFilesBuildPhase;
++ buildActionMask = 2147483647;
++ dstPath = "";
++ dstSubfolderSpec = 10;
++ files = (
++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */,
++ );
++ name = "Embed Frameworks";
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXCopyFilesBuildPhase section */
++
++/* Begin PBXFileReference section */
++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; };
++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
++ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
++ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; };
++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; };
++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; };
++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; };
++/* End PBXFileReference section */
++
++/* Begin PBXFrameworksBuildPhase section */
++ 607A660F2B0EFA380010BFC8 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXFrameworksBuildPhase section */
++
++/* Begin PBXGroup section */
++ 607A66092B0EFA380010BFC8 = {
++ isa = PBXGroup;
++ children = (
++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */,
++ 607A66142B0EFA380010BFC8 /* iOSTestbed */,
++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */,
++ 607A66132B0EFA380010BFC8 /* Products */,
++ 607A664F2B0EFFE00010BFC8 /* Frameworks */,
++ );
++ sourceTree = "";
++ };
++ 607A66132B0EFA380010BFC8 /* Products */ = {
++ isa = PBXGroup;
++ children = (
++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */,
++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */,
++ );
++ name = Products;
++ sourceTree = "";
++ };
++ 607A66142B0EFA380010BFC8 /* iOSTestbed */ = {
++ isa = PBXGroup;
++ children = (
++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */,
++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */,
++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */,
++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */,
++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */,
++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */,
++ 607A66272B0EFA390010BFC8 /* main.m */,
++ );
++ path = iOSTestbed;
++ sourceTree = "";
++ };
++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = {
++ isa = PBXGroup;
++ children = (
++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */,
++ );
++ path = iOSTestbedTests;
++ sourceTree = "";
++ };
++ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = {
++ isa = PBXGroup;
++ children = (
++ );
++ name = Frameworks;
++ sourceTree = "";
++ };
++/* End PBXGroup section */
++
++/* Begin PBXNativeTarget section */
++ 607A66112B0EFA380010BFC8 /* iOSTestbed */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */;
++ buildPhases = (
++ 607A660E2B0EFA380010BFC8 /* Sources */,
++ 607A660F2B0EFA380010BFC8 /* Frameworks */,
++ 607A66102B0EFA380010BFC8 /* Resources */,
++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */,
++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */,
++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ );
++ name = iOSTestbed;
++ productName = iOSTestbed;
++ productReference = 607A66122B0EFA380010BFC8 /* iOSTestbed.app */;
++ productType = "com.apple.product-type.application";
++ };
++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */;
++ buildPhases = (
++ 607A66292B0EFA3A0010BFC8 /* Sources */,
++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */,
++ 607A662B2B0EFA3A0010BFC8 /* Resources */,
++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */,
++ );
++ name = iOSTestbedTests;
++ productName = iOSTestbedTests;
++ productReference = 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */;
++ productType = "com.apple.product-type.bundle.unit-test";
++ };
++/* End PBXNativeTarget section */
++
++/* Begin PBXProject section */
++ 607A660A2B0EFA380010BFC8 /* Project object */ = {
++ isa = PBXProject;
++ attributes = {
++ BuildIndependentTargetsInParallel = 1;
++ LastUpgradeCheck = 1500;
++ TargetAttributes = {
++ 607A66112B0EFA380010BFC8 = {
++ CreatedOnToolsVersion = 15.0.1;
++ };
++ 607A662C2B0EFA3A0010BFC8 = {
++ CreatedOnToolsVersion = 15.0.1;
++ TestTargetID = 607A66112B0EFA380010BFC8;
++ };
++ };
++ };
++ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */;
++ compatibilityVersion = "Xcode 14.0";
++ developmentRegion = en;
++ hasScannedForEncodings = 0;
++ knownRegions = (
++ en,
++ Base,
++ );
++ mainGroup = 607A66092B0EFA380010BFC8;
++ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */;
++ projectDirPath = "";
++ projectRoot = "";
++ targets = (
++ 607A66112B0EFA380010BFC8 /* iOSTestbed */,
++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */,
++ );
++ };
++/* End PBXProject section */
++
++/* Begin PBXResourcesBuildPhase section */
++ 607A66102B0EFA380010BFC8 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */,
++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */,
++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A662B2B0EFA3A0010BFC8 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXResourcesBuildPhase section */
++
++/* Begin PBXShellScriptBuildPhase section */
++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = {
++ isa = PBXShellScriptBuildPhase;
++ alwaysOutOfDate = 1;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ inputFileListPaths = (
++ );
++ inputPaths = (
++ );
++ name = "Install Target Specific Python Standard Library";
++ outputFileListPaths = (
++ );
++ outputPaths = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ shellPath = /bin/sh;
++ shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n";
++ };
++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = {
++ isa = PBXShellScriptBuildPhase;
++ alwaysOutOfDate = 1;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ inputFileListPaths = (
++ );
++ inputPaths = (
++ );
++ name = "Prepare Python Binary Modules";
++ outputFileListPaths = (
++ );
++ outputPaths = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ shellPath = /bin/sh;
++ shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_EXT=$2\n\n # The name of the extension file\n EXT=$(basename \"$FULL_EXT\")\n # The location of the extension file, relative to the bundle\n RELATIVE_EXT=${FULL_EXT#$CODESIGNING_FOLDER_PATH/} \n # The path to the extension file, relative to the install base\n PYTHON_EXT=${RELATIVE_EXT/$INSTALL_BASE/}\n # The full dotted name of the extension module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $PYTHON_EXT | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_EXT\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleExecutable -string \"$FULL_MODULE_NAME\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n plutil -replace CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n fi\n \n echo \"Installing binary for $FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" \n mv \"$FULL_EXT\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\"\n # Create a placeholder .fwork file where the .so was\n echo \"$FRAMEWORK_FOLDER/$FULL_MODULE_NAME\" > ${FULL_EXT%.so}.fwork\n # Create a back reference to the .so file location in the framework\n echo \"${RELATIVE_EXT%.so}.fwork\" > \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/$FULL_MODULE_NAME.origin\" \n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library extension modules...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.so\" | while read FULL_EXT; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload/ \"$FULL_EXT\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$CODESIGNING_FOLDER_PATH/Frameworks\" -name \"*.framework\" -exec /usr/bin/codesign --force --sign \"$EXPANDED_CODE_SIGN_IDENTITY\" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der \"{}\" \\; \n";
++ };
++/* End PBXShellScriptBuildPhase section */
++
++/* Begin PBXSourcesBuildPhase section */
++ 607A660E2B0EFA380010BFC8 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */,
++ 607A66282B0EFA390010BFC8 /* main.m in Sources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A66292B0EFA3A0010BFC8 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXSourcesBuildPhase section */
++
++/* Begin PBXTargetDependency section */
++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = {
++ isa = PBXTargetDependency;
++ target = 607A66112B0EFA380010BFC8 /* iOSTestbed */;
++ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */;
++ };
++/* End PBXTargetDependency section */
++
++/* Begin PBXVariantGroup section */
++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */ = {
++ isa = PBXVariantGroup;
++ children = (
++ 607A66242B0EFA390010BFC8 /* Base */,
++ );
++ name = LaunchScreen.storyboard;
++ sourceTree = "";
++ };
++/* End PBXVariantGroup section */
++
++/* Begin XCBuildConfiguration section */
++ 607A663F2B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = dwarf;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = YES;
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_DYNAMIC_NO_PIC = NO;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_OPTIMIZATION_LEVEL = 0;
++ GCC_PREPROCESSOR_DEFINITIONS = (
++ "DEBUG=1",
++ "$(inherited)",
++ );
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
++ MTL_FAST_MATH = YES;
++ ONLY_ACTIVE_ARCH = YES;
++ SDKROOT = iphoneos;
++ };
++ name = Debug;
++ };
++ 607A66402B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
++ ENABLE_NS_ASSERTIONS = NO;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = YES;
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = NO;
++ MTL_FAST_MATH = YES;
++ SDKROOT = iphoneos;
++ VALIDATE_PRODUCT = YES;
++ };
++ name = Release;
++ };
++ 607A66422B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = "";
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist";
++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 3.13.0a1;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = "1,2";
++ };
++ name = Debug;
++ };
++ 607A66432B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = "";
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist";
++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 3.13.0a1;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = "1,2";
++ };
++ name = Release;
++ };
++ 607A66452B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = 3HEZE76D99;
++ GENERATE_INFOPLIST_FILE = YES;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = "1,2";
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed";
++ };
++ name = Debug;
++ };
++ 607A66462B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = 3HEZE76D99;
++ GENERATE_INFOPLIST_FILE = YES;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = "1,2";
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed";
++ };
++ name = Release;
++ };
++/* End XCBuildConfiguration section */
++
++/* Begin XCConfigurationList section */
++ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A663F2B0EFA3A0010BFC8 /* Debug */,
++ 607A66402B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A66422B0EFA3A0010BFC8 /* Debug */,
++ 607A66432B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A66452B0EFA3A0010BFC8 /* Debug */,
++ 607A66462B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++/* End XCConfigurationList section */
++ };
++ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */;
++}
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/AppDelegate.h
+@@ -0,0 +1,11 @@
++//
++// AppDelegate.h
++// iOSTestbed
++//
++
++#import
++
++@interface AppDelegate : UIResponder
++
++
++@end
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/AppDelegate.m
+@@ -0,0 +1,19 @@
++//
++// AppDelegate.m
++// iOSTestbed
++//
++
++#import "AppDelegate.h"
++
++@interface AppDelegate ()
++
++@end
++
++@implementation AppDelegate
++
++
++- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
++ return YES;
++}
++
++@end
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json
+@@ -0,0 +1,11 @@
++{
++ "colors" : [
++ {
++ "idiom" : "universal"
++ }
++ ],
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json
+@@ -0,0 +1,13 @@
++{
++ "images" : [
++ {
++ "idiom" : "universal",
++ "platform" : "ios",
++ "size" : "1024x1024"
++ }
++ ],
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/Assets.xcassets/Contents.json
+@@ -0,0 +1,6 @@
++{
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/Base.lproj/LaunchScreen.storyboard
+@@ -0,0 +1,9 @@
++
++
++
++
++
++
++
++
++
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ iPhoneOS
++
++ MinimumOSVersion
++ 12.0
++ CFBundleVersion
++ 1
++
++
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/iOSTestbed-Info.plist
+@@ -0,0 +1,54 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleDisplayName
++ ${PRODUCT_NAME}
++ CFBundleExecutable
++ ${EXECUTABLE_NAME}
++ CFBundleIdentifier
++ org.python.iOSTestbed
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ ${PRODUCT_NAME}
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ 1
++ LSRequiresIPhoneOS
++
++ UIRequiresFullScreen
++
++ UILaunchStoryboardName
++ Launch Screen
++ UISupportedInterfaceOrientations
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++ UISupportedInterfaceOrientations~ipad
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationPortraitUpsideDown
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++ MainModule
++ ios
++ UIApplicationSceneManifest
++
++ UIApplicationSupportsMultipleScenes
++
++ UISceneConfigurations
++
++
++
++
+--- /dev/null
++++ b/iOS/testbed/iOSTestbed/main.m
+@@ -0,0 +1,16 @@
++//
++// main.m
++// iOSTestbed
++//
++
++#import
++#import "AppDelegate.h"
++
++int main(int argc, char * argv[]) {
++ NSString * appDelegateClassName;
++ @autoreleasepool {
++ appDelegateClassName = NSStringFromClass([AppDelegate class]);
++
++ return UIApplicationMain(argc, argv, nil, appDelegateClassName);
++ }
++}
+--- /dev/null
++++ b/iOS/testbed/iOSTestbedTests/iOSTestbedTests.m
+@@ -0,0 +1,111 @@
++#import
++#import
++
++@interface iOSTestbedTests : XCTestCase
++
++@end
++
++@implementation iOSTestbedTests
++
++
++- (void)testPython {
++ // Arguments to pass into the test suite runner.
++ // argv[0] must identify the process; any subsequent arg
++ // will be handled as if it were an argument to `python -m test`
++ const char *argv[] = {
++ "iOSTestbed", // argv[0] is the process that is running.
++ "-uall", // Enable all resources
++ "-W", // Display test output on failure
++ // To run a subset of tests, add the test names below; e.g.,
++ // "test_os",
++ // "test_sys",
++ };
++
++ // Start a Python interpreter.
++ int exit_code;
++ PyStatus status;
++ PyPreConfig preconfig;
++ PyConfig config;
++ NSString *python_home;
++ wchar_t *wtmp_str;
++
++ NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
++
++ // Generate an isolated Python configuration.
++ NSLog(@"Configuring isolated Python...");
++ PyPreConfig_InitIsolatedConfig(&preconfig);
++ PyConfig_InitIsolatedConfig(&config);
++
++ // Configure the Python interpreter:
++ // Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale.
++ // See https://docs.python.org/3/library/os.html#python-utf-8-mode.
++ preconfig.utf8_mode = 1;
++ // Don't buffer stdio. We want output to appears in the log immediately
++ config.buffered_stdio = 0;
++ // Don't write bytecode; we can't modify the app bundle
++ // after it has been signed.
++ config.write_bytecode = 0;
++ // Ensure that signal handlers are installed
++ config.install_signal_handlers = 1;
++ // Run the test module.
++ config.run_module = Py_DecodeLocale("test", NULL);
++ // For debugging - enable verbose mode.
++ // config.verbose = 1;
++
++ NSLog(@"Pre-initializing Python runtime...");
++ status = Py_PreInitialize(&preconfig);
++ if (PyStatus_Exception(status)) {
++ XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg);
++ PyConfig_Clear(&config);
++ return;
++ }
++
++ // Set the home for the Python interpreter
++ python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil];
++ NSLog(@"PythonHome: %@", python_home);
++ wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL);
++ status = PyConfig_SetString(&config, &config.home, wtmp_str);
++ if (PyStatus_Exception(status)) {
++ XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg);
++ PyConfig_Clear(&config);
++ return;
++ }
++ PyMem_RawFree(wtmp_str);
++
++ // Read the site config
++ status = PyConfig_Read(&config);
++ if (PyStatus_Exception(status)) {
++ XCTFail(@"Unable to read site config: %s", status.err_msg);
++ PyConfig_Clear(&config);
++ return;
++ }
++
++ NSLog(@"Configure argc/argv...");
++ status = PyConfig_SetBytesArgv(&config, sizeof(argv) / sizeof(char *), (char**) argv);
++ if (PyStatus_Exception(status)) {
++ XCTFail(@"Unable to configure argc/argv: %s", status.err_msg);
++ PyConfig_Clear(&config);
++ return;
++ }
++
++ NSLog(@"Initializing Python runtime...");
++ status = Py_InitializeFromConfig(&config);
++ if (PyStatus_Exception(status)) {
++ XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg);
++ PyConfig_Clear(&config);
++ return;
++ }
++
++ // Start the test suite. Print a separator to differentiate Python startup logs from app logs
++ NSLog(@"---------------------------------------------------------------------------");
++
++ exit_code = Py_RunMain();
++ XCTAssertEqual(exit_code, 0, @"Python test suite did not pass");
++
++ NSLog(@"---------------------------------------------------------------------------");
++
++ Py_Finalize();
++}
++
++
++@end
+--- /dev/null
++++ b/tvOS/README.rst
+@@ -0,0 +1,108 @@
++=====================
++Python on tvOS README
++=====================
++
++:Authors:
++ Russell Keith-Magee (2023-11)
++
++This document provides a quick overview of some tvOS specific features in the
++Python distribution.
++
++Compilers for building on tvOS
++==============================
++
++Building for tvOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode, on the
++most recently released macOS.
++
++tvOS specific arguments to configure
++===================================
++
++* ``--enable-framework[=DIR]``
++
++ This argument specifies the location where the Python.framework will
++ be installed.
++
++* ``--with-framework-name=NAME``
++
++ Specify the name for the python framework, defaults to ``Python``.
++
++
++Building and using Python on tvOS
++=================================
++
++ABIs and Architectures
++----------------------
++
++tvOS apps can be deployed on physical devices, and on the tvOS simulator.
++Although the API used on these devices is identical, the ABI is different - you
++need to link against different libraries for an tvOS device build
++(``appletvos``) or an tvOS simulator build (``appletvsimulator``). Apple uses
++the XCframework format to allow specifying a single dependency that supports
++multiple ABIs. An XCframework is a wrapper around multiple ABI-specific
++frameworks.
++
++tvOS can also support different CPU architectures within each ABI. At present,
++there is only a single support ed architecture on physical devices - ARM64.
++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
++Silicon machines), and x86_64 (for running on older Intel-based machines.)
++
++To support multiple CPU architectures on a single platform, Apple uses a "fat
++binary" format - a single physical file that contains support for multiple
++architectures.
++
++How do I build Python for tvOS?
++-------------------------------
++
++The Python build system will build a ``Python.framework`` that supports a
++*single* ABI with a *single* architecture. If you want to use Python in an tvOS
++project, you need to:
++
++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture;
++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary;
++3. Merge the "fat" frameworks for each ABI into a single XCframework.
++
++tvOS builds of Python *must* be constructed as framework builds. To support this,
++you must provide the ``--enable-framework`` flag when configuring the build.
++
++The build also requires the use of cross-compilation. The commands for building
++Python for tvOS will look somethign like::
++
++ $ ./configure \
++ --enable-framework=/path/to/install \
++ --host=aarch64-apple-tvos \
++ --build=aarch64-apple-darwin \
++ --with-build-python=/path/to/python.exe
++ $ make
++ $ make install
++
++In this invocation:
++
++* ``/path/to/install`` is the location where the final Python.framework will be
++ output.
++
++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
++ triple format. This will be one of:
++
++ - ``aarch64-apple-tvos`` for ARM64 tvOS devices.
++ - ``aarch64-apple-tvos-simulator`` for the tvOS simulator running on Apple
++ Silicon devices.
++ - ``x86_64-apple-tvos-simulator`` for the tvOS simulator running on Intel
++ devices.
++
++* ``--build`` is the GNU compiler triple for the machine that will be running
++ the compiler. This is one of:
++
++ - ``aarch64-apple-darwin`` for Apple Silicon devices.
++ - ``x86_64-apple-darwin`` for Intel devices.
++
++* ``/path/to/python.exe`` is the path to a Python binary on the machine that
++ will be running the compiler. This is needed because the Python compilation
++ process involves running some Python code. On a normal desktop build of
++ Python, you can compile a python interpreter and then use that interpreter to
++ run Python code. However, the binaries produced for tvOS won't run on macOS, so
++ you need to provide an external Python interpreter. This interpreter must be
++ the version as the Python that is being compiled.
++
++Using a framework-based Python on tvOS
++======================================
+--- /dev/null
++++ b/tvOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2024 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ 1
++ CFBundleSupportedPlatforms
++
++ tvOS
++
++ MinimumOSVersion
++ @TVOS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos $@
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos -E $@
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos-simulator $@
+--- /dev/null
++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos-simulator -E $@
+--- /dev/null
++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos-simulator $@
+--- /dev/null
++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos-simulator -E $@
+--- /dev/null
++++ b/tvOS/Resources/dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ tvOS
++
++ MinimumOSVersion
++ 9.0
++ CFBundleVersion
++ 1
++
++
+--- /dev/null
++++ b/tvOS/Resources/pyconfig.h
+@@ -0,0 +1,7 @@
++#ifdef __arm64__
++#include "pyconfig-arm64.h"
++#endif
++
++#ifdef __x86_64__
++#include "pyconfig-x86_64.h"
++#endif
+--- /dev/null
++++ b/watchOS/README.rst
+@@ -0,0 +1,108 @@
++========================
++Python on watchOS README
++========================
++
++:Authors:
++ Russell Keith-Magee (2023-11)
++
++This document provides a quick overview of some watchOS specific features in the
++Python distribution.
++
++Compilers for building on watchOS
++=================================
++
++Building for watchOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode, on the
++most recently released macOS.
++
++watchOS specific arguments to configure
++=======================================
++
++* ``--enable-framework[=DIR]``
++
++ This argument specifies the location where the Python.framework will
++ be installed.
++
++* ``--with-framework-name=NAME``
++
++ Specify the name for the python framework, defaults to ``Python``.
++
++
++Building and using Python on watchOS
++====================================
++
++ABIs and Architectures
++----------------------
++
++watchOS apps can be deployed on physical devices, and on the watchOS simulator.
++Although the API used on these devices is identical, the ABI is different - you
++need to link against different libraries for an watchOS device build
++(``watchos``) or an watchOS simulator build (``watchsimulator``). Apple uses the
++XCframework format to allow specifying a single dependency that supports
++multiple ABIs. An XCframework is a wrapper around multiple ABI-specific
++frameworks.
++
++watchOS can also support different CPU architectures within each ABI. At present,
++there is only a single support ed architecture on physical devices - ARM64.
++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
++Silicon machines), and x86_64 (for running on older Intel-based machines.)
++
++To support multiple CPU architectures on a single platform, Apple uses a "fat
++binary" format - a single physical file that contains support for multiple
++architectures.
++
++How do I build Python for watchOS?
++-------------------------------
++
++The Python build system will build a ``Python.framework`` that supports a
++*single* ABI with a *single* architecture. If you want to use Python in an watchOS
++project, you need to:
++
++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture;
++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary;
++3. Merge the "fat" frameworks for each ABI into a single XCframework.
++
++watchOS builds of Python *must* be constructed as framework builds. To support this,
++you must provide the ``--enable-framework`` flag when configuring the build.
++
++The build also requires the use of cross-compilation. The commands for building
++Python for watchOS will look somethign like::
++
++ $ ./configure \
++ --enable-framework=/path/to/install \
++ --host=aarch64-apple-watchos \
++ --build=aarch64-apple-darwin \
++ --with-build-python=/path/to/python.exe
++ $ make
++ $ make install
++
++In this invocation:
++
++* ``/path/to/install`` is the location where the final Python.framework will be
++ output.
++
++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
++ triple format. This will be one of:
++
++ - ``arm64_32-apple-watchos`` for ARM64-32 watchOS devices.
++ - ``aarch64-apple-watchos-simulator`` for the watchOS simulator running on Apple
++ Silicon devices.
++ - ``x86_64-apple-watchos-simulator`` for the watchOS simulator running on Intel
++ devices.
++
++* ``--build`` is the GNU compiler triple for the machine that will be running
++ the compiler. This is one of:
++
++ - ``aarch64-apple-darwin`` for Apple Silicon devices.
++ - ``x86_64-apple-darwin`` for Intel devices.
++
++* ``/path/to/python.exe`` is the path to a Python binary on the machine that
++ will be running the compiler. This is needed because the Python compilation
++ process involves running some Python code. On a normal desktop build of
++ Python, you can compile a python interpreter and then use that interpreter to
++ run Python code. However, the binaries produced for watchOS won't run on macOS, so
++ you need to provide an external Python interpreter. This interpreter must be
++ the version as the Python that is being compiled.
++
++Using a framework-based Python on watchOS
++======================================
+--- /dev/null
++++ b/watchOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2023 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ %VERSION%
++ CFBundleSupportedPlatforms
++
++ watchOS
++
++ MinimumOSVersion
++ @WATCHOS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target arm64-apple-watchos-simulator $@
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator clang -target arm64-apple-watchos-simulator -E $@
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos $@
+--- /dev/null
++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos -E $@
+--- /dev/null
++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar $@
+--- /dev/null
++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos-simulator $@
+--- /dev/null
++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos-simulator -E $@
+--- /dev/null
++++ b/watchOS/Resources/dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ watchOS
++
++ MinimumOSVersion
++ 4.0
++ CFBundleVersion
++ 1
++
++
+--- /dev/null
++++ b/watchOS/Resources/pyconfig.h
+@@ -0,0 +1,11 @@
++#ifdef __arm64__
++# ifdef __LP64__
++#include "pyconfig-arm64.h"
++# else
++#include "pyconfig-arm64_32.h"
++# endif
++#endif
++
++#ifdef __x86_64__
++#include "pyconfig-x86_64.h"
++#endif
From ce48e8bad1cd82e22051930fb7a122c1143f1095 Mon Sep 17 00:00:00 2001
From: Russell Keith-Magee
Date: Mon, 9 Sep 2024 11:08:49 +0800
Subject: [PATCH 03/10] Update patch to Python 3.12.6.
Also includes updates to:
- XZ 5.6.2
- OpenSSL 3.0.15
---
Makefile | 2 +-
README.rst | 2 +-
patch/Python/Python.patch | 46498 +-----------------------------------
3 files changed, 335 insertions(+), 46167 deletions(-)
diff --git a/Makefile b/Makefile
index 689091d5..6e29d5a5 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ BUILD_NUMBER=custom
# of a release cycle, as official binaries won't be published.
# PYTHON_MICRO_VERSION is the full version number, without any alpha/beta/rc suffix. (e.g., 3.10.0)
# PYTHON_VER is the major/minor version (e.g., 3.10)
-PYTHON_VERSION=3.12.4
+PYTHON_VERSION=3.12.6
PYTHON_PKG_VERSION=$(PYTHON_VERSION)
PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+")
PYTHON_PKG_MICRO_VERSION=$(shell echo $(PYTHON_PKG_VERSION) | grep -Eo "\d+\.\d+\.\d+")
diff --git a/README.rst b/README.rst
index 580c8abd..4af94e95 100644
--- a/README.rst
+++ b/README.rst
@@ -4,7 +4,7 @@ Python Apple Support
This is a meta-package for building a version of Python that can be embedded
into a macOS, iOS, tvOS or watchOS project.
-**This branch builds a packaged version of Python 3.12.0**.
+**This branch builds a packaged version of Python 3.12.6**.
Other Python versions are available by cloning other branches of the main
repository:
diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch
index fdec1287..0bcb11c6 100644
--- a/patch/Python/Python.patch
+++ b/patch/Python/Python.patch
@@ -1,4117 +1,3 @@
-diff --git a/.azure-pipelines/ci.yml b/.azure-pipelines/ci.yml
-index b5b2765e438..d3e842d9f31 100644
---- a/.azure-pipelines/ci.yml
-+++ b/.azure-pipelines/ci.yml
-@@ -1,4 +1,4 @@
--trigger: ['main', '3.12', '3.11', '3.10', '3.9', '3.8', '3.7']
-+trigger: ['main', '3.13', '3.12', '3.11', '3.10', '3.9', '3.8']
-
- jobs:
- - job: Prebuild
-diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
-index 663a11897d9..c64ca318677 100644
---- a/.pre-commit-config.yaml
-+++ b/.pre-commit-config.yaml
-@@ -3,13 +3,21 @@
- rev: v0.3.4
- hooks:
- - id: ruff
-- name: Run Ruff on Lib/test/
-+ name: Run Ruff (lint) on Doc/
-+ args: [--exit-non-zero-on-fix]
-+ files: ^Doc/
-+ - id: ruff
-+ name: Run Ruff (lint) on Lib/test/
- args: [--exit-non-zero-on-fix]
- files: ^Lib/test/
- - id: ruff
-- name: Run Ruff on Argument Clinic
-+ name: Run Ruff (lint) on Argument Clinic
- args: [--exit-non-zero-on-fix, --config=Tools/clinic/.ruff.toml]
- files: ^Tools/clinic/|Lib/test/test_clinic.py
-+ - id: ruff-format
-+ name: Run Ruff (format) on Doc/
-+ args: [--check]
-+ files: ^Doc/
-
- - repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
-diff --git a/.readthedocs.yml b/.readthedocs.yml
-index 898a9ae89db..250d7ea0233 100644
---- a/.readthedocs.yml
-+++ b/.readthedocs.yml
-@@ -8,11 +8,14 @@
- configuration: Doc/conf.py
-
- build:
-- os: ubuntu-22.04
-+ os: ubuntu-24.04
- tools:
- python: "3"
-
- commands:
-+ - asdf plugin add uv
-+ - asdf install uv latest
-+ - asdf global uv latest
- - make -C Doc venv html
- - mkdir _readthedocs
- - mv Doc/build/html _readthedocs/html
---- /dev/null
-+++ b/Doc/.ruff.toml
-@@ -0,0 +1,42 @@
-+target-version = "py312" # Align with the version in oldest_supported_sphinx
-+fix = true
-+output-format = "full"
-+line-length = 79
-+extend-exclude = [
-+ "includes/*",
-+ # Temporary exclusions:
-+ "tools/extensions/pyspecific.py",
-+]
-+
-+[lint]
-+preview = true
-+select = [
-+ "C4", # flake8-comprehensions
-+ "B", # flake8-bugbear
-+ "E", # pycodestyle
-+ "F", # pyflakes
-+ "FA", # flake8-future-annotations
-+ "FLY", # flynt
-+ "FURB", # refurb
-+ "G", # flake8-logging-format
-+ "I", # isort
-+ "LOG", # flake8-logging
-+ "N", # pep8-naming
-+ "PERF", # perflint
-+ "PGH", # pygrep-hooks
-+ "PT", # flake8-pytest-style
-+ "TCH", # flake8-type-checking
-+ "UP", # pyupgrade
-+ "W", # pycodestyle
-+]
-+ignore = [
-+ "E501", # Ignore line length errors (we use auto-formatting)
-+]
-+
-+[format]
-+preview = true
-+quote-style = "preserve"
-+docstring-code-format = true
-+exclude = [
-+ "tools/extensions/lexers/*",
-+]
-diff --git a/Doc/Makefile b/Doc/Makefile
-index 1cbfc722b01..dbd799fd400 100644
---- a/Doc/Makefile
-+++ b/Doc/Makefile
-@@ -6,6 +6,7 @@
- # You can set these variables from the command line.
- PYTHON = python3
- VENVDIR = ./venv
-+UV = uv
- SPHINXBUILD = PATH=$(VENVDIR)/bin:$$PATH sphinx-build
- BLURB = PATH=$(VENVDIR)/bin:$$PATH blurb
- JOBS = auto
-@@ -150,14 +151,10 @@
- htmlview: html
- $(PYTHON) -c "import os, webbrowser; webbrowser.open('file://' + os.path.realpath('build/html/index.html'))"
-
--.PHONY: ensure-sphinx-autobuild
--ensure-sphinx-autobuild: venv
-- $(VENVDIR)/bin/sphinx-autobuild --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install sphinx-autobuild
--
- .PHONY: htmllive
- htmllive: SPHINXBUILD = $(VENVDIR)/bin/sphinx-autobuild
- htmllive: SPHINXOPTS = --re-ignore="/venv/" --open-browser --delay 0
--htmllive: ensure-sphinx-autobuild html
-+htmllive: _ensure-sphinx-autobuild html
-
- .PHONY: clean
- clean: clean-venv
-@@ -174,9 +171,14 @@
- echo "To recreate it, remove it first with \`make clean-venv'."; \
- else \
- echo "Creating venv in $(VENVDIR)"; \
-- $(PYTHON) -m venv $(VENVDIR); \
-- $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \
-- $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \
-+ if $(UV) --version >/dev/null 2>&1; then \
-+ $(UV) venv $(VENVDIR); \
-+ VIRTUAL_ENV=$(VENVDIR) $(UV) pip install -r $(REQUIREMENTS); \
-+ else \
-+ $(PYTHON) -m venv $(VENVDIR); \
-+ $(VENVDIR)/bin/python3 -m pip install --upgrade pip; \
-+ $(VENVDIR)/bin/python3 -m pip install -r $(REQUIREMENTS); \
-+ fi; \
- echo "The venv has been created in the $(VENVDIR) directory"; \
- fi
-
-@@ -186,58 +188,88 @@
- mkdir -p dist
-
- # archive the HTML
-- make html
-+ @echo "Building HTML..."
-+ $(MAKE) html
- cp -pPR build/html dist/python-$(DISTVERSION)-docs-html
- tar -C dist -cf dist/python-$(DISTVERSION)-docs-html.tar python-$(DISTVERSION)-docs-html
- bzip2 -9 -k dist/python-$(DISTVERSION)-docs-html.tar
- (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-html.zip python-$(DISTVERSION)-docs-html)
- rm -r dist/python-$(DISTVERSION)-docs-html
- rm dist/python-$(DISTVERSION)-docs-html.tar
-+ @echo "Build finished and archived!"
-
- # archive the text build
-- make text
-+ @echo "Building text..."
-+ $(MAKE) text
- cp -pPR build/text dist/python-$(DISTVERSION)-docs-text
- tar -C dist -cf dist/python-$(DISTVERSION)-docs-text.tar python-$(DISTVERSION)-docs-text
- bzip2 -9 -k dist/python-$(DISTVERSION)-docs-text.tar
- (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-text.zip python-$(DISTVERSION)-docs-text)
- rm -r dist/python-$(DISTVERSION)-docs-text
- rm dist/python-$(DISTVERSION)-docs-text.tar
-+ @echo "Build finished and archived!"
-
- # archive the A4 latex
-+ @echo "Building LaTeX (A4 paper)..."
- rm -rf build/latex
-- make latex PAPER=a4
-- -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile
-- (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2)
-+ $(MAKE) latex PAPER=a4
-+ # remove zip & bz2 dependency on all-pdf,
-+ # as otherwise the full latexmk process is run twice.
-+ # ($$ is needed to escape the $; https://www.gnu.org/software/make/manual/make.html#Basics-of-Variable-References)
-+ -sed -i 's/: all-$$(FMT)/:/' build/latex/Makefile
-+ (cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`nproc`+1)) --output-sync LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2)
- cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-a4.zip
- cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-a4.tar.bz2
-+ @echo "Build finished and archived!"
-
- # archive the letter latex
-+ @echo "Building LaTeX (US paper)..."
- rm -rf build/latex
-- make latex PAPER=letter
-- -sed -i 's/makeindex/makeindex -q/' build/latex/Makefile
-- (cd build/latex; make clean && make all-pdf && make FMT=pdf zip bz2)
-+ $(MAKE) latex PAPER=letter
-+ -sed -i 's/: all-$$(FMT)/:/' build/latex/Makefile
-+ (cd build/latex; $(MAKE) clean && $(MAKE) --jobs=$$((`nproc`+1)) --output-sync LATEXMKOPTS='-quiet' all-pdf && $(MAKE) FMT=pdf zip bz2)
- cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-letter.zip
- cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-letter.tar.bz2
-+ @echo "Build finished and archived!"
-
- # copy the epub build
-+ @echo "Building EPUB..."
- rm -rf build/epub
-- make epub
-+ $(MAKE) epub
- cp -pPR build/epub/Python.epub dist/python-$(DISTVERSION)-docs.epub
-+ @echo "Build finished and archived!"
-
- # archive the texinfo build
-+ @echo "Building Texinfo..."
- rm -rf build/texinfo
-- make texinfo
-- make info --directory=build/texinfo
-+ $(MAKE) texinfo
-+ $(MAKE) info --directory=build/texinfo
- cp -pPR build/texinfo dist/python-$(DISTVERSION)-docs-texinfo
- tar -C dist -cf dist/python-$(DISTVERSION)-docs-texinfo.tar python-$(DISTVERSION)-docs-texinfo
- bzip2 -9 -k dist/python-$(DISTVERSION)-docs-texinfo.tar
- (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-texinfo.zip python-$(DISTVERSION)-docs-texinfo)
- rm -r dist/python-$(DISTVERSION)-docs-texinfo
- rm dist/python-$(DISTVERSION)-docs-texinfo.tar
-+ @echo "Build finished and archived!"
-+
-+.PHONY: _ensure-package
-+_ensure-package: venv
-+ if $(UV) --version >/dev/null 2>&1; then \
-+ VIRTUAL_ENV=$(VENVDIR) $(UV) pip install $(PACKAGE); \
-+ else \
-+ $(VENVDIR)/bin/python3 -m pip install $(PACKAGE); \
-+ fi
-+
-+.PHONY: _ensure-pre-commit
-+_ensure-pre-commit:
-+ $(MAKE) _ensure-package PACKAGE=pre-commit
-+
-+.PHONY: _ensure-sphinx-autobuild
-+_ensure-sphinx-autobuild:
-+ $(MAKE) _ensure-package PACKAGE=sphinx-autobuild
-
- .PHONY: check
--check: venv
-- $(VENVDIR)/bin/python3 -m pre_commit --version > /dev/null || $(VENVDIR)/bin/python3 -m pip install pre-commit
-+check: _ensure-pre-commit
- $(VENVDIR)/bin/python3 -m pre_commit run --all-files
-
- .PHONY: serve
-@@ -254,12 +286,12 @@
- # for development releases: always build
- .PHONY: autobuild-dev
- autobuild-dev:
-- make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
-+ $(MAKE) dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
-
- # for quick rebuilds (HTML only)
- .PHONY: autobuild-dev-html
- autobuild-dev-html:
-- make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
-+ $(MAKE) html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1'
-
- # for stable releases: only build if not in pre-release stage (alpha, beta)
- # release candidate downloads are okay, since the stable tree can be in that stage
-@@ -269,7 +301,7 @@
- echo "Not building; $(DISTVERSION) is not a release version."; \
- exit 1;; \
- esac
-- @make autobuild-dev
-+ @$(MAKE) autobuild-dev
-
- .PHONY: autobuild-stable-html
- autobuild-stable-html:
-@@ -277,4 +309,4 @@
- echo "Not building; $(DISTVERSION) is not a release version."; \
- exit 1;; \
- esac
-- @make autobuild-dev-html
-+ @$(MAKE) autobuild-dev-html
-diff --git a/Doc/README.rst b/Doc/README.rst
-index a3bb5fa5445..efcee0db428 100644
---- a/Doc/README.rst
-+++ b/Doc/README.rst
-@@ -28,7 +28,7 @@
- Using make
- ----------
-
--To get started on UNIX, you can create a virtual environment and build
-+To get started on Unix, you can create a virtual environment and build
- documentation with the commands::
-
- make venv
-@@ -40,13 +40,13 @@
- you can specify it using the ``VENVDIR`` variable.
-
- You can also skip creating the virtual environment altogether, in which case
--the Makefile will look for instances of ``sphinx-build`` and ``blurb``
-+the ``Makefile`` will look for instances of ``sphinx-build`` and ``blurb``
- installed on your process ``PATH`` (configurable with the ``SPHINXBUILD`` and
- ``BLURB`` variables).
-
--On Windows, we try to emulate the Makefile as closely as possible with a
-+On Windows, we try to emulate the ``Makefile`` as closely as possible with a
- ``make.bat`` file. If you need to specify the Python interpreter to use,
--set the PYTHON environment variable.
-+set the ``PYTHON`` environment variable.
-
- Available make targets are:
-
-@@ -62,15 +62,19 @@
- * "htmlview", which re-uses the "html" builder, but then opens the main page
- in your default web browser.
-
-+* "htmllive", which re-uses the "html" builder, rebuilds the docs,
-+ starts a local server, and automatically reloads the page in your browser
-+ when you make changes to reST files (Unix only).
-+
- * "htmlhelp", which builds HTML files and a HTML Help project file usable to
- convert them into a single Compiled HTML (.chm) file -- these are popular
- under Microsoft Windows, but very handy on every platform.
-
- To create the CHM file, you need to run the Microsoft HTML Help Workshop
-- over the generated project (.hhp) file. The make.bat script does this for
-+ over the generated project (.hhp) file. The ``make.bat`` script does this for
- you on Windows.
-
--* "latex", which builds LaTeX source files as input to "pdflatex" to produce
-+* "latex", which builds LaTeX source files as input to ``pdflatex`` to produce
- PDF documents.
-
- * "text", which builds a plain text file for each source file.
-@@ -95,8 +99,6 @@
-
- * "check", which checks for frequent markup errors.
-
--* "serve", which serves the build/html directory on port 8000.
--
- * "dist", (Unix only) which creates distributable archives of HTML, text,
- PDF, and EPUB builds.
-
-diff --git a/Doc/c-api/arg.rst b/Doc/c-api/arg.rst
-index 657b10d3e0a..b8af24f53c3 100644
---- a/Doc/c-api/arg.rst
-+++ b/Doc/c-api/arg.rst
-@@ -280,10 +280,10 @@
- length 1, to a C :c:expr:`int`.
-
- ``f`` (:class:`float`) [float]
-- Convert a Python floating point number to a C :c:expr:`float`.
-+ Convert a Python floating-point number to a C :c:expr:`float`.
-
- ``d`` (:class:`float`) [double]
-- Convert a Python floating point number to a C :c:expr:`double`.
-+ Convert a Python floating-point number to a C :c:expr:`double`.
-
- ``D`` (:class:`complex`) [Py_complex]
- Convert a Python complex number to a C :c:type:`Py_complex` structure.
-@@ -607,10 +607,10 @@
- object of length 1.
-
- ``d`` (:class:`float`) [double]
-- Convert a C :c:expr:`double` to a Python floating point number.
-+ Convert a C :c:expr:`double` to a Python floating-point number.
-
- ``f`` (:class:`float`) [float]
-- Convert a C :c:expr:`float` to a Python floating point number.
-+ Convert a C :c:expr:`float` to a Python floating-point number.
-
- ``D`` (:class:`complex`) [Py_complex \*]
- Convert a C :c:type:`Py_complex` structure to a Python complex number.
-diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst
-index 456f7d89bca..9045689a6be 100644
---- a/Doc/c-api/bytearray.rst
-+++ b/Doc/c-api/bytearray.rst
-@@ -42,17 +42,22 @@
- Return a new bytearray object from any object, *o*, that implements the
- :ref:`buffer protocol `.
-
-+ On failure, return ``NULL`` with an exception set.
-+
-
- .. c:function:: PyObject* PyByteArray_FromStringAndSize(const char *string, Py_ssize_t len)
-
-- Create a new bytearray object from *string* and its length, *len*. On
-- failure, ``NULL`` is returned.
-+ Create a new bytearray object from *string* and its length, *len*.
-+
-+ On failure, return ``NULL`` with an exception set.
-
-
- .. c:function:: PyObject* PyByteArray_Concat(PyObject *a, PyObject *b)
-
- Concat bytearrays *a* and *b* and return a new bytearray with the result.
-
-+ On failure, return ``NULL`` with an exception set.
-+
-
- .. c:function:: Py_ssize_t PyByteArray_Size(PyObject *bytearray)
-
-diff --git a/Doc/c-api/cell.rst b/Doc/c-api/cell.rst
-index f8cd0344fdd..61eb994c370 100644
---- a/Doc/c-api/cell.rst
-+++ b/Doc/c-api/cell.rst
-@@ -39,7 +39,8 @@
-
- .. c:function:: PyObject* PyCell_Get(PyObject *cell)
-
-- Return the contents of the cell *cell*.
-+ Return the contents of the cell *cell*, which can be ``NULL``.
-+ If *cell* is not a cell object, returns ``NULL`` with an exception set.
-
-
- .. c:function:: PyObject* PyCell_GET(PyObject *cell)
-@@ -52,8 +53,10 @@
-
- Set the contents of the cell object *cell* to *value*. This releases the
- reference to any current content of the cell. *value* may be ``NULL``. *cell*
-- must be non-``NULL``; if it is not a cell object, ``-1`` will be returned. On
-- success, ``0`` will be returned.
-+ must be non-``NULL``.
-+
-+ On success, return ``0``.
-+ If *cell* is not a cell object, set an exception and return ``-1``.
-
-
- .. c:function:: void PyCell_SET(PyObject *cell, PyObject *value)
-diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
-index e3fd001c599..77cb67d8de2 100644
---- a/Doc/c-api/complex.rst
-+++ b/Doc/c-api/complex.rst
-@@ -25,12 +25,16 @@
-
- The C structure which corresponds to the value portion of a Python complex
- number object. Most of the functions for dealing with complex number objects
-- use structures of this type as input or output values, as appropriate. It is
-- defined as::
-+ use structures of this type as input or output values, as appropriate.
-+
-+ .. c:member:: double real
-+ double imag
-+
-+ The structure is defined as::
-
- typedef struct {
-- double real;
-- double imag;
-+ double real;
-+ double imag;
- } Py_complex;
-
-
-@@ -106,17 +110,22 @@
- .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
-
- Create a new Python complex number object from a C :c:type:`Py_complex` value.
-+ Return ``NULL`` with an exception set on error.
-
-
- .. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag)
-
- Return a new :c:type:`PyComplexObject` object from *real* and *imag*.
-+ Return ``NULL`` with an exception set on error.
-
-
- .. c:function:: double PyComplex_RealAsDouble(PyObject *op)
-
- Return the real part of *op* as a C :c:expr:`double`.
-
-+ Upon failure, this method returns ``-1.0`` with an exception set, so one
-+ should call :c:func:`PyErr_Occurred` to check for errors.
-+
-
- .. c:function:: double PyComplex_ImagAsDouble(PyObject *op)
-
-@@ -131,8 +140,11 @@
- method, this method will first be called to convert *op* to a Python complex
- number object. If :meth:`!__complex__` is not defined then it falls back to
- :meth:`~object.__float__`. If :meth:`!__float__` is not defined then it falls back
-- to :meth:`~object.__index__`. Upon failure, this method returns ``-1.0`` as a real
-- value.
-+ to :meth:`~object.__index__`.
-+
-+ Upon failure, this method returns :c:type:`Py_complex`
-+ with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception set, so one
-+ should call :c:func:`PyErr_Occurred` to check for errors.
-
- .. versionchanged:: 3.8
- Use :meth:`~object.__index__` if available.
-diff --git a/Doc/c-api/datetime.rst b/Doc/c-api/datetime.rst
-index 97522da7734..d2d4d5309c7 100644
---- a/Doc/c-api/datetime.rst
-+++ b/Doc/c-api/datetime.rst
-@@ -318,10 +318,10 @@
- .. c:function:: PyObject* PyDateTime_FromTimestamp(PyObject *args)
-
- Create and return a new :class:`datetime.datetime` object given an argument
-- tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp()`.
-+ tuple suitable for passing to :meth:`datetime.datetime.fromtimestamp`.
-
-
- .. c:function:: PyObject* PyDate_FromTimestamp(PyObject *args)
-
- Create and return a new :class:`datetime.date` object given an argument
-- tuple suitable for passing to :meth:`datetime.date.fromtimestamp()`.
-+ tuple suitable for passing to :meth:`datetime.date.fromtimestamp`.
-diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
-index 7ddecb24734..9913273421a 100644
---- a/Doc/c-api/exceptions.rst
-+++ b/Doc/c-api/exceptions.rst
-@@ -34,7 +34,7 @@
- and may fail in mysterious ways.
-
- .. note::
-- The error indicator is **not** the result of :func:`sys.exc_info()`.
-+ The error indicator is **not** the result of :func:`sys.exc_info`.
- The former corresponds to an exception that is not yet caught (and is
- therefore still propagating), while the latter returns an exception after
- it is caught (and has therefore stopped propagating).
-diff --git a/Doc/c-api/float.rst b/Doc/c-api/float.rst
-index 4f6ac0d8175..1da37a5bcae 100644
---- a/Doc/c-api/float.rst
-+++ b/Doc/c-api/float.rst
-@@ -2,20 +2,20 @@
-
- .. _floatobjects:
-
--Floating Point Objects
-+Floating-Point Objects
- ======================
-
--.. index:: pair: object; floating point
-+.. index:: pair: object; floating-point
-
-
- .. c:type:: PyFloatObject
-
-- This subtype of :c:type:`PyObject` represents a Python floating point object.
-+ This subtype of :c:type:`PyObject` represents a Python floating-point object.
-
-
- .. c:var:: PyTypeObject PyFloat_Type
-
-- This instance of :c:type:`PyTypeObject` represents the Python floating point
-+ This instance of :c:type:`PyTypeObject` represents the Python floating-point
- type. This is the same object as :class:`float` in the Python layer.
-
-
-@@ -45,7 +45,7 @@
- .. c:function:: double PyFloat_AsDouble(PyObject *pyfloat)
-
- Return a C :c:expr:`double` representation of the contents of *pyfloat*. If
-- *pyfloat* is not a Python floating point object but has a :meth:`~object.__float__`
-+ *pyfloat* is not a Python floating-point object but has a :meth:`~object.__float__`
- method, this method will first be called to convert *pyfloat* into a float.
- If :meth:`!__float__` is not defined then it falls back to :meth:`~object.__index__`.
- This method returns ``-1.0`` upon failure, so one should call
-diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst
-index 380465b817d..b8687c61c26 100644
---- a/Doc/c-api/import.rst
-+++ b/Doc/c-api/import.rst
-@@ -174,7 +174,7 @@
-
- .. versionadded:: 3.2
- .. versionchanged:: 3.3
-- Uses :func:`!imp.source_from_cache()` in calculating the source path if
-+ Uses :func:`!imp.source_from_cache` in calculating the source path if
- only the bytecode path is provided.
- .. versionchanged:: 3.12
- No longer uses the removed :mod:`!imp` module.
-diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst
-index a51f1da6b66..8b7b28ae319 100644
---- a/Doc/c-api/init.rst
-+++ b/Doc/c-api/init.rst
-@@ -388,9 +388,16 @@
- :c:func:`Py_NewInterpreter` below) that were created and not yet destroyed since
- the last call to :c:func:`Py_Initialize`. Ideally, this frees all memory
- allocated by the Python interpreter. This is a no-op when called for a second
-- time (without calling :c:func:`Py_Initialize` again first). Normally the
-- return value is ``0``. If there were errors during finalization
-- (flushing buffered data), ``-1`` is returned.
-+ time (without calling :c:func:`Py_Initialize` again first).
-+
-+ Since this is the reverse of :c:func:`Py_Initialize`, it should be called
-+ in the same thread with the same interpreter active. That means
-+ the main thread and the main interpreter.
-+ This should never be called while :c:func:`Py_RunMain` is running.
-+
-+ Normally the return value is ``0``.
-+ If there were errors during finalization (flushing buffered data),
-+ ``-1`` is returned.
-
- This function is provided for a number of reasons. An embedding application
- might want to restart Python without having to restart the application itself.
-diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
-index 7c5465b5bfa..c586cfb39e8 100644
---- a/Doc/c-api/init_config.rst
-+++ b/Doc/c-api/init_config.rst
-@@ -311,7 +311,7 @@
- * Set :c:member:`PyConfig.filesystem_encoding` to ``"mbcs"``,
- * Set :c:member:`PyConfig.filesystem_errors` to ``"replace"``.
-
-- Initialized the from :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment
-+ Initialized from the :envvar:`PYTHONLEGACYWINDOWSFSENCODING` environment
- variable value.
-
- Only available on Windows. ``#ifdef MS_WINDOWS`` macro can be used for
-@@ -499,7 +499,7 @@
- The :c:func:`PyConfig_Read` function only parses
- :c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv`
- is set to ``2`` after arguments are parsed. Since Python arguments are
-- strippped from :c:member:`PyConfig.argv`, parsing arguments twice would
-+ stripped from :c:member:`PyConfig.argv`, parsing arguments twice would
- parse the application options as Python options.
-
- :ref:`Preinitialize Python ` if needed.
-@@ -1000,7 +1000,7 @@
- The :c:func:`PyConfig_Read` function only parses
- :c:member:`PyConfig.argv` arguments once: :c:member:`PyConfig.parse_argv`
- is set to ``2`` after arguments are parsed. Since Python arguments are
-- strippped from :c:member:`PyConfig.argv`, parsing arguments twice would
-+ stripped from :c:member:`PyConfig.argv`, parsing arguments twice would
- parse the application options as Python options.
-
- Default: ``1`` in Python mode, ``0`` in isolated mode.
-diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
-index 76ac80322f8..af86810c6b1 100644
---- a/Doc/c-api/long.rst
-+++ b/Doc/c-api/long.rst
-@@ -324,6 +324,17 @@
- Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate.
-
-
-+.. c:function:: PyObject* PyLong_GetInfo(void)
-+
-+ On success, return a read only :term:`named tuple`, that holds
-+ information about Python's internal representation of integers.
-+ See :data:`sys.int_info` for description of individual fields.
-+
-+ On failure, return ``NULL`` with an exception set.
-+
-+ .. versionadded:: 3.1
-+
-+
- .. c:function:: int PyUnstable_Long_IsCompact(const PyLongObject* op)
-
- Return 1 if *op* is compact, 0 otherwise.
-diff --git a/Doc/c-api/marshal.rst b/Doc/c-api/marshal.rst
-index 489f1580a41..b9085ad3ec3 100644
---- a/Doc/c-api/marshal.rst
-+++ b/Doc/c-api/marshal.rst
-@@ -15,7 +15,7 @@
-
- The module supports two versions of the data format: version 0 is the
- historical version, version 1 shares interned strings in the file, and upon
--unmarshalling. Version 2 uses a binary format for floating point numbers.
-+unmarshalling. Version 2 uses a binary format for floating-point numbers.
- ``Py_MARSHAL_VERSION`` indicates the current file format (currently 2).
-
-
-diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
-index f941f0c7d42..9340a942656 100644
---- a/Doc/c-api/module.rst
-+++ b/Doc/c-api/module.rst
-@@ -43,6 +43,8 @@
- to ``None``); the caller is responsible for providing a :attr:`__file__`
- attribute.
-
-+ Return ``NULL`` with an exception set on error.
-+
- .. versionadded:: 3.3
-
- .. versionchanged:: 3.4
-@@ -265,6 +267,8 @@
- API version *module_api_version*. If that version does not match the version
- of the running interpreter, a :exc:`RuntimeWarning` is emitted.
-
-+ Return ``NULL`` with an exception set on error.
-+
- .. note::
-
- Most uses of this function should be using :c:func:`PyModule_Create`
-@@ -338,7 +342,8 @@
- The *value* pointer of this slot must point to a function of the signature:
-
- .. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
-- :noindex:
-+ :no-index-entry:
-+ :no-contents-entry:
-
- The function receives a :py:class:`~importlib.machinery.ModuleSpec`
- instance, as defined in :PEP:`451`, and the module definition.
-@@ -373,7 +378,8 @@
- The signature of the function is:
-
- .. c:function:: int exec_module(PyObject* module)
-- :noindex:
-+ :no-index-entry:
-+ :no-contents-entry:
-
- If multiple ``Py_mod_exec`` slots are specified, they are processed in the
- order they appear in the *m_slots* array.
-@@ -436,6 +442,8 @@
- If that version does not match the version of the running interpreter,
- a :exc:`RuntimeWarning` is emitted.
-
-+ Return ``NULL`` with an exception set on error.
-+
- .. note::
-
- Most uses of this function should be using :c:func:`PyModule_FromDefAndSpec`
-@@ -486,7 +494,7 @@
-
- On success, return ``0``. On error, raise an exception and return ``-1``.
-
-- Return ``NULL`` if *value* is ``NULL``. It must be called with an exception
-+ Return ``-1`` if *value* is ``NULL``. It must be called with an exception
- raised in this case.
-
- Example usage::
-@@ -579,15 +587,16 @@
- .. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)
-
- Add an integer constant to *module* as *name*. This convenience function can be
-- used from the module's initialization function. Return ``-1`` on error, ``0`` on
-- success.
-+ used from the module's initialization function.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
-
- .. c:function:: int PyModule_AddStringConstant(PyObject *module, const char *name, const char *value)
-
- Add a string constant to *module* as *name*. This convenience function can be
- used from the module's initialization function. The string *value* must be
-- ``NULL``-terminated. Return ``-1`` on error, ``0`` on success.
-+ ``NULL``-terminated.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
-
- .. c:macro:: PyModule_AddIntMacro(module, macro)
-@@ -595,7 +604,7 @@
- Add an int constant to *module*. The name and the value are taken from
- *macro*. For example ``PyModule_AddIntMacro(module, AF_INET)`` adds the int
- constant *AF_INET* with the value of *AF_INET* to *module*.
-- Return ``-1`` on error, ``0`` on success.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
-
- .. c:macro:: PyModule_AddStringMacro(module, macro)
-@@ -608,7 +617,7 @@
- The type object is finalized by calling internally :c:func:`PyType_Ready`.
- The name of the type object is taken from the last component of
- :c:member:`~PyTypeObject.tp_name` after dot.
-- Return ``-1`` on error, ``0`` on success.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
- .. versionadded:: 3.9
-
-@@ -647,14 +656,14 @@
-
- The caller must hold the GIL.
-
-- Return 0 on success or -1 on failure.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
- .. versionadded:: 3.3
-
- .. c:function:: int PyState_RemoveModule(PyModuleDef *def)
-
- Removes the module object created from *def* from the interpreter state.
-- Return 0 on success or -1 on failure.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
- The caller must hold the GIL.
-
-diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
-index 13d3c5af956..ad8b5935258 100644
---- a/Doc/c-api/number.rst
-+++ b/Doc/c-api/number.rst
-@@ -51,8 +51,8 @@
-
- Return a reasonable approximation for the mathematical value of *o1* divided by
- *o2*, or ``NULL`` on failure. The return value is "approximate" because binary
-- floating point numbers are approximate; it is not possible to represent all real
-- numbers in base two. This function can return a floating point value when
-+ floating-point numbers are approximate; it is not possible to represent all real
-+ numbers in base two. This function can return a floating-point value when
- passed two integers. This is the equivalent of the Python expression ``o1 / o2``.
-
-
-@@ -177,8 +177,8 @@
-
- Return a reasonable approximation for the mathematical value of *o1* divided by
- *o2*, or ``NULL`` on failure. The return value is "approximate" because binary
-- floating point numbers are approximate; it is not possible to represent all real
-- numbers in base two. This function can return a floating point value when
-+ floating-point numbers are approximate; it is not possible to represent all real
-+ numbers in base two. This function can return a floating-point value when
- passed two integers. The operation is done *in-place* when *o1* supports it.
- This is the equivalent of the Python statement ``o1 /= o2``.
-
-diff --git a/Doc/c-api/slice.rst b/Doc/c-api/slice.rst
-index 9e880c6b7f2..819929a0e60 100644
---- a/Doc/c-api/slice.rst
-+++ b/Doc/c-api/slice.rst
-@@ -23,7 +23,9 @@
- Return a new slice object with the given values. The *start*, *stop*, and
- *step* parameters are used as the values of the slice object attributes of
- the same names. Any of the values may be ``NULL``, in which case the
-- ``None`` will be used for the corresponding attribute. Return ``NULL`` if
-+ ``None`` will be used for the corresponding attribute.
-+
-+ Return ``NULL`` with an exception set if
- the new object could not be allocated.
-
-
-@@ -52,7 +54,7 @@
- of bounds indices are clipped in a manner consistent with the handling of
- normal slices.
-
-- Returns ``0`` on success and ``-1`` on error with exception set.
-+ Return ``0`` on success and ``-1`` on error with an exception set.
-
- .. note::
- This function is considered not safe for resizable sequences.
-@@ -95,7 +97,7 @@
- ``PY_SSIZE_T_MIN`` to ``PY_SSIZE_T_MIN``, and silently boost the step
- values less than ``-PY_SSIZE_T_MAX`` to ``-PY_SSIZE_T_MAX``.
-
-- Return ``-1`` on error, ``0`` on success.
-+ Return ``-1`` with an exception set on error, ``0`` on success.
-
- .. versionadded:: 3.6.1
-
-diff --git a/Doc/c-api/tuple.rst b/Doc/c-api/tuple.rst
-index e0186c1f522..82ef4bcd147 100644
---- a/Doc/c-api/tuple.rst
-+++ b/Doc/c-api/tuple.rst
-@@ -33,12 +33,14 @@
-
- .. c:function:: PyObject* PyTuple_New(Py_ssize_t len)
-
-- Return a new tuple object of size *len*, or ``NULL`` on failure.
-+ Return a new tuple object of size *len*,
-+ or ``NULL`` with an exception set on failure.
-
-
- .. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...)
-
-- Return a new tuple object of size *n*, or ``NULL`` on failure. The tuple values
-+ Return a new tuple object of size *n*,
-+ or ``NULL`` with an exception set on failure. The tuple values
- are initialized to the subsequent *n* C arguments pointing to Python objects.
- ``PyTuple_Pack(2, a, b)`` is equivalent to ``Py_BuildValue("(OO)", a, b)``.
-
-@@ -46,12 +48,12 @@
- .. c:function:: Py_ssize_t PyTuple_Size(PyObject *p)
-
- Take a pointer to a tuple object, and return the size of that tuple.
-+ On error, return ``-1`` and with an exception set.
-
-
- .. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p)
-
-- Return the size of the tuple *p*, which must be non-``NULL`` and point to a tuple;
-- no error checking is performed.
-+ Like :c:func:`PyTuple_Size`, but without error checking.
-
-
- .. c:function:: PyObject* PyTuple_GetItem(PyObject *p, Py_ssize_t pos)
-@@ -74,8 +76,10 @@
- .. c:function:: PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high)
-
- Return the slice of the tuple pointed to by *p* between *low* and *high*,
-- or ``NULL`` on failure. This is the equivalent of the Python expression
-- ``p[low:high]``. Indexing from the end of the tuple is not supported.
-+ or ``NULL`` with an exception set on failure.
-+
-+ This is the equivalent of the Python expression ``p[low:high]``.
-+ Indexing from the end of the tuple is not supported.
-
-
- .. c:function:: int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o)
-@@ -132,6 +136,8 @@
- Create a new struct sequence type from the data in *desc*, described below. Instances
- of the resulting type can be created with :c:func:`PyStructSequence_New`.
-
-+ Return ``NULL`` with an exception set on failure.
-+
-
- .. c:function:: void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
-
-@@ -140,8 +146,8 @@
-
- .. c:function:: int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
-
-- The same as ``PyStructSequence_InitType``, but returns ``0`` on success and ``-1`` on
-- failure.
-+ Like :c:func:`PyStructSequence_InitType`, but returns ``0`` on success
-+ and ``-1`` with an exception set on failure.
-
- .. versionadded:: 3.4
-
-@@ -198,6 +204,8 @@
- Creates an instance of *type*, which must have been created with
- :c:func:`PyStructSequence_NewType`.
-
-+ Return ``NULL`` with an exception set on failure.
-+
-
- .. c:function:: PyObject* PyStructSequence_GetItem(PyObject *p, Py_ssize_t pos)
-
-diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
-index f6d865f2f52..90896572046 100644
---- a/Doc/c-api/typeobj.rst
-+++ b/Doc/c-api/typeobj.rst
-@@ -1584,7 +1584,7 @@
- weak references to the type object itself.
-
- It is an error to set both the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit and
-- :c:member:`~PyTypeObject.tp_weaklist`.
-+ :c:member:`~PyTypeObject.tp_weaklistoffset`.
-
- **Inheritance:**
-
-@@ -1596,7 +1596,7 @@
- **Default:**
-
- If the :c:macro:`Py_TPFLAGS_MANAGED_WEAKREF` bit is set in the
-- :c:member:`~PyTypeObject.tp_dict` field, then
-+ :c:member:`~PyTypeObject.tp_flags` field, then
- :c:member:`~PyTypeObject.tp_weaklistoffset` will be set to a negative value,
- to indicate that it is unsafe to use this field.
-
-diff --git a/Doc/conf.py b/Doc/conf.py
-index e292bdd5003..319cdf60790 100644
---- a/Doc/conf.py
-+++ b/Doc/conf.py
-@@ -6,9 +6,11 @@
- # The contents of this file are pickled, so don't put values in the namespace
- # that aren't pickleable (module imports are okay, they're removed automatically).
-
-+import importlib
- import os
- import sys
- import time
-+
- sys.path.append(os.path.abspath('tools/extensions'))
- sys.path.append(os.path.abspath('includes'))
-
-@@ -18,11 +20,10 @@
- # ---------------------
-
- extensions = [
-- 'asdl_highlight',
-+ 'audit_events',
- 'c_annotations',
-- 'escape4chm',
- 'glossary_search',
-- 'peg_highlight',
-+ 'lexers',
- 'pyspecific',
- 'sphinx.ext.coverage',
- 'sphinx.ext.doctest',
-@@ -31,7 +32,7 @@
-
- # Skip if downstream redistributors haven't installed it
- try:
-- import sphinxext.opengraph
-+ import sphinxext.opengraph # noqa: F401
- except ImportError:
- pass
- else:
-@@ -58,8 +59,8 @@
-
- # We look for the Include/patchlevel.h file in the current Python source tree
- # and replace the values accordingly.
--import patchlevel
--version, release = patchlevel.get_version_info()
-+# See Doc/tools/extensions/patchlevel.py
-+version, release = importlib.import_module('patchlevel').get_version_info()
-
- rst_epilog = f"""
- .. |python_version_literal| replace:: ``Python {version}``
-@@ -75,7 +76,7 @@
- highlight_language = 'python3'
-
- # Minimum version of sphinx required
--needs_sphinx = '4.2'
-+needs_sphinx = '6.2.1'
-
- # Create table of contents entries for domain objects (e.g. functions, classes,
- # attributes, etc.). Default is True.
-@@ -256,6 +257,9 @@
- ('c:data', 'PyExc_UnicodeWarning'),
- ('c:data', 'PyExc_UserWarning'),
- ('c:data', 'PyExc_Warning'),
-+ # Undocumented public C macros
-+ ('c:macro', 'Py_BUILD_ASSERT'),
-+ ('c:macro', 'Py_BUILD_ASSERT_EXPR'),
- # Do not error nit-picky mode builds when _SubParsersAction.add_parser cannot
- # be resolved, as the method is currently undocumented. For context, see
- # https://github.com/python/cpython/pull/103289.
-@@ -280,7 +284,8 @@
-
- # Disable Docutils smartquotes for several translations
- smartquotes_excludes = {
-- 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'],
-+ 'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'],
-+ 'builders': ['man', 'text'],
- }
-
- # Avoid a warning with Sphinx >= 4.0
-@@ -289,6 +294,7 @@
- # Allow translation of index directives
- gettext_additional_targets = [
- 'index',
-+ 'literal-block',
- ]
-
- # Options for HTML output
-@@ -301,11 +307,13 @@
- 'collapsiblesidebar': True,
- 'issues_url': '/bugs.html',
- 'license_url': '/license.html',
-- 'root_include_title': False # We use the version switcher instead.
-+ 'root_include_title': False, # We use the version switcher instead.
- }
-
- if os.getenv("READTHEDOCS"):
-- html_theme_options["hosted_on"] = 'Read the Docs'
-+ html_theme_options["hosted_on"] = (
-+ 'Read the Docs'
-+ )
-
- # Override stylesheet fingerprinting for Windows CHM htmlhelp to fix GH-91207
- # https://github.com/python/cpython/issues/91207
-@@ -319,15 +327,21 @@
-
- # Deployment preview information
- # (See .readthedocs.yml and https://docs.readthedocs.io/en/stable/reference/environment-variables.html)
--repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL")
-+is_deployment_preview = os.getenv("READTHEDOCS_VERSION_TYPE") == "external"
-+repository_url = os.getenv("READTHEDOCS_GIT_CLONE_URL", "")
-+repository_url = repository_url.removesuffix(".git")
- html_context = {
-- "is_deployment_preview": os.getenv("READTHEDOCS_VERSION_TYPE") == "external",
-- "repository_url": repository_url.removesuffix(".git") if repository_url else None,
-- "pr_id": os.getenv("READTHEDOCS_VERSION")
-+ "is_deployment_preview": is_deployment_preview,
-+ "repository_url": repository_url or None,
-+ "pr_id": os.getenv("READTHEDOCS_VERSION"),
-+ "enable_analytics": os.getenv("PYTHON_DOCS_ENABLE_ANALYTICS"),
- }
-
- # This 'Last updated on:' timestamp is inserted at the bottom of every page.
--html_last_updated_fmt = time.strftime('%b %d, %Y (%H:%M UTC)', time.gmtime())
-+html_time = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
-+html_last_updated_fmt = time.strftime(
-+ '%b %d, %Y (%H:%M UTC)', time.gmtime(html_time)
-+)
-
- # Path to find HTML templates.
- templates_path = ['tools/templates']
-@@ -387,30 +401,70 @@
- # (source start file, target name, title, author, document class [howto/manual]).
- _stdauthor = 'Guido van Rossum and the Python development team'
- latex_documents = [
-- ('c-api/index', 'c-api.tex',
-- 'The Python/C API', _stdauthor, 'manual'),
-- ('extending/index', 'extending.tex',
-- 'Extending and Embedding Python', _stdauthor, 'manual'),
-- ('installing/index', 'installing.tex',
-- 'Installing Python Modules', _stdauthor, 'manual'),
-- ('library/index', 'library.tex',
-- 'The Python Library Reference', _stdauthor, 'manual'),
-- ('reference/index', 'reference.tex',
-- 'The Python Language Reference', _stdauthor, 'manual'),
-- ('tutorial/index', 'tutorial.tex',
-- 'Python Tutorial', _stdauthor, 'manual'),
-- ('using/index', 'using.tex',
-- 'Python Setup and Usage', _stdauthor, 'manual'),
-- ('faq/index', 'faq.tex',
-- 'Python Frequently Asked Questions', _stdauthor, 'manual'),
-- ('whatsnew/' + version, 'whatsnew.tex',
-- 'What\'s New in Python', 'A. M. Kuchling', 'howto'),
-+ ('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'),
-+ (
-+ 'extending/index',
-+ 'extending.tex',
-+ 'Extending and Embedding Python',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'installing/index',
-+ 'installing.tex',
-+ 'Installing Python Modules',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'library/index',
-+ 'library.tex',
-+ 'The Python Library Reference',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'reference/index',
-+ 'reference.tex',
-+ 'The Python Language Reference',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'tutorial/index',
-+ 'tutorial.tex',
-+ 'Python Tutorial',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'using/index',
-+ 'using.tex',
-+ 'Python Setup and Usage',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'faq/index',
-+ 'faq.tex',
-+ 'Python Frequently Asked Questions',
-+ _stdauthor,
-+ 'manual',
-+ ),
-+ (
-+ 'whatsnew/' + version,
-+ 'whatsnew.tex',
-+ 'What\'s New in Python',
-+ 'A. M. Kuchling',
-+ 'howto',
-+ ),
- ]
- # Collect all HOWTOs individually
--latex_documents.extend(('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex',
-- '', _stdauthor, 'howto')
-- for fn in os.listdir('howto')
-- if fn.endswith('.rst') and fn != 'index.rst')
-+latex_documents.extend(
-+ ('howto/' + fn[:-4], 'howto-' + fn[:-4] + '.tex', '', _stdauthor, 'howto')
-+ for fn in os.listdir('howto')
-+ if fn.endswith('.rst') and fn != 'index.rst'
-+)
-
- # Documents to append as an appendix to all manuals.
- latex_appendices = ['glossary', 'about', 'license', 'copyright']
-@@ -439,8 +493,7 @@
- 'test($|_)',
- ]
-
--coverage_ignore_classes = [
--]
-+coverage_ignore_classes = []
-
- # Glob patterns for C source files for C API coverage, relative to this directory.
- coverage_c_path = [
-@@ -457,7 +510,7 @@
- # The coverage checker will ignore all C items whose names match these regexes
- # (using re.match) -- the keys must be the same as in coverage_c_regexes.
- coverage_ignore_c_items = {
--# 'cfunction': [...]
-+ # 'cfunction': [...]
- }
-
-
-@@ -522,14 +575,16 @@
- }
- extlinks_detect_hardcoded_links = True
-
--# Options for extensions
--# ----------------------
-+# Options for c_annotations
-+# -------------------------
-
- # Relative filename of the data files
- refcount_file = 'data/refcounts.dat'
- stable_abi_file = 'data/stable_abi.dat'
-
--# sphinxext-opengraph config
-+# Options for sphinxext-opengraph
-+# -------------------------------
-+
- ogp_site_url = 'https://docs.python.org/3/'
- ogp_site_name = 'Python documentation'
- ogp_image = '_static/og-image.png'
-diff --git a/Doc/constraints.txt b/Doc/constraints.txt
-index 16b735ea07a..26ac1862dba 100644
---- a/Doc/constraints.txt
-+++ b/Doc/constraints.txt
-@@ -7,18 +7,20 @@
- # Direct dependencies of Sphinx
- babel<3
- colorama<0.5
--imagesize<1.5
--Jinja2<3.2
--packaging<24
--Pygments>=2.16.1,<3
-+imagesize<2
-+Jinja2<4
-+packaging<25
-+Pygments<3
- requests<3
- snowballstemmer<3
--sphinxcontrib-applehelp<1.0.5
--sphinxcontrib-devhelp<1.0.6
--sphinxcontrib-htmlhelp<2.0.5
--sphinxcontrib-jsmath<1.1
--sphinxcontrib-qthelp<1.0.7
--sphinxcontrib-serializinghtml<1.1.10
-+# keep lower-bounds until Sphinx 8.1 is released
-+# https://github.com/sphinx-doc/sphinx/pull/12756
-+sphinxcontrib-applehelp>=1.0.7,<3
-+sphinxcontrib-devhelp>=1.0.6,<3
-+sphinxcontrib-htmlhelp>=2.0.6,<3
-+sphinxcontrib-jsmath>=1.0.1,<2
-+sphinxcontrib-qthelp>=1.0.6,<3
-+sphinxcontrib-serializinghtml>=1.1.9,<3
-
- # Direct dependencies of Jinja2 (Jinja is a dependency of Sphinx, see above)
--MarkupSafe<2.2
-+MarkupSafe<3
-diff --git a/Doc/contents.rst b/Doc/contents.rst
-index 24ceacb0076..b57f4b09a5d 100644
---- a/Doc/contents.rst
-+++ b/Doc/contents.rst
-@@ -14,6 +14,7 @@
- installing/index.rst
- howto/index.rst
- faq/index.rst
-+ deprecations/index.rst
- glossary.rst
-
- about.rst
-diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
-index f112d268129..4aa2b35162d 100644
---- a/Doc/data/stable_abi.dat
-+++ b/Doc/data/stable_abi.dat
-@@ -1,868 +1,868 @@
- role,name,added,ifdef_note,struct_abi_kind
- macro,PY_VECTORCALL_ARGUMENTS_OFFSET,3.12,,
--function,PyAIter_Check,3.10,,
--function,PyArg_Parse,3.2,,
--function,PyArg_ParseTuple,3.2,,
--function,PyArg_ParseTupleAndKeywords,3.2,,
--function,PyArg_UnpackTuple,3.2,,
--function,PyArg_VaParse,3.2,,
--function,PyArg_VaParseTupleAndKeywords,3.2,,
--function,PyArg_ValidateKeywordArguments,3.2,,
--var,PyBaseObject_Type,3.2,,
--function,PyBool_FromLong,3.2,,
--var,PyBool_Type,3.2,,
--function,PyBuffer_FillContiguousStrides,3.11,,
--function,PyBuffer_FillInfo,3.11,,
--function,PyBuffer_FromContiguous,3.11,,
--function,PyBuffer_GetPointer,3.11,,
--function,PyBuffer_IsContiguous,3.11,,
--function,PyBuffer_Release,3.11,,
--function,PyBuffer_SizeFromFormat,3.11,,
--function,PyBuffer_ToContiguous,3.11,,
--var,PyByteArrayIter_Type,3.2,,
--function,PyByteArray_AsString,3.2,,
--function,PyByteArray_Concat,3.2,,
--function,PyByteArray_FromObject,3.2,,
--function,PyByteArray_FromStringAndSize,3.2,,
--function,PyByteArray_Resize,3.2,,
--function,PyByteArray_Size,3.2,,
--var,PyByteArray_Type,3.2,,
--var,PyBytesIter_Type,3.2,,
--function,PyBytes_AsString,3.2,,
--function,PyBytes_AsStringAndSize,3.2,,
--function,PyBytes_Concat,3.2,,
--function,PyBytes_ConcatAndDel,3.2,,
--function,PyBytes_DecodeEscape,3.2,,
--function,PyBytes_FromFormat,3.2,,
--function,PyBytes_FromFormatV,3.2,,
--function,PyBytes_FromObject,3.2,,
--function,PyBytes_FromString,3.2,,
--function,PyBytes_FromStringAndSize,3.2,,
--function,PyBytes_Repr,3.2,,
--function,PyBytes_Size,3.2,,
--var,PyBytes_Type,3.2,,
-+func,PyAIter_Check,3.10,,
-+func,PyArg_Parse,3.2,,
-+func,PyArg_ParseTuple,3.2,,
-+func,PyArg_ParseTupleAndKeywords,3.2,,
-+func,PyArg_UnpackTuple,3.2,,
-+func,PyArg_VaParse,3.2,,
-+func,PyArg_VaParseTupleAndKeywords,3.2,,
-+func,PyArg_ValidateKeywordArguments,3.2,,
-+data,PyBaseObject_Type,3.2,,
-+func,PyBool_FromLong,3.2,,
-+data,PyBool_Type,3.2,,
-+func,PyBuffer_FillContiguousStrides,3.11,,
-+func,PyBuffer_FillInfo,3.11,,
-+func,PyBuffer_FromContiguous,3.11,,
-+func,PyBuffer_GetPointer,3.11,,
-+func,PyBuffer_IsContiguous,3.11,,
-+func,PyBuffer_Release,3.11,,
-+func,PyBuffer_SizeFromFormat,3.11,,
-+func,PyBuffer_ToContiguous,3.11,,
-+data,PyByteArrayIter_Type,3.2,,
-+func,PyByteArray_AsString,3.2,,
-+func,PyByteArray_Concat,3.2,,
-+func,PyByteArray_FromObject,3.2,,
-+func,PyByteArray_FromStringAndSize,3.2,,
-+func,PyByteArray_Resize,3.2,,
-+func,PyByteArray_Size,3.2,,
-+data,PyByteArray_Type,3.2,,
-+data,PyBytesIter_Type,3.2,,
-+func,PyBytes_AsString,3.2,,
-+func,PyBytes_AsStringAndSize,3.2,,
-+func,PyBytes_Concat,3.2,,
-+func,PyBytes_ConcatAndDel,3.2,,
-+func,PyBytes_DecodeEscape,3.2,,
-+func,PyBytes_FromFormat,3.2,,
-+func,PyBytes_FromFormatV,3.2,,
-+func,PyBytes_FromObject,3.2,,
-+func,PyBytes_FromString,3.2,,
-+func,PyBytes_FromStringAndSize,3.2,,
-+func,PyBytes_Repr,3.2,,
-+func,PyBytes_Size,3.2,,
-+data,PyBytes_Type,3.2,,
- type,PyCFunction,3.2,,
- type,PyCFunctionWithKeywords,3.2,,
--function,PyCFunction_Call,3.2,,
--function,PyCFunction_GetFlags,3.2,,
--function,PyCFunction_GetFunction,3.2,,
--function,PyCFunction_GetSelf,3.2,,
--function,PyCFunction_New,3.4,,
--function,PyCFunction_NewEx,3.2,,
--var,PyCFunction_Type,3.2,,
--function,PyCMethod_New,3.9,,
--function,PyCallIter_New,3.2,,
--var,PyCallIter_Type,3.2,,
--function,PyCallable_Check,3.2,,
-+func,PyCFunction_Call,3.2,,
-+func,PyCFunction_GetFlags,3.2,,
-+func,PyCFunction_GetFunction,3.2,,
-+func,PyCFunction_GetSelf,3.2,,
-+func,PyCFunction_New,3.4,,
-+func,PyCFunction_NewEx,3.2,,
-+data,PyCFunction_Type,3.2,,
-+func,PyCMethod_New,3.9,,
-+func,PyCallIter_New,3.2,,
-+data,PyCallIter_Type,3.2,,
-+func,PyCallable_Check,3.2,,
- type,PyCapsule_Destructor,3.2,,
--function,PyCapsule_GetContext,3.2,,
--function,PyCapsule_GetDestructor,3.2,,
--function,PyCapsule_GetName,3.2,,
--function,PyCapsule_GetPointer,3.2,,
--function,PyCapsule_Import,3.2,,
--function,PyCapsule_IsValid,3.2,,
--function,PyCapsule_New,3.2,,
--function,PyCapsule_SetContext,3.2,,
--function,PyCapsule_SetDestructor,3.2,,
--function,PyCapsule_SetName,3.2,,
--function,PyCapsule_SetPointer,3.2,,
--var,PyCapsule_Type,3.2,,
--var,PyClassMethodDescr_Type,3.2,,
--function,PyCodec_BackslashReplaceErrors,3.2,,
--function,PyCodec_Decode,3.2,,
--function,PyCodec_Decoder,3.2,,
--function,PyCodec_Encode,3.2,,
--function,PyCodec_Encoder,3.2,,
--function,PyCodec_IgnoreErrors,3.2,,
--function,PyCodec_IncrementalDecoder,3.2,,
--function,PyCodec_IncrementalEncoder,3.2,,
--function,PyCodec_KnownEncoding,3.2,,
--function,PyCodec_LookupError,3.2,,
--function,PyCodec_NameReplaceErrors,3.7,,
--function,PyCodec_Register,3.2,,
--function,PyCodec_RegisterError,3.2,,
--function,PyCodec_ReplaceErrors,3.2,,
--function,PyCodec_StreamReader,3.2,,
--function,PyCodec_StreamWriter,3.2,,
--function,PyCodec_StrictErrors,3.2,,
--function,PyCodec_Unregister,3.10,,
--function,PyCodec_XMLCharRefReplaceErrors,3.2,,
--function,PyComplex_FromDoubles,3.2,,
--function,PyComplex_ImagAsDouble,3.2,,
--function,PyComplex_RealAsDouble,3.2,,
--var,PyComplex_Type,3.2,,
--function,PyDescr_NewClassMethod,3.2,,
--function,PyDescr_NewGetSet,3.2,,
--function,PyDescr_NewMember,3.2,,
--function,PyDescr_NewMethod,3.2,,
--var,PyDictItems_Type,3.2,,
--var,PyDictIterItem_Type,3.2,,
--var,PyDictIterKey_Type,3.2,,
--var,PyDictIterValue_Type,3.2,,
--var,PyDictKeys_Type,3.2,,
--function,PyDictProxy_New,3.2,,
--var,PyDictProxy_Type,3.2,,
--var,PyDictRevIterItem_Type,3.8,,
--var,PyDictRevIterKey_Type,3.8,,
--var,PyDictRevIterValue_Type,3.8,,
--var,PyDictValues_Type,3.2,,
--function,PyDict_Clear,3.2,,
--function,PyDict_Contains,3.2,,
--function,PyDict_Copy,3.2,,
--function,PyDict_DelItem,3.2,,
--function,PyDict_DelItemString,3.2,,
--function,PyDict_GetItem,3.2,,
--function,PyDict_GetItemString,3.2,,
--function,PyDict_GetItemWithError,3.2,,
--function,PyDict_Items,3.2,,
--function,PyDict_Keys,3.2,,
--function,PyDict_Merge,3.2,,
--function,PyDict_MergeFromSeq2,3.2,,
--function,PyDict_New,3.2,,
--function,PyDict_Next,3.2,,
--function,PyDict_SetItem,3.2,,
--function,PyDict_SetItemString,3.2,,
--function,PyDict_Size,3.2,,
--var,PyDict_Type,3.2,,
--function,PyDict_Update,3.2,,
--function,PyDict_Values,3.2,,
--var,PyEllipsis_Type,3.2,,
--var,PyEnum_Type,3.2,,
--function,PyErr_BadArgument,3.2,,
--function,PyErr_BadInternalCall,3.2,,
--function,PyErr_CheckSignals,3.2,,
--function,PyErr_Clear,3.2,,
--function,PyErr_Display,3.2,,
--function,PyErr_DisplayException,3.12,,
--function,PyErr_ExceptionMatches,3.2,,
--function,PyErr_Fetch,3.2,,
--function,PyErr_Format,3.2,,
--function,PyErr_FormatV,3.5,,
--function,PyErr_GetExcInfo,3.7,,
--function,PyErr_GetHandledException,3.11,,
--function,PyErr_GetRaisedException,3.12,,
--function,PyErr_GivenExceptionMatches,3.2,,
--function,PyErr_NewException,3.2,,
--function,PyErr_NewExceptionWithDoc,3.2,,
--function,PyErr_NoMemory,3.2,,
--function,PyErr_NormalizeException,3.2,,
--function,PyErr_Occurred,3.2,,
--function,PyErr_Print,3.2,,
--function,PyErr_PrintEx,3.2,,
--function,PyErr_ProgramText,3.2,,
--function,PyErr_ResourceWarning,3.6,,
--function,PyErr_Restore,3.2,,
--function,PyErr_SetExcFromWindowsErr,3.7,on Windows,
--function,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows,
--function,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows,
--function,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows,
--function,PyErr_SetExcInfo,3.7,,
--function,PyErr_SetFromErrno,3.2,,
--function,PyErr_SetFromErrnoWithFilename,3.2,,
--function,PyErr_SetFromErrnoWithFilenameObject,3.2,,
--function,PyErr_SetFromErrnoWithFilenameObjects,3.7,,
--function,PyErr_SetFromWindowsErr,3.7,on Windows,
--function,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows,
--function,PyErr_SetHandledException,3.11,,
--function,PyErr_SetImportError,3.7,,
--function,PyErr_SetImportErrorSubclass,3.6,,
--function,PyErr_SetInterrupt,3.2,,
--function,PyErr_SetInterruptEx,3.10,,
--function,PyErr_SetNone,3.2,,
--function,PyErr_SetObject,3.2,,
--function,PyErr_SetRaisedException,3.12,,
--function,PyErr_SetString,3.2,,
--function,PyErr_SyntaxLocation,3.2,,
--function,PyErr_SyntaxLocationEx,3.7,,
--function,PyErr_WarnEx,3.2,,
--function,PyErr_WarnExplicit,3.2,,
--function,PyErr_WarnFormat,3.2,,
--function,PyErr_WriteUnraisable,3.2,,
--function,PyEval_AcquireLock,3.2,,
--function,PyEval_AcquireThread,3.2,,
--function,PyEval_CallFunction,3.2,,
--function,PyEval_CallMethod,3.2,,
--function,PyEval_CallObjectWithKeywords,3.2,,
--function,PyEval_EvalCode,3.2,,
--function,PyEval_EvalCodeEx,3.2,,
--function,PyEval_EvalFrame,3.2,,
--function,PyEval_EvalFrameEx,3.2,,
--function,PyEval_GetBuiltins,3.2,,
--function,PyEval_GetFrame,3.2,,
--function,PyEval_GetFuncDesc,3.2,,
--function,PyEval_GetFuncName,3.2,,
--function,PyEval_GetGlobals,3.2,,
--function,PyEval_GetLocals,3.2,,
--function,PyEval_InitThreads,3.2,,
--function,PyEval_ReleaseLock,3.2,,
--function,PyEval_ReleaseThread,3.2,,
--function,PyEval_RestoreThread,3.2,,
--function,PyEval_SaveThread,3.2,,
--function,PyEval_ThreadsInitialized,3.2,,
--var,PyExc_ArithmeticError,3.2,,
--var,PyExc_AssertionError,3.2,,
--var,PyExc_AttributeError,3.2,,
--var,PyExc_BaseException,3.2,,
--var,PyExc_BaseExceptionGroup,3.11,,
--var,PyExc_BlockingIOError,3.7,,
--var,PyExc_BrokenPipeError,3.7,,
--var,PyExc_BufferError,3.2,,
--var,PyExc_BytesWarning,3.2,,
--var,PyExc_ChildProcessError,3.7,,
--var,PyExc_ConnectionAbortedError,3.7,,
--var,PyExc_ConnectionError,3.7,,
--var,PyExc_ConnectionRefusedError,3.7,,
--var,PyExc_ConnectionResetError,3.7,,
--var,PyExc_DeprecationWarning,3.2,,
--var,PyExc_EOFError,3.2,,
--var,PyExc_EncodingWarning,3.10,,
--var,PyExc_EnvironmentError,3.2,,
--var,PyExc_Exception,3.2,,
--var,PyExc_FileExistsError,3.7,,
--var,PyExc_FileNotFoundError,3.7,,
--var,PyExc_FloatingPointError,3.2,,
--var,PyExc_FutureWarning,3.2,,
--var,PyExc_GeneratorExit,3.2,,
--var,PyExc_IOError,3.2,,
--var,PyExc_ImportError,3.2,,
--var,PyExc_ImportWarning,3.2,,
--var,PyExc_IndentationError,3.2,,
--var,PyExc_IndexError,3.2,,
--var,PyExc_InterruptedError,3.7,,
--var,PyExc_IsADirectoryError,3.7,,
--var,PyExc_KeyError,3.2,,
--var,PyExc_KeyboardInterrupt,3.2,,
--var,PyExc_LookupError,3.2,,
--var,PyExc_MemoryError,3.2,,
--var,PyExc_ModuleNotFoundError,3.6,,
--var,PyExc_NameError,3.2,,
--var,PyExc_NotADirectoryError,3.7,,
--var,PyExc_NotImplementedError,3.2,,
--var,PyExc_OSError,3.2,,
--var,PyExc_OverflowError,3.2,,
--var,PyExc_PendingDeprecationWarning,3.2,,
--var,PyExc_PermissionError,3.7,,
--var,PyExc_ProcessLookupError,3.7,,
--var,PyExc_RecursionError,3.7,,
--var,PyExc_ReferenceError,3.2,,
--var,PyExc_ResourceWarning,3.7,,
--var,PyExc_RuntimeError,3.2,,
--var,PyExc_RuntimeWarning,3.2,,
--var,PyExc_StopAsyncIteration,3.7,,
--var,PyExc_StopIteration,3.2,,
--var,PyExc_SyntaxError,3.2,,
--var,PyExc_SyntaxWarning,3.2,,
--var,PyExc_SystemError,3.2,,
--var,PyExc_SystemExit,3.2,,
--var,PyExc_TabError,3.2,,
--var,PyExc_TimeoutError,3.7,,
--var,PyExc_TypeError,3.2,,
--var,PyExc_UnboundLocalError,3.2,,
--var,PyExc_UnicodeDecodeError,3.2,,
--var,PyExc_UnicodeEncodeError,3.2,,
--var,PyExc_UnicodeError,3.2,,
--var,PyExc_UnicodeTranslateError,3.2,,
--var,PyExc_UnicodeWarning,3.2,,
--var,PyExc_UserWarning,3.2,,
--var,PyExc_ValueError,3.2,,
--var,PyExc_Warning,3.2,,
--var,PyExc_WindowsError,3.7,on Windows,
--var,PyExc_ZeroDivisionError,3.2,,
--function,PyExceptionClass_Name,3.8,,
--function,PyException_GetArgs,3.12,,
--function,PyException_GetCause,3.2,,
--function,PyException_GetContext,3.2,,
--function,PyException_GetTraceback,3.2,,
--function,PyException_SetArgs,3.12,,
--function,PyException_SetCause,3.2,,
--function,PyException_SetContext,3.2,,
--function,PyException_SetTraceback,3.2,,
--function,PyFile_FromFd,3.2,,
--function,PyFile_GetLine,3.2,,
--function,PyFile_WriteObject,3.2,,
--function,PyFile_WriteString,3.2,,
--var,PyFilter_Type,3.2,,
--function,PyFloat_AsDouble,3.2,,
--function,PyFloat_FromDouble,3.2,,
--function,PyFloat_FromString,3.2,,
--function,PyFloat_GetInfo,3.2,,
--function,PyFloat_GetMax,3.2,,
--function,PyFloat_GetMin,3.2,,
--var,PyFloat_Type,3.2,,
-+func,PyCapsule_GetContext,3.2,,
-+func,PyCapsule_GetDestructor,3.2,,
-+func,PyCapsule_GetName,3.2,,
-+func,PyCapsule_GetPointer,3.2,,
-+func,PyCapsule_Import,3.2,,
-+func,PyCapsule_IsValid,3.2,,
-+func,PyCapsule_New,3.2,,
-+func,PyCapsule_SetContext,3.2,,
-+func,PyCapsule_SetDestructor,3.2,,
-+func,PyCapsule_SetName,3.2,,
-+func,PyCapsule_SetPointer,3.2,,
-+data,PyCapsule_Type,3.2,,
-+data,PyClassMethodDescr_Type,3.2,,
-+func,PyCodec_BackslashReplaceErrors,3.2,,
-+func,PyCodec_Decode,3.2,,
-+func,PyCodec_Decoder,3.2,,
-+func,PyCodec_Encode,3.2,,
-+func,PyCodec_Encoder,3.2,,
-+func,PyCodec_IgnoreErrors,3.2,,
-+func,PyCodec_IncrementalDecoder,3.2,,
-+func,PyCodec_IncrementalEncoder,3.2,,
-+func,PyCodec_KnownEncoding,3.2,,
-+func,PyCodec_LookupError,3.2,,
-+func,PyCodec_NameReplaceErrors,3.7,,
-+func,PyCodec_Register,3.2,,
-+func,PyCodec_RegisterError,3.2,,
-+func,PyCodec_ReplaceErrors,3.2,,
-+func,PyCodec_StreamReader,3.2,,
-+func,PyCodec_StreamWriter,3.2,,
-+func,PyCodec_StrictErrors,3.2,,
-+func,PyCodec_Unregister,3.10,,
-+func,PyCodec_XMLCharRefReplaceErrors,3.2,,
-+func,PyComplex_FromDoubles,3.2,,
-+func,PyComplex_ImagAsDouble,3.2,,
-+func,PyComplex_RealAsDouble,3.2,,
-+data,PyComplex_Type,3.2,,
-+func,PyDescr_NewClassMethod,3.2,,
-+func,PyDescr_NewGetSet,3.2,,
-+func,PyDescr_NewMember,3.2,,
-+func,PyDescr_NewMethod,3.2,,
-+data,PyDictItems_Type,3.2,,
-+data,PyDictIterItem_Type,3.2,,
-+data,PyDictIterKey_Type,3.2,,
-+data,PyDictIterValue_Type,3.2,,
-+data,PyDictKeys_Type,3.2,,
-+func,PyDictProxy_New,3.2,,
-+data,PyDictProxy_Type,3.2,,
-+data,PyDictRevIterItem_Type,3.8,,
-+data,PyDictRevIterKey_Type,3.8,,
-+data,PyDictRevIterValue_Type,3.8,,
-+data,PyDictValues_Type,3.2,,
-+func,PyDict_Clear,3.2,,
-+func,PyDict_Contains,3.2,,
-+func,PyDict_Copy,3.2,,
-+func,PyDict_DelItem,3.2,,
-+func,PyDict_DelItemString,3.2,,
-+func,PyDict_GetItem,3.2,,
-+func,PyDict_GetItemString,3.2,,
-+func,PyDict_GetItemWithError,3.2,,
-+func,PyDict_Items,3.2,,
-+func,PyDict_Keys,3.2,,
-+func,PyDict_Merge,3.2,,
-+func,PyDict_MergeFromSeq2,3.2,,
-+func,PyDict_New,3.2,,
-+func,PyDict_Next,3.2,,
-+func,PyDict_SetItem,3.2,,
-+func,PyDict_SetItemString,3.2,,
-+func,PyDict_Size,3.2,,
-+data,PyDict_Type,3.2,,
-+func,PyDict_Update,3.2,,
-+func,PyDict_Values,3.2,,
-+data,PyEllipsis_Type,3.2,,
-+data,PyEnum_Type,3.2,,
-+func,PyErr_BadArgument,3.2,,
-+func,PyErr_BadInternalCall,3.2,,
-+func,PyErr_CheckSignals,3.2,,
-+func,PyErr_Clear,3.2,,
-+func,PyErr_Display,3.2,,
-+func,PyErr_DisplayException,3.12,,
-+func,PyErr_ExceptionMatches,3.2,,
-+func,PyErr_Fetch,3.2,,
-+func,PyErr_Format,3.2,,
-+func,PyErr_FormatV,3.5,,
-+func,PyErr_GetExcInfo,3.7,,
-+func,PyErr_GetHandledException,3.11,,
-+func,PyErr_GetRaisedException,3.12,,
-+func,PyErr_GivenExceptionMatches,3.2,,
-+func,PyErr_NewException,3.2,,
-+func,PyErr_NewExceptionWithDoc,3.2,,
-+func,PyErr_NoMemory,3.2,,
-+func,PyErr_NormalizeException,3.2,,
-+func,PyErr_Occurred,3.2,,
-+func,PyErr_Print,3.2,,
-+func,PyErr_PrintEx,3.2,,
-+func,PyErr_ProgramText,3.2,,
-+func,PyErr_ResourceWarning,3.6,,
-+func,PyErr_Restore,3.2,,
-+func,PyErr_SetExcFromWindowsErr,3.7,on Windows,
-+func,PyErr_SetExcFromWindowsErrWithFilename,3.7,on Windows,
-+func,PyErr_SetExcFromWindowsErrWithFilenameObject,3.7,on Windows,
-+func,PyErr_SetExcFromWindowsErrWithFilenameObjects,3.7,on Windows,
-+func,PyErr_SetExcInfo,3.7,,
-+func,PyErr_SetFromErrno,3.2,,
-+func,PyErr_SetFromErrnoWithFilename,3.2,,
-+func,PyErr_SetFromErrnoWithFilenameObject,3.2,,
-+func,PyErr_SetFromErrnoWithFilenameObjects,3.7,,
-+func,PyErr_SetFromWindowsErr,3.7,on Windows,
-+func,PyErr_SetFromWindowsErrWithFilename,3.7,on Windows,
-+func,PyErr_SetHandledException,3.11,,
-+func,PyErr_SetImportError,3.7,,
-+func,PyErr_SetImportErrorSubclass,3.6,,
-+func,PyErr_SetInterrupt,3.2,,
-+func,PyErr_SetInterruptEx,3.10,,
-+func,PyErr_SetNone,3.2,,
-+func,PyErr_SetObject,3.2,,
-+func,PyErr_SetRaisedException,3.12,,
-+func,PyErr_SetString,3.2,,
-+func,PyErr_SyntaxLocation,3.2,,
-+func,PyErr_SyntaxLocationEx,3.7,,
-+func,PyErr_WarnEx,3.2,,
-+func,PyErr_WarnExplicit,3.2,,
-+func,PyErr_WarnFormat,3.2,,
-+func,PyErr_WriteUnraisable,3.2,,
-+func,PyEval_AcquireLock,3.2,,
-+func,PyEval_AcquireThread,3.2,,
-+func,PyEval_CallFunction,3.2,,
-+func,PyEval_CallMethod,3.2,,
-+func,PyEval_CallObjectWithKeywords,3.2,,
-+func,PyEval_EvalCode,3.2,,
-+func,PyEval_EvalCodeEx,3.2,,
-+func,PyEval_EvalFrame,3.2,,
-+func,PyEval_EvalFrameEx,3.2,,
-+func,PyEval_GetBuiltins,3.2,,
-+func,PyEval_GetFrame,3.2,,
-+func,PyEval_GetFuncDesc,3.2,,
-+func,PyEval_GetFuncName,3.2,,
-+func,PyEval_GetGlobals,3.2,,
-+func,PyEval_GetLocals,3.2,,
-+func,PyEval_InitThreads,3.2,,
-+func,PyEval_ReleaseLock,3.2,,
-+func,PyEval_ReleaseThread,3.2,,
-+func,PyEval_RestoreThread,3.2,,
-+func,PyEval_SaveThread,3.2,,
-+func,PyEval_ThreadsInitialized,3.2,,
-+data,PyExc_ArithmeticError,3.2,,
-+data,PyExc_AssertionError,3.2,,
-+data,PyExc_AttributeError,3.2,,
-+data,PyExc_BaseException,3.2,,
-+data,PyExc_BaseExceptionGroup,3.11,,
-+data,PyExc_BlockingIOError,3.7,,
-+data,PyExc_BrokenPipeError,3.7,,
-+data,PyExc_BufferError,3.2,,
-+data,PyExc_BytesWarning,3.2,,
-+data,PyExc_ChildProcessError,3.7,,
-+data,PyExc_ConnectionAbortedError,3.7,,
-+data,PyExc_ConnectionError,3.7,,
-+data,PyExc_ConnectionRefusedError,3.7,,
-+data,PyExc_ConnectionResetError,3.7,,
-+data,PyExc_DeprecationWarning,3.2,,
-+data,PyExc_EOFError,3.2,,
-+data,PyExc_EncodingWarning,3.10,,
-+data,PyExc_EnvironmentError,3.2,,
-+data,PyExc_Exception,3.2,,
-+data,PyExc_FileExistsError,3.7,,
-+data,PyExc_FileNotFoundError,3.7,,
-+data,PyExc_FloatingPointError,3.2,,
-+data,PyExc_FutureWarning,3.2,,
-+data,PyExc_GeneratorExit,3.2,,
-+data,PyExc_IOError,3.2,,
-+data,PyExc_ImportError,3.2,,
-+data,PyExc_ImportWarning,3.2,,
-+data,PyExc_IndentationError,3.2,,
-+data,PyExc_IndexError,3.2,,
-+data,PyExc_InterruptedError,3.7,,
-+data,PyExc_IsADirectoryError,3.7,,
-+data,PyExc_KeyError,3.2,,
-+data,PyExc_KeyboardInterrupt,3.2,,
-+data,PyExc_LookupError,3.2,,
-+data,PyExc_MemoryError,3.2,,
-+data,PyExc_ModuleNotFoundError,3.6,,
-+data,PyExc_NameError,3.2,,
-+data,PyExc_NotADirectoryError,3.7,,
-+data,PyExc_NotImplementedError,3.2,,
-+data,PyExc_OSError,3.2,,
-+data,PyExc_OverflowError,3.2,,
-+data,PyExc_PendingDeprecationWarning,3.2,,
-+data,PyExc_PermissionError,3.7,,
-+data,PyExc_ProcessLookupError,3.7,,
-+data,PyExc_RecursionError,3.7,,
-+data,PyExc_ReferenceError,3.2,,
-+data,PyExc_ResourceWarning,3.7,,
-+data,PyExc_RuntimeError,3.2,,
-+data,PyExc_RuntimeWarning,3.2,,
-+data,PyExc_StopAsyncIteration,3.7,,
-+data,PyExc_StopIteration,3.2,,
-+data,PyExc_SyntaxError,3.2,,
-+data,PyExc_SyntaxWarning,3.2,,
-+data,PyExc_SystemError,3.2,,
-+data,PyExc_SystemExit,3.2,,
-+data,PyExc_TabError,3.2,,
-+data,PyExc_TimeoutError,3.7,,
-+data,PyExc_TypeError,3.2,,
-+data,PyExc_UnboundLocalError,3.2,,
-+data,PyExc_UnicodeDecodeError,3.2,,
-+data,PyExc_UnicodeEncodeError,3.2,,
-+data,PyExc_UnicodeError,3.2,,
-+data,PyExc_UnicodeTranslateError,3.2,,
-+data,PyExc_UnicodeWarning,3.2,,
-+data,PyExc_UserWarning,3.2,,
-+data,PyExc_ValueError,3.2,,
-+data,PyExc_Warning,3.2,,
-+data,PyExc_WindowsError,3.7,on Windows,
-+data,PyExc_ZeroDivisionError,3.2,,
-+func,PyExceptionClass_Name,3.8,,
-+func,PyException_GetArgs,3.12,,
-+func,PyException_GetCause,3.2,,
-+func,PyException_GetContext,3.2,,
-+func,PyException_GetTraceback,3.2,,
-+func,PyException_SetArgs,3.12,,
-+func,PyException_SetCause,3.2,,
-+func,PyException_SetContext,3.2,,
-+func,PyException_SetTraceback,3.2,,
-+func,PyFile_FromFd,3.2,,
-+func,PyFile_GetLine,3.2,,
-+func,PyFile_WriteObject,3.2,,
-+func,PyFile_WriteString,3.2,,
-+data,PyFilter_Type,3.2,,
-+func,PyFloat_AsDouble,3.2,,
-+func,PyFloat_FromDouble,3.2,,
-+func,PyFloat_FromString,3.2,,
-+func,PyFloat_GetInfo,3.2,,
-+func,PyFloat_GetMax,3.2,,
-+func,PyFloat_GetMin,3.2,,
-+data,PyFloat_Type,3.2,,
- type,PyFrameObject,3.2,,opaque
--function,PyFrame_GetCode,3.10,,
--function,PyFrame_GetLineNumber,3.10,,
--function,PyFrozenSet_New,3.2,,
--var,PyFrozenSet_Type,3.2,,
--function,PyGC_Collect,3.2,,
--function,PyGC_Disable,3.10,,
--function,PyGC_Enable,3.10,,
--function,PyGC_IsEnabled,3.10,,
--function,PyGILState_Ensure,3.2,,
--function,PyGILState_GetThisThreadState,3.2,,
--function,PyGILState_Release,3.2,,
-+func,PyFrame_GetCode,3.10,,
-+func,PyFrame_GetLineNumber,3.10,,
-+func,PyFrozenSet_New,3.2,,
-+data,PyFrozenSet_Type,3.2,,
-+func,PyGC_Collect,3.2,,
-+func,PyGC_Disable,3.10,,
-+func,PyGC_Enable,3.10,,
-+func,PyGC_IsEnabled,3.10,,
-+func,PyGILState_Ensure,3.2,,
-+func,PyGILState_GetThisThreadState,3.2,,
-+func,PyGILState_Release,3.2,,
- type,PyGILState_STATE,3.2,,
- type,PyGetSetDef,3.2,,full-abi
--var,PyGetSetDescr_Type,3.2,,
--function,PyImport_AddModule,3.2,,
--function,PyImport_AddModuleObject,3.7,,
--function,PyImport_AppendInittab,3.2,,
--function,PyImport_ExecCodeModule,3.2,,
--function,PyImport_ExecCodeModuleEx,3.2,,
--function,PyImport_ExecCodeModuleObject,3.7,,
--function,PyImport_ExecCodeModuleWithPathnames,3.2,,
--function,PyImport_GetImporter,3.2,,
--function,PyImport_GetMagicNumber,3.2,,
--function,PyImport_GetMagicTag,3.2,,
--function,PyImport_GetModule,3.8,,
--function,PyImport_GetModuleDict,3.2,,
--function,PyImport_Import,3.2,,
--function,PyImport_ImportFrozenModule,3.2,,
--function,PyImport_ImportFrozenModuleObject,3.7,,
--function,PyImport_ImportModule,3.2,,
--function,PyImport_ImportModuleLevel,3.2,,
--function,PyImport_ImportModuleLevelObject,3.7,,
--function,PyImport_ImportModuleNoBlock,3.2,,
--function,PyImport_ReloadModule,3.2,,
--function,PyIndex_Check,3.8,,
-+data,PyGetSetDescr_Type,3.2,,
-+func,PyImport_AddModule,3.2,,
-+func,PyImport_AddModuleObject,3.7,,
-+func,PyImport_AppendInittab,3.2,,
-+func,PyImport_ExecCodeModule,3.2,,
-+func,PyImport_ExecCodeModuleEx,3.2,,
-+func,PyImport_ExecCodeModuleObject,3.7,,
-+func,PyImport_ExecCodeModuleWithPathnames,3.2,,
-+func,PyImport_GetImporter,3.2,,
-+func,PyImport_GetMagicNumber,3.2,,
-+func,PyImport_GetMagicTag,3.2,,
-+func,PyImport_GetModule,3.8,,
-+func,PyImport_GetModuleDict,3.2,,
-+func,PyImport_Import,3.2,,
-+func,PyImport_ImportFrozenModule,3.2,,
-+func,PyImport_ImportFrozenModuleObject,3.7,,
-+func,PyImport_ImportModule,3.2,,
-+func,PyImport_ImportModuleLevel,3.2,,
-+func,PyImport_ImportModuleLevelObject,3.7,,
-+func,PyImport_ImportModuleNoBlock,3.2,,
-+func,PyImport_ReloadModule,3.2,,
-+func,PyIndex_Check,3.8,,
- type,PyInterpreterState,3.2,,opaque
--function,PyInterpreterState_Clear,3.2,,
--function,PyInterpreterState_Delete,3.2,,
--function,PyInterpreterState_Get,3.9,,
--function,PyInterpreterState_GetDict,3.8,,
--function,PyInterpreterState_GetID,3.7,,
--function,PyInterpreterState_New,3.2,,
--function,PyIter_Check,3.8,,
--function,PyIter_Next,3.2,,
--function,PyIter_Send,3.10,,
--var,PyListIter_Type,3.2,,
--var,PyListRevIter_Type,3.2,,
--function,PyList_Append,3.2,,
--function,PyList_AsTuple,3.2,,
--function,PyList_GetItem,3.2,,
--function,PyList_GetSlice,3.2,,
--function,PyList_Insert,3.2,,
--function,PyList_New,3.2,,
--function,PyList_Reverse,3.2,,
--function,PyList_SetItem,3.2,,
--function,PyList_SetSlice,3.2,,
--function,PyList_Size,3.2,,
--function,PyList_Sort,3.2,,
--var,PyList_Type,3.2,,
-+func,PyInterpreterState_Clear,3.2,,
-+func,PyInterpreterState_Delete,3.2,,
-+func,PyInterpreterState_Get,3.9,,
-+func,PyInterpreterState_GetDict,3.8,,
-+func,PyInterpreterState_GetID,3.7,,
-+func,PyInterpreterState_New,3.2,,
-+func,PyIter_Check,3.8,,
-+func,PyIter_Next,3.2,,
-+func,PyIter_Send,3.10,,
-+data,PyListIter_Type,3.2,,
-+data,PyListRevIter_Type,3.2,,
-+func,PyList_Append,3.2,,
-+func,PyList_AsTuple,3.2,,
-+func,PyList_GetItem,3.2,,
-+func,PyList_GetSlice,3.2,,
-+func,PyList_Insert,3.2,,
-+func,PyList_New,3.2,,
-+func,PyList_Reverse,3.2,,
-+func,PyList_SetItem,3.2,,
-+func,PyList_SetSlice,3.2,,
-+func,PyList_Size,3.2,,
-+func,PyList_Sort,3.2,,
-+data,PyList_Type,3.2,,
- type,PyLongObject,3.2,,opaque
--var,PyLongRangeIter_Type,3.2,,
--function,PyLong_AsDouble,3.2,,
--function,PyLong_AsLong,3.2,,
--function,PyLong_AsLongAndOverflow,3.2,,
--function,PyLong_AsLongLong,3.2,,
--function,PyLong_AsLongLongAndOverflow,3.2,,
--function,PyLong_AsSize_t,3.2,,
--function,PyLong_AsSsize_t,3.2,,
--function,PyLong_AsUnsignedLong,3.2,,
--function,PyLong_AsUnsignedLongLong,3.2,,
--function,PyLong_AsUnsignedLongLongMask,3.2,,
--function,PyLong_AsUnsignedLongMask,3.2,,
--function,PyLong_AsVoidPtr,3.2,,
--function,PyLong_FromDouble,3.2,,
--function,PyLong_FromLong,3.2,,
--function,PyLong_FromLongLong,3.2,,
--function,PyLong_FromSize_t,3.2,,
--function,PyLong_FromSsize_t,3.2,,
--function,PyLong_FromString,3.2,,
--function,PyLong_FromUnsignedLong,3.2,,
--function,PyLong_FromUnsignedLongLong,3.2,,
--function,PyLong_FromVoidPtr,3.2,,
--function,PyLong_GetInfo,3.2,,
--var,PyLong_Type,3.2,,
--var,PyMap_Type,3.2,,
--function,PyMapping_Check,3.2,,
--function,PyMapping_GetItemString,3.2,,
--function,PyMapping_HasKey,3.2,,
--function,PyMapping_HasKeyString,3.2,,
--function,PyMapping_Items,3.2,,
--function,PyMapping_Keys,3.2,,
--function,PyMapping_Length,3.2,,
--function,PyMapping_SetItemString,3.2,,
--function,PyMapping_Size,3.2,,
--function,PyMapping_Values,3.2,,
--function,PyMem_Calloc,3.7,,
--function,PyMem_Free,3.2,,
--function,PyMem_Malloc,3.2,,
--function,PyMem_Realloc,3.2,,
-+data,PyLongRangeIter_Type,3.2,,
-+func,PyLong_AsDouble,3.2,,
-+func,PyLong_AsLong,3.2,,
-+func,PyLong_AsLongAndOverflow,3.2,,
-+func,PyLong_AsLongLong,3.2,,
-+func,PyLong_AsLongLongAndOverflow,3.2,,
-+func,PyLong_AsSize_t,3.2,,
-+func,PyLong_AsSsize_t,3.2,,
-+func,PyLong_AsUnsignedLong,3.2,,
-+func,PyLong_AsUnsignedLongLong,3.2,,
-+func,PyLong_AsUnsignedLongLongMask,3.2,,
-+func,PyLong_AsUnsignedLongMask,3.2,,
-+func,PyLong_AsVoidPtr,3.2,,
-+func,PyLong_FromDouble,3.2,,
-+func,PyLong_FromLong,3.2,,
-+func,PyLong_FromLongLong,3.2,,
-+func,PyLong_FromSize_t,3.2,,
-+func,PyLong_FromSsize_t,3.2,,
-+func,PyLong_FromString,3.2,,
-+func,PyLong_FromUnsignedLong,3.2,,
-+func,PyLong_FromUnsignedLongLong,3.2,,
-+func,PyLong_FromVoidPtr,3.2,,
-+func,PyLong_GetInfo,3.2,,
-+data,PyLong_Type,3.2,,
-+data,PyMap_Type,3.2,,
-+func,PyMapping_Check,3.2,,
-+func,PyMapping_GetItemString,3.2,,
-+func,PyMapping_HasKey,3.2,,
-+func,PyMapping_HasKeyString,3.2,,
-+func,PyMapping_Items,3.2,,
-+func,PyMapping_Keys,3.2,,
-+func,PyMapping_Length,3.2,,
-+func,PyMapping_SetItemString,3.2,,
-+func,PyMapping_Size,3.2,,
-+func,PyMapping_Values,3.2,,
-+func,PyMem_Calloc,3.7,,
-+func,PyMem_Free,3.2,,
-+func,PyMem_Malloc,3.2,,
-+func,PyMem_Realloc,3.2,,
- type,PyMemberDef,3.2,,full-abi
--var,PyMemberDescr_Type,3.2,,
--function,PyMember_GetOne,3.2,,
--function,PyMember_SetOne,3.2,,
--function,PyMemoryView_FromBuffer,3.11,,
--function,PyMemoryView_FromMemory,3.7,,
--function,PyMemoryView_FromObject,3.2,,
--function,PyMemoryView_GetContiguous,3.2,,
--var,PyMemoryView_Type,3.2,,
-+data,PyMemberDescr_Type,3.2,,
-+func,PyMember_GetOne,3.2,,
-+func,PyMember_SetOne,3.2,,
-+func,PyMemoryView_FromBuffer,3.11,,
-+func,PyMemoryView_FromMemory,3.7,,
-+func,PyMemoryView_FromObject,3.2,,
-+func,PyMemoryView_GetContiguous,3.2,,
-+data,PyMemoryView_Type,3.2,,
- type,PyMethodDef,3.2,,full-abi
--var,PyMethodDescr_Type,3.2,,
-+data,PyMethodDescr_Type,3.2,,
- type,PyModuleDef,3.2,,full-abi
- type,PyModuleDef_Base,3.2,,full-abi
--function,PyModuleDef_Init,3.5,,
--var,PyModuleDef_Type,3.5,,
--function,PyModule_AddFunctions,3.7,,
--function,PyModule_AddIntConstant,3.2,,
--function,PyModule_AddObject,3.2,,
--function,PyModule_AddObjectRef,3.10,,
--function,PyModule_AddStringConstant,3.2,,
--function,PyModule_AddType,3.10,,
--function,PyModule_Create2,3.2,,
--function,PyModule_ExecDef,3.7,,
--function,PyModule_FromDefAndSpec2,3.7,,
--function,PyModule_GetDef,3.2,,
--function,PyModule_GetDict,3.2,,
--function,PyModule_GetFilename,3.2,,
--function,PyModule_GetFilenameObject,3.2,,
--function,PyModule_GetName,3.2,,
--function,PyModule_GetNameObject,3.7,,
--function,PyModule_GetState,3.2,,
--function,PyModule_New,3.2,,
--function,PyModule_NewObject,3.7,,
--function,PyModule_SetDocString,3.7,,
--var,PyModule_Type,3.2,,
--function,PyNumber_Absolute,3.2,,
--function,PyNumber_Add,3.2,,
--function,PyNumber_And,3.2,,
--function,PyNumber_AsSsize_t,3.2,,
--function,PyNumber_Check,3.2,,
--function,PyNumber_Divmod,3.2,,
--function,PyNumber_Float,3.2,,
--function,PyNumber_FloorDivide,3.2,,
--function,PyNumber_InPlaceAdd,3.2,,
--function,PyNumber_InPlaceAnd,3.2,,
--function,PyNumber_InPlaceFloorDivide,3.2,,
--function,PyNumber_InPlaceLshift,3.2,,
--function,PyNumber_InPlaceMatrixMultiply,3.7,,
--function,PyNumber_InPlaceMultiply,3.2,,
--function,PyNumber_InPlaceOr,3.2,,
--function,PyNumber_InPlacePower,3.2,,
--function,PyNumber_InPlaceRemainder,3.2,,
--function,PyNumber_InPlaceRshift,3.2,,
--function,PyNumber_InPlaceSubtract,3.2,,
--function,PyNumber_InPlaceTrueDivide,3.2,,
--function,PyNumber_InPlaceXor,3.2,,
--function,PyNumber_Index,3.2,,
--function,PyNumber_Invert,3.2,,
--function,PyNumber_Long,3.2,,
--function,PyNumber_Lshift,3.2,,
--function,PyNumber_MatrixMultiply,3.7,,
--function,PyNumber_Multiply,3.2,,
--function,PyNumber_Negative,3.2,,
--function,PyNumber_Or,3.2,,
--function,PyNumber_Positive,3.2,,
--function,PyNumber_Power,3.2,,
--function,PyNumber_Remainder,3.2,,
--function,PyNumber_Rshift,3.2,,
--function,PyNumber_Subtract,3.2,,
--function,PyNumber_ToBase,3.2,,
--function,PyNumber_TrueDivide,3.2,,
--function,PyNumber_Xor,3.2,,
--function,PyOS_AfterFork,3.2,on platforms with fork(),
--function,PyOS_AfterFork_Child,3.7,on platforms with fork(),
--function,PyOS_AfterFork_Parent,3.7,on platforms with fork(),
--function,PyOS_BeforeFork,3.7,on platforms with fork(),
--function,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK,
--function,PyOS_FSPath,3.6,,
--var,PyOS_InputHook,3.2,,
--function,PyOS_InterruptOccurred,3.2,,
--function,PyOS_double_to_string,3.2,,
--function,PyOS_getsig,3.2,,
--function,PyOS_mystricmp,3.2,,
--function,PyOS_mystrnicmp,3.2,,
--function,PyOS_setsig,3.2,,
-+func,PyModuleDef_Init,3.5,,
-+data,PyModuleDef_Type,3.5,,
-+func,PyModule_AddFunctions,3.7,,
-+func,PyModule_AddIntConstant,3.2,,
-+func,PyModule_AddObject,3.2,,
-+func,PyModule_AddObjectRef,3.10,,
-+func,PyModule_AddStringConstant,3.2,,
-+func,PyModule_AddType,3.10,,
-+func,PyModule_Create2,3.2,,
-+func,PyModule_ExecDef,3.7,,
-+func,PyModule_FromDefAndSpec2,3.7,,
-+func,PyModule_GetDef,3.2,,
-+func,PyModule_GetDict,3.2,,
-+func,PyModule_GetFilename,3.2,,
-+func,PyModule_GetFilenameObject,3.2,,
-+func,PyModule_GetName,3.2,,
-+func,PyModule_GetNameObject,3.7,,
-+func,PyModule_GetState,3.2,,
-+func,PyModule_New,3.2,,
-+func,PyModule_NewObject,3.7,,
-+func,PyModule_SetDocString,3.7,,
-+data,PyModule_Type,3.2,,
-+func,PyNumber_Absolute,3.2,,
-+func,PyNumber_Add,3.2,,
-+func,PyNumber_And,3.2,,
-+func,PyNumber_AsSsize_t,3.2,,
-+func,PyNumber_Check,3.2,,
-+func,PyNumber_Divmod,3.2,,
-+func,PyNumber_Float,3.2,,
-+func,PyNumber_FloorDivide,3.2,,
-+func,PyNumber_InPlaceAdd,3.2,,
-+func,PyNumber_InPlaceAnd,3.2,,
-+func,PyNumber_InPlaceFloorDivide,3.2,,
-+func,PyNumber_InPlaceLshift,3.2,,
-+func,PyNumber_InPlaceMatrixMultiply,3.7,,
-+func,PyNumber_InPlaceMultiply,3.2,,
-+func,PyNumber_InPlaceOr,3.2,,
-+func,PyNumber_InPlacePower,3.2,,
-+func,PyNumber_InPlaceRemainder,3.2,,
-+func,PyNumber_InPlaceRshift,3.2,,
-+func,PyNumber_InPlaceSubtract,3.2,,
-+func,PyNumber_InPlaceTrueDivide,3.2,,
-+func,PyNumber_InPlaceXor,3.2,,
-+func,PyNumber_Index,3.2,,
-+func,PyNumber_Invert,3.2,,
-+func,PyNumber_Long,3.2,,
-+func,PyNumber_Lshift,3.2,,
-+func,PyNumber_MatrixMultiply,3.7,,
-+func,PyNumber_Multiply,3.2,,
-+func,PyNumber_Negative,3.2,,
-+func,PyNumber_Or,3.2,,
-+func,PyNumber_Positive,3.2,,
-+func,PyNumber_Power,3.2,,
-+func,PyNumber_Remainder,3.2,,
-+func,PyNumber_Rshift,3.2,,
-+func,PyNumber_Subtract,3.2,,
-+func,PyNumber_ToBase,3.2,,
-+func,PyNumber_TrueDivide,3.2,,
-+func,PyNumber_Xor,3.2,,
-+func,PyOS_AfterFork,3.2,on platforms with fork(),
-+func,PyOS_AfterFork_Child,3.7,on platforms with fork(),
-+func,PyOS_AfterFork_Parent,3.7,on platforms with fork(),
-+func,PyOS_BeforeFork,3.7,on platforms with fork(),
-+func,PyOS_CheckStack,3.7,on platforms with USE_STACKCHECK,
-+func,PyOS_FSPath,3.6,,
-+data,PyOS_InputHook,3.2,,
-+func,PyOS_InterruptOccurred,3.2,,
-+func,PyOS_double_to_string,3.2,,
-+func,PyOS_getsig,3.2,,
-+func,PyOS_mystricmp,3.2,,
-+func,PyOS_mystrnicmp,3.2,,
-+func,PyOS_setsig,3.2,,
- type,PyOS_sighandler_t,3.2,,
--function,PyOS_snprintf,3.2,,
--function,PyOS_string_to_double,3.2,,
--function,PyOS_strtol,3.2,,
--function,PyOS_strtoul,3.2,,
--function,PyOS_vsnprintf,3.2,,
-+func,PyOS_snprintf,3.2,,
-+func,PyOS_string_to_double,3.2,,
-+func,PyOS_strtol,3.2,,
-+func,PyOS_strtoul,3.2,,
-+func,PyOS_vsnprintf,3.2,,
- type,PyObject,3.2,,members
- member,PyObject.ob_refcnt,3.2,,
- member,PyObject.ob_type,3.2,,
--function,PyObject_ASCII,3.2,,
--function,PyObject_AsCharBuffer,3.2,,
--function,PyObject_AsFileDescriptor,3.2,,
--function,PyObject_AsReadBuffer,3.2,,
--function,PyObject_AsWriteBuffer,3.2,,
--function,PyObject_Bytes,3.2,,
--function,PyObject_Call,3.2,,
--function,PyObject_CallFunction,3.2,,
--function,PyObject_CallFunctionObjArgs,3.2,,
--function,PyObject_CallMethod,3.2,,
--function,PyObject_CallMethodObjArgs,3.2,,
--function,PyObject_CallNoArgs,3.10,,
--function,PyObject_CallObject,3.2,,
--function,PyObject_Calloc,3.7,,
--function,PyObject_CheckBuffer,3.11,,
--function,PyObject_CheckReadBuffer,3.2,,
--function,PyObject_ClearWeakRefs,3.2,,
--function,PyObject_CopyData,3.11,,
--function,PyObject_DelItem,3.2,,
--function,PyObject_DelItemString,3.2,,
--function,PyObject_Dir,3.2,,
--function,PyObject_Format,3.2,,
--function,PyObject_Free,3.2,,
--function,PyObject_GC_Del,3.2,,
--function,PyObject_GC_IsFinalized,3.9,,
--function,PyObject_GC_IsTracked,3.9,,
--function,PyObject_GC_Track,3.2,,
--function,PyObject_GC_UnTrack,3.2,,
--function,PyObject_GenericGetAttr,3.2,,
--function,PyObject_GenericGetDict,3.10,,
--function,PyObject_GenericSetAttr,3.2,,
--function,PyObject_GenericSetDict,3.7,,
--function,PyObject_GetAIter,3.10,,
--function,PyObject_GetAttr,3.2,,
--function,PyObject_GetAttrString,3.2,,
--function,PyObject_GetBuffer,3.11,,
--function,PyObject_GetItem,3.2,,
--function,PyObject_GetIter,3.2,,
--function,PyObject_GetTypeData,3.12,,
--function,PyObject_HasAttr,3.2,,
--function,PyObject_HasAttrString,3.2,,
--function,PyObject_Hash,3.2,,
--function,PyObject_HashNotImplemented,3.2,,
--function,PyObject_Init,3.2,,
--function,PyObject_InitVar,3.2,,
--function,PyObject_IsInstance,3.2,,
--function,PyObject_IsSubclass,3.2,,
--function,PyObject_IsTrue,3.2,,
--function,PyObject_Length,3.2,,
--function,PyObject_Malloc,3.2,,
--function,PyObject_Not,3.2,,
--function,PyObject_Realloc,3.2,,
--function,PyObject_Repr,3.2,,
--function,PyObject_RichCompare,3.2,,
--function,PyObject_RichCompareBool,3.2,,
--function,PyObject_SelfIter,3.2,,
--function,PyObject_SetAttr,3.2,,
--function,PyObject_SetAttrString,3.2,,
--function,PyObject_SetItem,3.2,,
--function,PyObject_Size,3.2,,
--function,PyObject_Str,3.2,,
--function,PyObject_Type,3.2,,
--function,PyObject_Vectorcall,3.12,,
--function,PyObject_VectorcallMethod,3.12,,
--var,PyProperty_Type,3.2,,
--var,PyRangeIter_Type,3.2,,
--var,PyRange_Type,3.2,,
--var,PyReversed_Type,3.2,,
--function,PySeqIter_New,3.2,,
--var,PySeqIter_Type,3.2,,
--function,PySequence_Check,3.2,,
--function,PySequence_Concat,3.2,,
--function,PySequence_Contains,3.2,,
--function,PySequence_Count,3.2,,
--function,PySequence_DelItem,3.2,,
--function,PySequence_DelSlice,3.2,,
--function,PySequence_Fast,3.2,,
--function,PySequence_GetItem,3.2,,
--function,PySequence_GetSlice,3.2,,
--function,PySequence_In,3.2,,
--function,PySequence_InPlaceConcat,3.2,,
--function,PySequence_InPlaceRepeat,3.2,,
--function,PySequence_Index,3.2,,
--function,PySequence_Length,3.2,,
--function,PySequence_List,3.2,,
--function,PySequence_Repeat,3.2,,
--function,PySequence_SetItem,3.2,,
--function,PySequence_SetSlice,3.2,,
--function,PySequence_Size,3.2,,
--function,PySequence_Tuple,3.2,,
--var,PySetIter_Type,3.2,,
--function,PySet_Add,3.2,,
--function,PySet_Clear,3.2,,
--function,PySet_Contains,3.2,,
--function,PySet_Discard,3.2,,
--function,PySet_New,3.2,,
--function,PySet_Pop,3.2,,
--function,PySet_Size,3.2,,
--var,PySet_Type,3.2,,
--function,PySlice_AdjustIndices,3.7,,
--function,PySlice_GetIndices,3.2,,
--function,PySlice_GetIndicesEx,3.2,,
--function,PySlice_New,3.2,,
--var,PySlice_Type,3.2,,
--function,PySlice_Unpack,3.7,,
--function,PyState_AddModule,3.3,,
--function,PyState_FindModule,3.2,,
--function,PyState_RemoveModule,3.3,,
-+func,PyObject_ASCII,3.2,,
-+func,PyObject_AsCharBuffer,3.2,,
-+func,PyObject_AsFileDescriptor,3.2,,
-+func,PyObject_AsReadBuffer,3.2,,
-+func,PyObject_AsWriteBuffer,3.2,,
-+func,PyObject_Bytes,3.2,,
-+func,PyObject_Call,3.2,,
-+func,PyObject_CallFunction,3.2,,
-+func,PyObject_CallFunctionObjArgs,3.2,,
-+func,PyObject_CallMethod,3.2,,
-+func,PyObject_CallMethodObjArgs,3.2,,
-+func,PyObject_CallNoArgs,3.10,,
-+func,PyObject_CallObject,3.2,,
-+func,PyObject_Calloc,3.7,,
-+func,PyObject_CheckBuffer,3.11,,
-+func,PyObject_CheckReadBuffer,3.2,,
-+func,PyObject_ClearWeakRefs,3.2,,
-+func,PyObject_CopyData,3.11,,
-+func,PyObject_DelItem,3.2,,
-+func,PyObject_DelItemString,3.2,,
-+func,PyObject_Dir,3.2,,
-+func,PyObject_Format,3.2,,
-+func,PyObject_Free,3.2,,
-+func,PyObject_GC_Del,3.2,,
-+func,PyObject_GC_IsFinalized,3.9,,
-+func,PyObject_GC_IsTracked,3.9,,
-+func,PyObject_GC_Track,3.2,,
-+func,PyObject_GC_UnTrack,3.2,,
-+func,PyObject_GenericGetAttr,3.2,,
-+func,PyObject_GenericGetDict,3.10,,
-+func,PyObject_GenericSetAttr,3.2,,
-+func,PyObject_GenericSetDict,3.7,,
-+func,PyObject_GetAIter,3.10,,
-+func,PyObject_GetAttr,3.2,,
-+func,PyObject_GetAttrString,3.2,,
-+func,PyObject_GetBuffer,3.11,,
-+func,PyObject_GetItem,3.2,,
-+func,PyObject_GetIter,3.2,,
-+func,PyObject_GetTypeData,3.12,,
-+func,PyObject_HasAttr,3.2,,
-+func,PyObject_HasAttrString,3.2,,
-+func,PyObject_Hash,3.2,,
-+func,PyObject_HashNotImplemented,3.2,,
-+func,PyObject_Init,3.2,,
-+func,PyObject_InitVar,3.2,,
-+func,PyObject_IsInstance,3.2,,
-+func,PyObject_IsSubclass,3.2,,
-+func,PyObject_IsTrue,3.2,,
-+func,PyObject_Length,3.2,,
-+func,PyObject_Malloc,3.2,,
-+func,PyObject_Not,3.2,,
-+func,PyObject_Realloc,3.2,,
-+func,PyObject_Repr,3.2,,
-+func,PyObject_RichCompare,3.2,,
-+func,PyObject_RichCompareBool,3.2,,
-+func,PyObject_SelfIter,3.2,,
-+func,PyObject_SetAttr,3.2,,
-+func,PyObject_SetAttrString,3.2,,
-+func,PyObject_SetItem,3.2,,
-+func,PyObject_Size,3.2,,
-+func,PyObject_Str,3.2,,
-+func,PyObject_Type,3.2,,
-+func,PyObject_Vectorcall,3.12,,
-+func,PyObject_VectorcallMethod,3.12,,
-+data,PyProperty_Type,3.2,,
-+data,PyRangeIter_Type,3.2,,
-+data,PyRange_Type,3.2,,
-+data,PyReversed_Type,3.2,,
-+func,PySeqIter_New,3.2,,
-+data,PySeqIter_Type,3.2,,
-+func,PySequence_Check,3.2,,
-+func,PySequence_Concat,3.2,,
-+func,PySequence_Contains,3.2,,
-+func,PySequence_Count,3.2,,
-+func,PySequence_DelItem,3.2,,
-+func,PySequence_DelSlice,3.2,,
-+func,PySequence_Fast,3.2,,
-+func,PySequence_GetItem,3.2,,
-+func,PySequence_GetSlice,3.2,,
-+func,PySequence_In,3.2,,
-+func,PySequence_InPlaceConcat,3.2,,
-+func,PySequence_InPlaceRepeat,3.2,,
-+func,PySequence_Index,3.2,,
-+func,PySequence_Length,3.2,,
-+func,PySequence_List,3.2,,
-+func,PySequence_Repeat,3.2,,
-+func,PySequence_SetItem,3.2,,
-+func,PySequence_SetSlice,3.2,,
-+func,PySequence_Size,3.2,,
-+func,PySequence_Tuple,3.2,,
-+data,PySetIter_Type,3.2,,
-+func,PySet_Add,3.2,,
-+func,PySet_Clear,3.2,,
-+func,PySet_Contains,3.2,,
-+func,PySet_Discard,3.2,,
-+func,PySet_New,3.2,,
-+func,PySet_Pop,3.2,,
-+func,PySet_Size,3.2,,
-+data,PySet_Type,3.2,,
-+func,PySlice_AdjustIndices,3.7,,
-+func,PySlice_GetIndices,3.2,,
-+func,PySlice_GetIndicesEx,3.2,,
-+func,PySlice_New,3.2,,
-+data,PySlice_Type,3.2,,
-+func,PySlice_Unpack,3.7,,
-+func,PyState_AddModule,3.3,,
-+func,PyState_FindModule,3.2,,
-+func,PyState_RemoveModule,3.3,,
- type,PyStructSequence_Desc,3.2,,full-abi
- type,PyStructSequence_Field,3.2,,full-abi
--function,PyStructSequence_GetItem,3.2,,
--function,PyStructSequence_New,3.2,,
--function,PyStructSequence_NewType,3.2,,
--function,PyStructSequence_SetItem,3.2,,
--var,PyStructSequence_UnnamedField,3.11,,
--var,PySuper_Type,3.2,,
--function,PySys_AddWarnOption,3.2,,
--function,PySys_AddWarnOptionUnicode,3.2,,
--function,PySys_AddXOption,3.7,,
--function,PySys_FormatStderr,3.2,,
--function,PySys_FormatStdout,3.2,,
--function,PySys_GetObject,3.2,,
--function,PySys_GetXOptions,3.7,,
--function,PySys_HasWarnOptions,3.2,,
--function,PySys_ResetWarnOptions,3.2,,
--function,PySys_SetArgv,3.2,,
--function,PySys_SetArgvEx,3.2,,
--function,PySys_SetObject,3.2,,
--function,PySys_SetPath,3.2,,
--function,PySys_WriteStderr,3.2,,
--function,PySys_WriteStdout,3.2,,
-+func,PyStructSequence_GetItem,3.2,,
-+func,PyStructSequence_New,3.2,,
-+func,PyStructSequence_NewType,3.2,,
-+func,PyStructSequence_SetItem,3.2,,
-+data,PyStructSequence_UnnamedField,3.11,,
-+data,PySuper_Type,3.2,,
-+func,PySys_AddWarnOption,3.2,,
-+func,PySys_AddWarnOptionUnicode,3.2,,
-+func,PySys_AddXOption,3.7,,
-+func,PySys_FormatStderr,3.2,,
-+func,PySys_FormatStdout,3.2,,
-+func,PySys_GetObject,3.2,,
-+func,PySys_GetXOptions,3.7,,
-+func,PySys_HasWarnOptions,3.2,,
-+func,PySys_ResetWarnOptions,3.2,,
-+func,PySys_SetArgv,3.2,,
-+func,PySys_SetArgvEx,3.2,,
-+func,PySys_SetObject,3.2,,
-+func,PySys_SetPath,3.2,,
-+func,PySys_WriteStderr,3.2,,
-+func,PySys_WriteStdout,3.2,,
- type,PyThreadState,3.2,,opaque
--function,PyThreadState_Clear,3.2,,
--function,PyThreadState_Delete,3.2,,
--function,PyThreadState_Get,3.2,,
--function,PyThreadState_GetDict,3.2,,
--function,PyThreadState_GetFrame,3.10,,
--function,PyThreadState_GetID,3.10,,
--function,PyThreadState_GetInterpreter,3.10,,
--function,PyThreadState_New,3.2,,
--function,PyThreadState_SetAsyncExc,3.2,,
--function,PyThreadState_Swap,3.2,,
--function,PyThread_GetInfo,3.3,,
--function,PyThread_ReInitTLS,3.2,,
--function,PyThread_acquire_lock,3.2,,
--function,PyThread_acquire_lock_timed,3.2,,
--function,PyThread_allocate_lock,3.2,,
--function,PyThread_create_key,3.2,,
--function,PyThread_delete_key,3.2,,
--function,PyThread_delete_key_value,3.2,,
--function,PyThread_exit_thread,3.2,,
--function,PyThread_free_lock,3.2,,
--function,PyThread_get_key_value,3.2,,
--function,PyThread_get_stacksize,3.2,,
--function,PyThread_get_thread_ident,3.2,,
--function,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs,
--function,PyThread_init_thread,3.2,,
--function,PyThread_release_lock,3.2,,
--function,PyThread_set_key_value,3.2,,
--function,PyThread_set_stacksize,3.2,,
--function,PyThread_start_new_thread,3.2,,
--function,PyThread_tss_alloc,3.7,,
--function,PyThread_tss_create,3.7,,
--function,PyThread_tss_delete,3.7,,
--function,PyThread_tss_free,3.7,,
--function,PyThread_tss_get,3.7,,
--function,PyThread_tss_is_created,3.7,,
--function,PyThread_tss_set,3.7,,
--function,PyTraceBack_Here,3.2,,
--function,PyTraceBack_Print,3.2,,
--var,PyTraceBack_Type,3.2,,
--var,PyTupleIter_Type,3.2,,
--function,PyTuple_GetItem,3.2,,
--function,PyTuple_GetSlice,3.2,,
--function,PyTuple_New,3.2,,
--function,PyTuple_Pack,3.2,,
--function,PyTuple_SetItem,3.2,,
--function,PyTuple_Size,3.2,,
--var,PyTuple_Type,3.2,,
-+func,PyThreadState_Clear,3.2,,
-+func,PyThreadState_Delete,3.2,,
-+func,PyThreadState_Get,3.2,,
-+func,PyThreadState_GetDict,3.2,,
-+func,PyThreadState_GetFrame,3.10,,
-+func,PyThreadState_GetID,3.10,,
-+func,PyThreadState_GetInterpreter,3.10,,
-+func,PyThreadState_New,3.2,,
-+func,PyThreadState_SetAsyncExc,3.2,,
-+func,PyThreadState_Swap,3.2,,
-+func,PyThread_GetInfo,3.3,,
-+func,PyThread_ReInitTLS,3.2,,
-+func,PyThread_acquire_lock,3.2,,
-+func,PyThread_acquire_lock_timed,3.2,,
-+func,PyThread_allocate_lock,3.2,,
-+func,PyThread_create_key,3.2,,
-+func,PyThread_delete_key,3.2,,
-+func,PyThread_delete_key_value,3.2,,
-+func,PyThread_exit_thread,3.2,,
-+func,PyThread_free_lock,3.2,,
-+func,PyThread_get_key_value,3.2,,
-+func,PyThread_get_stacksize,3.2,,
-+func,PyThread_get_thread_ident,3.2,,
-+func,PyThread_get_thread_native_id,3.2,on platforms with native thread IDs,
-+func,PyThread_init_thread,3.2,,
-+func,PyThread_release_lock,3.2,,
-+func,PyThread_set_key_value,3.2,,
-+func,PyThread_set_stacksize,3.2,,
-+func,PyThread_start_new_thread,3.2,,
-+func,PyThread_tss_alloc,3.7,,
-+func,PyThread_tss_create,3.7,,
-+func,PyThread_tss_delete,3.7,,
-+func,PyThread_tss_free,3.7,,
-+func,PyThread_tss_get,3.7,,
-+func,PyThread_tss_is_created,3.7,,
-+func,PyThread_tss_set,3.7,,
-+func,PyTraceBack_Here,3.2,,
-+func,PyTraceBack_Print,3.2,,
-+data,PyTraceBack_Type,3.2,,
-+data,PyTupleIter_Type,3.2,,
-+func,PyTuple_GetItem,3.2,,
-+func,PyTuple_GetSlice,3.2,,
-+func,PyTuple_New,3.2,,
-+func,PyTuple_Pack,3.2,,
-+func,PyTuple_SetItem,3.2,,
-+func,PyTuple_Size,3.2,,
-+data,PyTuple_Type,3.2,,
- type,PyTypeObject,3.2,,opaque
--function,PyType_ClearCache,3.2,,
--function,PyType_FromMetaclass,3.12,,
--function,PyType_FromModuleAndSpec,3.10,,
--function,PyType_FromSpec,3.2,,
--function,PyType_FromSpecWithBases,3.3,,
--function,PyType_GenericAlloc,3.2,,
--function,PyType_GenericNew,3.2,,
--function,PyType_GetFlags,3.2,,
--function,PyType_GetModule,3.10,,
--function,PyType_GetModuleState,3.10,,
--function,PyType_GetName,3.11,,
--function,PyType_GetQualName,3.11,,
--function,PyType_GetSlot,3.4,,
--function,PyType_GetTypeDataSize,3.12,,
--function,PyType_IsSubtype,3.2,,
--function,PyType_Modified,3.2,,
--function,PyType_Ready,3.2,,
-+func,PyType_ClearCache,3.2,,
-+func,PyType_FromMetaclass,3.12,,
-+func,PyType_FromModuleAndSpec,3.10,,
-+func,PyType_FromSpec,3.2,,
-+func,PyType_FromSpecWithBases,3.3,,
-+func,PyType_GenericAlloc,3.2,,
-+func,PyType_GenericNew,3.2,,
-+func,PyType_GetFlags,3.2,,
-+func,PyType_GetModule,3.10,,
-+func,PyType_GetModuleState,3.10,,
-+func,PyType_GetName,3.11,,
-+func,PyType_GetQualName,3.11,,
-+func,PyType_GetSlot,3.4,,
-+func,PyType_GetTypeDataSize,3.12,,
-+func,PyType_IsSubtype,3.2,,
-+func,PyType_Modified,3.2,,
-+func,PyType_Ready,3.2,,
- type,PyType_Slot,3.2,,full-abi
- type,PyType_Spec,3.2,,full-abi
--var,PyType_Type,3.2,,
--function,PyUnicodeDecodeError_Create,3.2,,
--function,PyUnicodeDecodeError_GetEncoding,3.2,,
--function,PyUnicodeDecodeError_GetEnd,3.2,,
--function,PyUnicodeDecodeError_GetObject,3.2,,
--function,PyUnicodeDecodeError_GetReason,3.2,,
--function,PyUnicodeDecodeError_GetStart,3.2,,
--function,PyUnicodeDecodeError_SetEnd,3.2,,
--function,PyUnicodeDecodeError_SetReason,3.2,,
--function,PyUnicodeDecodeError_SetStart,3.2,,
--function,PyUnicodeEncodeError_GetEncoding,3.2,,
--function,PyUnicodeEncodeError_GetEnd,3.2,,
--function,PyUnicodeEncodeError_GetObject,3.2,,
--function,PyUnicodeEncodeError_GetReason,3.2,,
--function,PyUnicodeEncodeError_GetStart,3.2,,
--function,PyUnicodeEncodeError_SetEnd,3.2,,
--function,PyUnicodeEncodeError_SetReason,3.2,,
--function,PyUnicodeEncodeError_SetStart,3.2,,
--var,PyUnicodeIter_Type,3.2,,
--function,PyUnicodeTranslateError_GetEnd,3.2,,
--function,PyUnicodeTranslateError_GetObject,3.2,,
--function,PyUnicodeTranslateError_GetReason,3.2,,
--function,PyUnicodeTranslateError_GetStart,3.2,,
--function,PyUnicodeTranslateError_SetEnd,3.2,,
--function,PyUnicodeTranslateError_SetReason,3.2,,
--function,PyUnicodeTranslateError_SetStart,3.2,,
--function,PyUnicode_Append,3.2,,
--function,PyUnicode_AppendAndDel,3.2,,
--function,PyUnicode_AsASCIIString,3.2,,
--function,PyUnicode_AsCharmapString,3.2,,
--function,PyUnicode_AsDecodedObject,3.2,,
--function,PyUnicode_AsDecodedUnicode,3.2,,
--function,PyUnicode_AsEncodedObject,3.2,,
--function,PyUnicode_AsEncodedString,3.2,,
--function,PyUnicode_AsEncodedUnicode,3.2,,
--function,PyUnicode_AsLatin1String,3.2,,
--function,PyUnicode_AsMBCSString,3.7,on Windows,
--function,PyUnicode_AsRawUnicodeEscapeString,3.2,,
--function,PyUnicode_AsUCS4,3.7,,
--function,PyUnicode_AsUCS4Copy,3.7,,
--function,PyUnicode_AsUTF16String,3.2,,
--function,PyUnicode_AsUTF32String,3.2,,
--function,PyUnicode_AsUTF8AndSize,3.10,,
--function,PyUnicode_AsUTF8String,3.2,,
--function,PyUnicode_AsUnicodeEscapeString,3.2,,
--function,PyUnicode_AsWideChar,3.2,,
--function,PyUnicode_AsWideCharString,3.7,,
--function,PyUnicode_BuildEncodingMap,3.2,,
--function,PyUnicode_Compare,3.2,,
--function,PyUnicode_CompareWithASCIIString,3.2,,
--function,PyUnicode_Concat,3.2,,
--function,PyUnicode_Contains,3.2,,
--function,PyUnicode_Count,3.2,,
--function,PyUnicode_Decode,3.2,,
--function,PyUnicode_DecodeASCII,3.2,,
--function,PyUnicode_DecodeCharmap,3.2,,
--function,PyUnicode_DecodeCodePageStateful,3.7,on Windows,
--function,PyUnicode_DecodeFSDefault,3.2,,
--function,PyUnicode_DecodeFSDefaultAndSize,3.2,,
--function,PyUnicode_DecodeLatin1,3.2,,
--function,PyUnicode_DecodeLocale,3.7,,
--function,PyUnicode_DecodeLocaleAndSize,3.7,,
--function,PyUnicode_DecodeMBCS,3.7,on Windows,
--function,PyUnicode_DecodeMBCSStateful,3.7,on Windows,
--function,PyUnicode_DecodeRawUnicodeEscape,3.2,,
--function,PyUnicode_DecodeUTF16,3.2,,
--function,PyUnicode_DecodeUTF16Stateful,3.2,,
--function,PyUnicode_DecodeUTF32,3.2,,
--function,PyUnicode_DecodeUTF32Stateful,3.2,,
--function,PyUnicode_DecodeUTF7,3.2,,
--function,PyUnicode_DecodeUTF7Stateful,3.2,,
--function,PyUnicode_DecodeUTF8,3.2,,
--function,PyUnicode_DecodeUTF8Stateful,3.2,,
--function,PyUnicode_DecodeUnicodeEscape,3.2,,
--function,PyUnicode_EncodeCodePage,3.7,on Windows,
--function,PyUnicode_EncodeFSDefault,3.2,,
--function,PyUnicode_EncodeLocale,3.7,,
--function,PyUnicode_FSConverter,3.2,,
--function,PyUnicode_FSDecoder,3.2,,
--function,PyUnicode_Find,3.2,,
--function,PyUnicode_FindChar,3.7,,
--function,PyUnicode_Format,3.2,,
--function,PyUnicode_FromEncodedObject,3.2,,
--function,PyUnicode_FromFormat,3.2,,
--function,PyUnicode_FromFormatV,3.2,,
--function,PyUnicode_FromObject,3.2,,
--function,PyUnicode_FromOrdinal,3.2,,
--function,PyUnicode_FromString,3.2,,
--function,PyUnicode_FromStringAndSize,3.2,,
--function,PyUnicode_FromWideChar,3.2,,
--function,PyUnicode_GetDefaultEncoding,3.2,,
--function,PyUnicode_GetLength,3.7,,
--function,PyUnicode_InternFromString,3.2,,
--function,PyUnicode_InternInPlace,3.2,,
--function,PyUnicode_IsIdentifier,3.2,,
--function,PyUnicode_Join,3.2,,
--function,PyUnicode_Partition,3.2,,
--function,PyUnicode_RPartition,3.2,,
--function,PyUnicode_RSplit,3.2,,
--function,PyUnicode_ReadChar,3.7,,
--function,PyUnicode_Replace,3.2,,
--function,PyUnicode_Resize,3.2,,
--function,PyUnicode_RichCompare,3.2,,
--function,PyUnicode_Split,3.2,,
--function,PyUnicode_Splitlines,3.2,,
--function,PyUnicode_Substring,3.7,,
--function,PyUnicode_Tailmatch,3.2,,
--function,PyUnicode_Translate,3.2,,
--var,PyUnicode_Type,3.2,,
--function,PyUnicode_WriteChar,3.7,,
-+data,PyType_Type,3.2,,
-+func,PyUnicodeDecodeError_Create,3.2,,
-+func,PyUnicodeDecodeError_GetEncoding,3.2,,
-+func,PyUnicodeDecodeError_GetEnd,3.2,,
-+func,PyUnicodeDecodeError_GetObject,3.2,,
-+func,PyUnicodeDecodeError_GetReason,3.2,,
-+func,PyUnicodeDecodeError_GetStart,3.2,,
-+func,PyUnicodeDecodeError_SetEnd,3.2,,
-+func,PyUnicodeDecodeError_SetReason,3.2,,
-+func,PyUnicodeDecodeError_SetStart,3.2,,
-+func,PyUnicodeEncodeError_GetEncoding,3.2,,
-+func,PyUnicodeEncodeError_GetEnd,3.2,,
-+func,PyUnicodeEncodeError_GetObject,3.2,,
-+func,PyUnicodeEncodeError_GetReason,3.2,,
-+func,PyUnicodeEncodeError_GetStart,3.2,,
-+func,PyUnicodeEncodeError_SetEnd,3.2,,
-+func,PyUnicodeEncodeError_SetReason,3.2,,
-+func,PyUnicodeEncodeError_SetStart,3.2,,
-+data,PyUnicodeIter_Type,3.2,,
-+func,PyUnicodeTranslateError_GetEnd,3.2,,
-+func,PyUnicodeTranslateError_GetObject,3.2,,
-+func,PyUnicodeTranslateError_GetReason,3.2,,
-+func,PyUnicodeTranslateError_GetStart,3.2,,
-+func,PyUnicodeTranslateError_SetEnd,3.2,,
-+func,PyUnicodeTranslateError_SetReason,3.2,,
-+func,PyUnicodeTranslateError_SetStart,3.2,,
-+func,PyUnicode_Append,3.2,,
-+func,PyUnicode_AppendAndDel,3.2,,
-+func,PyUnicode_AsASCIIString,3.2,,
-+func,PyUnicode_AsCharmapString,3.2,,
-+func,PyUnicode_AsDecodedObject,3.2,,
-+func,PyUnicode_AsDecodedUnicode,3.2,,
-+func,PyUnicode_AsEncodedObject,3.2,,
-+func,PyUnicode_AsEncodedString,3.2,,
-+func,PyUnicode_AsEncodedUnicode,3.2,,
-+func,PyUnicode_AsLatin1String,3.2,,
-+func,PyUnicode_AsMBCSString,3.7,on Windows,
-+func,PyUnicode_AsRawUnicodeEscapeString,3.2,,
-+func,PyUnicode_AsUCS4,3.7,,
-+func,PyUnicode_AsUCS4Copy,3.7,,
-+func,PyUnicode_AsUTF16String,3.2,,
-+func,PyUnicode_AsUTF32String,3.2,,
-+func,PyUnicode_AsUTF8AndSize,3.10,,
-+func,PyUnicode_AsUTF8String,3.2,,
-+func,PyUnicode_AsUnicodeEscapeString,3.2,,
-+func,PyUnicode_AsWideChar,3.2,,
-+func,PyUnicode_AsWideCharString,3.7,,
-+func,PyUnicode_BuildEncodingMap,3.2,,
-+func,PyUnicode_Compare,3.2,,
-+func,PyUnicode_CompareWithASCIIString,3.2,,
-+func,PyUnicode_Concat,3.2,,
-+func,PyUnicode_Contains,3.2,,
-+func,PyUnicode_Count,3.2,,
-+func,PyUnicode_Decode,3.2,,
-+func,PyUnicode_DecodeASCII,3.2,,
-+func,PyUnicode_DecodeCharmap,3.2,,
-+func,PyUnicode_DecodeCodePageStateful,3.7,on Windows,
-+func,PyUnicode_DecodeFSDefault,3.2,,
-+func,PyUnicode_DecodeFSDefaultAndSize,3.2,,
-+func,PyUnicode_DecodeLatin1,3.2,,
-+func,PyUnicode_DecodeLocale,3.7,,
-+func,PyUnicode_DecodeLocaleAndSize,3.7,,
-+func,PyUnicode_DecodeMBCS,3.7,on Windows,
-+func,PyUnicode_DecodeMBCSStateful,3.7,on Windows,
-+func,PyUnicode_DecodeRawUnicodeEscape,3.2,,
-+func,PyUnicode_DecodeUTF16,3.2,,
-+func,PyUnicode_DecodeUTF16Stateful,3.2,,
-+func,PyUnicode_DecodeUTF32,3.2,,
-+func,PyUnicode_DecodeUTF32Stateful,3.2,,
-+func,PyUnicode_DecodeUTF7,3.2,,
-+func,PyUnicode_DecodeUTF7Stateful,3.2,,
-+func,PyUnicode_DecodeUTF8,3.2,,
-+func,PyUnicode_DecodeUTF8Stateful,3.2,,
-+func,PyUnicode_DecodeUnicodeEscape,3.2,,
-+func,PyUnicode_EncodeCodePage,3.7,on Windows,
-+func,PyUnicode_EncodeFSDefault,3.2,,
-+func,PyUnicode_EncodeLocale,3.7,,
-+func,PyUnicode_FSConverter,3.2,,
-+func,PyUnicode_FSDecoder,3.2,,
-+func,PyUnicode_Find,3.2,,
-+func,PyUnicode_FindChar,3.7,,
-+func,PyUnicode_Format,3.2,,
-+func,PyUnicode_FromEncodedObject,3.2,,
-+func,PyUnicode_FromFormat,3.2,,
-+func,PyUnicode_FromFormatV,3.2,,
-+func,PyUnicode_FromObject,3.2,,
-+func,PyUnicode_FromOrdinal,3.2,,
-+func,PyUnicode_FromString,3.2,,
-+func,PyUnicode_FromStringAndSize,3.2,,
-+func,PyUnicode_FromWideChar,3.2,,
-+func,PyUnicode_GetDefaultEncoding,3.2,,
-+func,PyUnicode_GetLength,3.7,,
-+func,PyUnicode_InternFromString,3.2,,
-+func,PyUnicode_InternInPlace,3.2,,
-+func,PyUnicode_IsIdentifier,3.2,,
-+func,PyUnicode_Join,3.2,,
-+func,PyUnicode_Partition,3.2,,
-+func,PyUnicode_RPartition,3.2,,
-+func,PyUnicode_RSplit,3.2,,
-+func,PyUnicode_ReadChar,3.7,,
-+func,PyUnicode_Replace,3.2,,
-+func,PyUnicode_Resize,3.2,,
-+func,PyUnicode_RichCompare,3.2,,
-+func,PyUnicode_Split,3.2,,
-+func,PyUnicode_Splitlines,3.2,,
-+func,PyUnicode_Substring,3.7,,
-+func,PyUnicode_Tailmatch,3.2,,
-+func,PyUnicode_Translate,3.2,,
-+data,PyUnicode_Type,3.2,,
-+func,PyUnicode_WriteChar,3.7,,
- type,PyVarObject,3.2,,members
- member,PyVarObject.ob_base,3.2,,
- member,PyVarObject.ob_size,3.2,,
--function,PyVectorcall_Call,3.12,,
--function,PyVectorcall_NARGS,3.12,,
-+func,PyVectorcall_Call,3.12,,
-+func,PyVectorcall_NARGS,3.12,,
- type,PyWeakReference,3.2,,opaque
--function,PyWeakref_GetObject,3.2,,
--function,PyWeakref_NewProxy,3.2,,
--function,PyWeakref_NewRef,3.2,,
--var,PyWrapperDescr_Type,3.2,,
--function,PyWrapper_New,3.2,,
--var,PyZip_Type,3.2,,
--function,Py_AddPendingCall,3.2,,
--function,Py_AtExit,3.2,,
-+func,PyWeakref_GetObject,3.2,,
-+func,PyWeakref_NewProxy,3.2,,
-+func,PyWeakref_NewRef,3.2,,
-+data,PyWrapperDescr_Type,3.2,,
-+func,PyWrapper_New,3.2,,
-+data,PyZip_Type,3.2,,
-+func,Py_AddPendingCall,3.2,,
-+func,Py_AtExit,3.2,,
- macro,Py_BEGIN_ALLOW_THREADS,3.2,,
- macro,Py_BLOCK_THREADS,3.2,,
--function,Py_BuildValue,3.2,,
--function,Py_BytesMain,3.8,,
--function,Py_CompileString,3.2,,
--function,Py_DecRef,3.2,,
--function,Py_DecodeLocale,3.7,,
-+func,Py_BuildValue,3.2,,
-+func,Py_BytesMain,3.8,,
-+func,Py_CompileString,3.2,,
-+func,Py_DecRef,3.2,,
-+func,Py_DecodeLocale,3.7,,
- macro,Py_END_ALLOW_THREADS,3.2,,
--function,Py_EncodeLocale,3.7,,
--function,Py_EndInterpreter,3.2,,
--function,Py_EnterRecursiveCall,3.9,,
--function,Py_Exit,3.2,,
--function,Py_FatalError,3.2,,
--var,Py_FileSystemDefaultEncodeErrors,3.10,,
--var,Py_FileSystemDefaultEncoding,3.2,,
--function,Py_Finalize,3.2,,
--function,Py_FinalizeEx,3.6,,
--function,Py_GenericAlias,3.9,,
--var,Py_GenericAliasType,3.9,,
--function,Py_GetBuildInfo,3.2,,
--function,Py_GetCompiler,3.2,,
--function,Py_GetCopyright,3.2,,
--function,Py_GetExecPrefix,3.2,,
--function,Py_GetPath,3.2,,
--function,Py_GetPlatform,3.2,,
--function,Py_GetPrefix,3.2,,
--function,Py_GetProgramFullPath,3.2,,
--function,Py_GetProgramName,3.2,,
--function,Py_GetPythonHome,3.2,,
--function,Py_GetRecursionLimit,3.2,,
--function,Py_GetVersion,3.2,,
--var,Py_HasFileSystemDefaultEncoding,3.2,,
--function,Py_IncRef,3.2,,
--function,Py_Initialize,3.2,,
--function,Py_InitializeEx,3.2,,
--function,Py_Is,3.10,,
--function,Py_IsFalse,3.10,,
--function,Py_IsInitialized,3.2,,
--function,Py_IsNone,3.10,,
--function,Py_IsTrue,3.10,,
--function,Py_LeaveRecursiveCall,3.9,,
--function,Py_Main,3.2,,
--function,Py_MakePendingCalls,3.2,,
--function,Py_NewInterpreter,3.2,,
--function,Py_NewRef,3.10,,
--function,Py_ReprEnter,3.2,,
--function,Py_ReprLeave,3.2,,
--function,Py_SetPath,3.7,,
--function,Py_SetProgramName,3.2,,
--function,Py_SetPythonHome,3.2,,
--function,Py_SetRecursionLimit,3.2,,
-+func,Py_EncodeLocale,3.7,,
-+func,Py_EndInterpreter,3.2,,
-+func,Py_EnterRecursiveCall,3.9,,
-+func,Py_Exit,3.2,,
-+func,Py_FatalError,3.2,,
-+data,Py_FileSystemDefaultEncodeErrors,3.10,,
-+data,Py_FileSystemDefaultEncoding,3.2,,
-+func,Py_Finalize,3.2,,
-+func,Py_FinalizeEx,3.6,,
-+func,Py_GenericAlias,3.9,,
-+data,Py_GenericAliasType,3.9,,
-+func,Py_GetBuildInfo,3.2,,
-+func,Py_GetCompiler,3.2,,
-+func,Py_GetCopyright,3.2,,
-+func,Py_GetExecPrefix,3.2,,
-+func,Py_GetPath,3.2,,
-+func,Py_GetPlatform,3.2,,
-+func,Py_GetPrefix,3.2,,
-+func,Py_GetProgramFullPath,3.2,,
-+func,Py_GetProgramName,3.2,,
-+func,Py_GetPythonHome,3.2,,
-+func,Py_GetRecursionLimit,3.2,,
-+func,Py_GetVersion,3.2,,
-+data,Py_HasFileSystemDefaultEncoding,3.2,,
-+func,Py_IncRef,3.2,,
-+func,Py_Initialize,3.2,,
-+func,Py_InitializeEx,3.2,,
-+func,Py_Is,3.10,,
-+func,Py_IsFalse,3.10,,
-+func,Py_IsInitialized,3.2,,
-+func,Py_IsNone,3.10,,
-+func,Py_IsTrue,3.10,,
-+func,Py_LeaveRecursiveCall,3.9,,
-+func,Py_Main,3.2,,
-+func,Py_MakePendingCalls,3.2,,
-+func,Py_NewInterpreter,3.2,,
-+func,Py_NewRef,3.10,,
-+func,Py_ReprEnter,3.2,,
-+func,Py_ReprLeave,3.2,,
-+func,Py_SetPath,3.7,,
-+func,Py_SetProgramName,3.2,,
-+func,Py_SetPythonHome,3.2,,
-+func,Py_SetRecursionLimit,3.2,,
- type,Py_UCS4,3.2,,
- macro,Py_UNBLOCK_THREADS,3.2,,
--var,Py_UTF8Mode,3.8,,
--function,Py_VaBuildValue,3.2,,
--var,Py_Version,3.11,,
--function,Py_XNewRef,3.10,,
-+data,Py_UTF8Mode,3.8,,
-+func,Py_VaBuildValue,3.2,,
-+data,Py_Version,3.11,,
-+func,Py_XNewRef,3.10,,
- type,Py_buffer,3.11,,full-abi
- type,Py_intptr_t,3.2,,
- type,Py_ssize_t,3.2,,
---- /dev/null
-+++ b/Doc/deprecations/c-api-pending-removal-in-3.14.rst
-@@ -0,0 +1,46 @@
-+Pending Removal in Python 3.14
-+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+
-+* The ``ma_version_tag`` field in :c:type:`PyDictObject` for extension modules
-+ (:pep:`699`; :gh:`101193`).
-+
-+* Creating :c:data:`immutable types ` with mutable
-+ bases (:gh:`95388`).
-+
-+* Functions to configure Python's initialization, deprecated in Python 3.11:
-+
-+ * ``PySys_SetArgvEx()``: set :c:member:`PyConfig.argv` instead.
-+ * ``PySys_SetArgv()``: set :c:member:`PyConfig.argv` instead.
-+ * ``Py_SetProgramName()``: set :c:member:`PyConfig.program_name` instead.
-+ * ``Py_SetPythonHome()``: set :c:member:`PyConfig.home` instead.
-+
-+ The :c:func:`Py_InitializeFromConfig` API should be used with
-+ :c:type:`PyConfig` instead.
-+
-+* Global configuration variables:
-+
-+ * :c:var:`Py_DebugFlag`: use :c:member:`PyConfig.parser_debug` instead.
-+ * :c:var:`Py_VerboseFlag`: use :c:member:`PyConfig.verbose` instead.
-+ * :c:var:`Py_QuietFlag`: use :c:member:`PyConfig.quiet` instead.
-+ * :c:var:`Py_InteractiveFlag`: use :c:member:`PyConfig.interactive` instead.
-+ * :c:var:`Py_InspectFlag`: use :c:member:`PyConfig.inspect` instead.
-+ * :c:var:`Py_OptimizeFlag`: use :c:member:`PyConfig.optimization_level` instead.
-+ * :c:var:`Py_NoSiteFlag`: use :c:member:`PyConfig.site_import` instead.
-+ * :c:var:`Py_BytesWarningFlag`: use :c:member:`PyConfig.bytes_warning` instead.
-+ * :c:var:`Py_FrozenFlag`: use :c:member:`PyConfig.pathconfig_warnings` instead.
-+ * :c:var:`Py_IgnoreEnvironmentFlag`: use :c:member:`PyConfig.use_environment` instead.
-+ * :c:var:`Py_DontWriteBytecodeFlag`: use :c:member:`PyConfig.write_bytecode` instead.
-+ * :c:var:`Py_NoUserSiteDirectory`: use :c:member:`PyConfig.user_site_directory` instead.
-+ * :c:var:`Py_UnbufferedStdioFlag`: use :c:member:`PyConfig.buffered_stdio` instead.
-+ * :c:var:`Py_HashRandomizationFlag`: use :c:member:`PyConfig.use_hash_seed`
-+ and :c:member:`PyConfig.hash_seed` instead.
-+ * :c:var:`Py_IsolatedFlag`: use :c:member:`PyConfig.isolated` instead.
-+ * :c:var:`Py_LegacyWindowsFSEncodingFlag`: use :c:member:`PyPreConfig.legacy_windows_fs_encoding` instead.
-+ * :c:var:`Py_LegacyWindowsStdioFlag`: use :c:member:`PyConfig.legacy_windows_stdio` instead.
-+ * :c:var:`!Py_FileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` instead.
-+ * :c:var:`!Py_HasFileSystemDefaultEncoding`: use :c:member:`PyConfig.filesystem_encoding` instead.
-+ * :c:var:`!Py_FileSystemDefaultEncodeErrors`: use :c:member:`PyConfig.filesystem_errors` instead.
-+ * :c:var:`!Py_UTF8Mode`: use :c:member:`PyPreConfig.utf8_mode` instead. (see :c:func:`Py_PreInitialize`)
-+
-+ The :c:func:`Py_InitializeFromConfig` API should be used with
-+ :c:type:`PyConfig` instead.
---- /dev/null
-+++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst
-@@ -0,0 +1,20 @@
-+Pending Removal in Python 3.15
-+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+
-+* The bundled copy of ``libmpdecimal``.
-+* :c:func:`PyImport_ImportModuleNoBlock`: use :c:func:`PyImport_ImportModule` instead.
-+* :c:func:`PyWeakref_GET_OBJECT`: use :c:func:`!PyWeakref_GetRef` instead.
-+* :c:func:`PyWeakref_GetObject`: use :c:func:`!PyWeakref_GetRef` instead.
-+* :c:type:`!Py_UNICODE_WIDE` type: use :c:type:`wchar_t` instead.
-+* :c:type:`Py_UNICODE` type: use :c:type:`wchar_t` instead.
-+* Python initialization functions:
-+
-+ * :c:func:`PySys_ResetWarnOptions`: clear :data:`sys.warnoptions` and
-+ :data:`!warnings.filters` instead.
-+ * :c:func:`Py_GetExecPrefix`: get :data:`sys.exec_prefix` instead.
-+ * :c:func:`Py_GetPath`: get :data:`sys.path` instead.
-+ * :c:func:`Py_GetPrefix`: get :data:`sys.prefix` instead.
-+ * :c:func:`Py_GetProgramFullPath`: get :data:`sys.executable` instead.
-+ * :c:func:`Py_GetProgramName`: get :data:`sys.executable` instead.
-+ * :c:func:`Py_GetPythonHome`: get :c:member:`PyConfig.home` or
-+ the :envvar:`PYTHONHOME` environment variable instead.
---- /dev/null
-+++ b/Doc/deprecations/c-api-pending-removal-in-future.rst
-@@ -0,0 +1,31 @@
-+Pending Removal in Future Versions
-+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+
-+The following APIs are deprecated and will be removed,
-+although there is currently no date scheduled for their removal.
-+
-+* :c:macro:`Py_TPFLAGS_HAVE_FINALIZE`: unneeded since Python 3.8.
-+* :c:func:`PyErr_Fetch`: use :c:func:`PyErr_GetRaisedException` instead.
-+* :c:func:`PyErr_NormalizeException`: use :c:func:`PyErr_GetRaisedException` instead.
-+* :c:func:`PyErr_Restore`: use :c:func:`PyErr_SetRaisedException` instead.
-+* :c:func:`PyModule_GetFilename`: use :c:func:`PyModule_GetFilenameObject` instead.
-+* :c:func:`PyOS_AfterFork`: use :c:func:`PyOS_AfterFork_Child` instead.
-+* :c:func:`PySlice_GetIndicesEx`: use :c:func:`PySlice_Unpack` and :c:func:`PySlice_AdjustIndices` instead.
-+* :c:func:`!PyUnicode_AsDecodedObject`: use :c:func:`PyCodec_Decode` instead.
-+* :c:func:`!PyUnicode_AsDecodedUnicode`: use :c:func:`PyCodec_Decode` instead.
-+* :c:func:`!PyUnicode_AsEncodedObject`: use :c:func:`PyCodec_Encode` instead.
-+* :c:func:`!PyUnicode_AsEncodedUnicode`: use :c:func:`PyCodec_Encode` instead.
-+* :c:func:`PyUnicode_READY`: unneeded since Python 3.12
-+* :c:func:`!PyErr_Display`: use :c:func:`PyErr_DisplayException` instead.
-+* :c:func:`!_PyErr_ChainExceptions`: use ``_PyErr_ChainExceptions1`` instead.
-+* :c:member:`!PyBytesObject.ob_shash` member:
-+ call :c:func:`PyObject_Hash` instead.
-+* :c:member:`!PyDictObject.ma_version_tag` member.
-+* Thread Local Storage (TLS) API:
-+
-+ * :c:func:`PyThread_create_key`: use :c:func:`PyThread_tss_alloc` instead.
-+ * :c:func:`PyThread_delete_key`: use :c:func:`PyThread_tss_free` instead.
-+ * :c:func:`PyThread_set_key_value`: use :c:func:`PyThread_tss_set` instead.
-+ * :c:func:`PyThread_get_key_value`: use :c:func:`PyThread_tss_get` instead.
-+ * :c:func:`PyThread_delete_key_value`: use :c:func:`PyThread_tss_delete` instead.
-+ * :c:func:`PyThread_ReInitTLS`: unneeded since Python 3.7.
---- /dev/null
-+++ b/Doc/deprecations/index.rst
-@@ -0,0 +1,21 @@
-+Deprecations
-+============
-+
-+.. include:: pending-removal-in-3.13.rst
-+
-+.. include:: pending-removal-in-3.14.rst
-+
-+.. include:: pending-removal-in-3.15.rst
-+
-+.. include:: pending-removal-in-3.16.rst
-+
-+.. include:: pending-removal-in-future.rst
-+
-+C API Deprecations
-+------------------
-+
-+.. include:: c-api-pending-removal-in-3.14.rst
-+
-+.. include:: c-api-pending-removal-in-3.15.rst
-+
-+.. include:: c-api-pending-removal-in-future.rst
---- /dev/null
-+++ b/Doc/deprecations/pending-removal-in-3.13.rst
-@@ -0,0 +1,52 @@
-+Pending Removal in Python 3.13
-+------------------------------
-+
-+Modules (see :pep:`594`):
-+
-+* :mod:`aifc`
-+* :mod:`audioop`
-+* :mod:`cgi`
-+* :mod:`cgitb`
-+* :mod:`chunk`
-+* :mod:`crypt`
-+* :mod:`imghdr`
-+* :mod:`mailcap`
-+* :mod:`msilib`
-+* :mod:`nis`
-+* :mod:`nntplib`
-+* :mod:`ossaudiodev`
-+* :mod:`pipes`
-+* :mod:`sndhdr`
-+* :mod:`spwd`
-+* :mod:`sunau`
-+* :mod:`telnetlib`
-+* :mod:`uu`
-+* :mod:`xdrlib`
-+
-+Other modules:
-+
-+* :mod:`!lib2to3`, and the :program:`2to3` program (:gh:`84540`)
-+
-+APIs:
-+
-+* :class:`!configparser.LegacyInterpolation` (:gh:`90765`)
-+* ``locale.resetlocale()`` (:gh:`90817`)
-+* :meth:`!turtle.RawTurtle.settiltangle` (:gh:`50096`)
-+* :func:`!unittest.findTestCases` (:gh:`50096`)
-+* :func:`!unittest.getTestCaseNames` (:gh:`50096`)
-+* :func:`!unittest.makeSuite` (:gh:`50096`)
-+* :meth:`!unittest.TestProgram.usageExit` (:gh:`67048`)
-+* :class:`!webbrowser.MacOSX` (:gh:`86421`)
-+* :class:`classmethod` descriptor chaining (:gh:`89519`)
-+* :mod:`importlib.resources` deprecated methods:
-+
-+ * ``contents()``
-+ * ``is_resource()``
-+ * ``open_binary()``
-+ * ``open_text()``
-+ * ``path()``
-+ * ``read_binary()``
-+ * ``read_text()``
-+
-+ Use :func:`importlib.resources.files` instead. Refer to `importlib-resources: Migrating from Legacy
-+ `_ (:gh:`106531`)
---- /dev/null
-+++ b/Doc/deprecations/pending-removal-in-3.14.rst
-@@ -0,0 +1,118 @@
-+Pending Removal in Python 3.14
-+------------------------------
-+
-+* :mod:`argparse`: The *type*, *choices*, and *metavar* parameters
-+ of :class:`!argparse.BooleanOptionalAction` are deprecated
-+ and will be removed in 3.14.
-+ (Contributed by Nikita Sobolev in :gh:`92248`.)
-+
-+* :mod:`ast`: The following features have been deprecated in documentation
-+ since Python 3.8, now cause a :exc:`DeprecationWarning` to be emitted at
-+ runtime when they are accessed or used, and will be removed in Python 3.14:
-+
-+ * :class:`!ast.Num`
-+ * :class:`!ast.Str`
-+ * :class:`!ast.Bytes`
-+ * :class:`!ast.NameConstant`
-+ * :class:`!ast.Ellipsis`
-+
-+ Use :class:`ast.Constant` instead.
-+ (Contributed by Serhiy Storchaka in :gh:`90953`.)
-+
-+* :mod:`asyncio`:
-+
-+ * The child watcher classes :class:`~asyncio.MultiLoopChildWatcher`,
-+ :class:`~asyncio.FastChildWatcher`, :class:`~asyncio.AbstractChildWatcher`
-+ and :class:`~asyncio.SafeChildWatcher` are deprecated and
-+ will be removed in Python 3.14.
-+ (Contributed by Kumar Aditya in :gh:`94597`.)
-+
-+ * :func:`asyncio.set_child_watcher`, :func:`asyncio.get_child_watcher`,
-+ :meth:`asyncio.AbstractEventLoopPolicy.set_child_watcher` and
-+ :meth:`asyncio.AbstractEventLoopPolicy.get_child_watcher` are deprecated
-+ and will be removed in Python 3.14.
-+ (Contributed by Kumar Aditya in :gh:`94597`.)
-+
-+ * The :meth:`~asyncio.get_event_loop` method of the
-+ default event loop policy now emits a :exc:`DeprecationWarning` if there
-+ is no current event loop set and it decides to create one.
-+ (Contributed by Serhiy Storchaka and Guido van Rossum in :gh:`100160`.)
-+
-+* :mod:`collections.abc`: Deprecated :class:`~collections.abc.ByteString`.
-+ Prefer :class:`!Sequence` or :class:`~collections.abc.Buffer`.
-+ For use in typing, prefer a union, like ``bytes | bytearray``,
-+ or :class:`collections.abc.Buffer`.
-+ (Contributed by Shantanu Jain in :gh:`91896`.)
-+
-+* :mod:`email`: Deprecated the *isdst* parameter in :func:`email.utils.localtime`.
-+ (Contributed by Alan Williams in :gh:`72346`.)
-+
-+* :mod:`importlib`: ``__package__`` and ``__cached__`` will cease to be set or
-+ taken into consideration by the import system (:gh:`97879`).
-+
-+* :mod:`importlib.abc` deprecated classes:
-+
-+ * :class:`!importlib.abc.ResourceReader`
-+ * :class:`!importlib.abc.Traversable`
-+ * :class:`!importlib.abc.TraversableResources`
-+
-+ Use :mod:`importlib.resources.abc` classes instead:
-+
-+ * :class:`importlib.resources.abc.Traversable`
-+ * :class:`importlib.resources.abc.TraversableResources`
-+
-+ (Contributed by Jason R. Coombs and Hugo van Kemenade in :gh:`93963`.)
-+
-+* :mod:`itertools` had undocumented, inefficient, historically buggy,
-+ and inconsistent support for copy, deepcopy, and pickle operations.
-+ This will be removed in 3.14 for a significant reduction in code
-+ volume and maintenance burden.
-+ (Contributed by Raymond Hettinger in :gh:`101588`.)
-+
-+* :mod:`multiprocessing`: The default start method will change to a safer one on
-+ Linux, BSDs, and other non-macOS POSIX platforms where ``'fork'`` is currently
-+ the default (:gh:`84559`). Adding a runtime warning about this was deemed too
-+ disruptive as the majority of code is not expected to care. Use the
-+ :func:`~multiprocessing.get_context` or
-+ :func:`~multiprocessing.set_start_method` APIs to explicitly specify when
-+ your code *requires* ``'fork'``. See :ref:`multiprocessing-start-methods`.
-+
-+* :mod:`pathlib`: :meth:`~pathlib.PurePath.is_relative_to` and
-+ :meth:`~pathlib.PurePath.relative_to`: passing additional arguments is
-+ deprecated.
-+
-+* :mod:`pkgutil`: :func:`~pkgutil.find_loader` and :func:`~pkgutil.get_loader`
-+ now raise :exc:`DeprecationWarning`;
-+ use :func:`importlib.util.find_spec` instead.
-+ (Contributed by Nikita Sobolev in :gh:`97850`.)
-+
-+* :mod:`pty`:
-+
-+ * ``master_open()``: use :func:`pty.openpty`.
-+ * ``slave_open()``: use :func:`pty.openpty`.
-+
-+* :mod:`sqlite3`:
-+
-+ * :data:`~sqlite3.version` and :data:`~sqlite3.version_info`.
-+
-+ * :meth:`~sqlite3.Cursor.execute` and :meth:`~sqlite3.Cursor.executemany`
-+ if :ref:`named placeholders ` are used and
-+ *parameters* is a sequence instead of a :class:`dict`.
-+
-+ * date and datetime adapter, date and timestamp converter:
-+ see the :mod:`sqlite3` documentation for suggested replacement recipes.
-+
-+* :class:`types.CodeType`: Accessing :attr:`~codeobject.co_lnotab` was
-+ deprecated in :pep:`626`
-+ since 3.10 and was planned to be removed in 3.12,
-+ but it only got a proper :exc:`DeprecationWarning` in 3.12.
-+ May be removed in 3.14.
-+ (Contributed by Nikita Sobolev in :gh:`101866`.)
-+
-+* :mod:`typing`: :class:`~typing.ByteString`, deprecated since Python 3.9,
-+ now causes a :exc:`DeprecationWarning` to be emitted when it is used.
-+
-+* :mod:`urllib`:
-+ :class:`!urllib.parse.Quoter` is deprecated: it was not intended to be a
-+ public API.
-+ (Contributed by Gregory P. Smith in :gh:`88168`.)
---- /dev/null
-+++ b/Doc/deprecations/pending-removal-in-3.15.rst
-@@ -0,0 +1,57 @@
-+Pending Removal in Python 3.15
-+------------------------------
-+
-+* :class:`http.server.CGIHTTPRequestHandler` will be removed along with its
-+ related ``--cgi`` flag to ``python -m http.server``. It was obsolete and
-+ rarely used. No direct replacement exists. *Anything* is better than CGI
-+ to interface a web server with a request handler.
-+
-+* :class:`locale`: :func:`locale.getdefaultlocale` was deprecated in Python 3.11
-+ and originally planned for removal in Python 3.13 (:gh:`90817`),
-+ but removal has been postponed to Python 3.15.
-+ Use :func:`locale.setlocale`, :func:`locale.getencoding` and
-+ :func:`locale.getlocale` instead.
-+ (Contributed by Hugo van Kemenade in :gh:`111187`.)
-+
-+* :mod:`pathlib`:
-+ :meth:`pathlib.PurePath.is_reserved` is deprecated and scheduled for
-+ removal in Python 3.15. From Python 3.13 onwards, use ``os.path.isreserved``
-+ to detect reserved paths on Windows.
-+
-+* :mod:`platform`:
-+ :func:`~platform.java_ver` is deprecated and will be removed in 3.15.
-+ It was largely untested, had a confusing API,
-+ and was only useful for Jython support.
-+ (Contributed by Nikita Sobolev in :gh:`116349`.)
-+
-+* :mod:`threading`:
-+ Passing any arguments to :func:`threading.RLock` is now deprecated.
-+ C version allows any numbers of args and kwargs,
-+ but they are just ignored. Python version does not allow any arguments.
-+ All arguments will be removed from :func:`threading.RLock` in Python 3.15.
-+ (Contributed by Nikita Sobolev in :gh:`102029`.)
-+
-+* :class:`typing.NamedTuple`:
-+
-+ * The undocumented keyword argument syntax for creating :class:`!NamedTuple` classes
-+ (``NT = NamedTuple("NT", x=int)``) is deprecated, and will be disallowed in
-+ 3.15. Use the class-based syntax or the functional syntax instead.
-+
-+ * When using the functional syntax to create a :class:`!NamedTuple` class, failing to
-+ pass a value to the *fields* parameter (``NT = NamedTuple("NT")``) is
-+ deprecated. Passing ``None`` to the *fields* parameter
-+ (``NT = NamedTuple("NT", None)``) is also deprecated. Both will be
-+ disallowed in Python 3.15. To create a :class:`!NamedTuple` class with 0 fields, use
-+ ``class NT(NamedTuple): pass`` or ``NT = NamedTuple("NT", [])``.
-+
-+* :class:`typing.TypedDict`: When using the functional syntax to create a
-+ :class:`!TypedDict` class, failing to pass a value to the *fields* parameter (``TD =
-+ TypedDict("TD")``) is deprecated. Passing ``None`` to the *fields* parameter
-+ (``TD = TypedDict("TD", None)``) is also deprecated. Both will be disallowed
-+ in Python 3.15. To create a :class:`!TypedDict` class with 0 fields, use ``class
-+ TD(TypedDict): pass`` or ``TD = TypedDict("TD", {})``.
-+
-+* :mod:`wave`: Deprecate the ``getmark()``, ``setmark()`` and ``getmarkers()``
-+ methods of the :class:`wave.Wave_read` and :class:`wave.Wave_write` classes.
-+ They will be removed in Python 3.15.
-+ (Contributed by Victor Stinner in :gh:`105096`.)
---- /dev/null
-+++ b/Doc/deprecations/pending-removal-in-3.16.rst
-@@ -0,0 +1,13 @@
-+Pending Removal in Python 3.16
-+------------------------------
-+
-+* :mod:`array`:
-+ :class:`array.array` ``'u'`` type (:c:type:`wchar_t`):
-+ use the ``'w'`` type instead (``Py_UCS4``).
-+
-+* :mod:`builtins`:
-+ ``~bool``, bitwise inversion on bool.
-+
-+* :mod:`symtable`:
-+ Deprecate :meth:`symtable.Class.get_methods` due to the lack of interest.
-+ (Contributed by Bénédikt Tran in :gh:`119698`.)
---- /dev/null
-+++ b/Doc/deprecations/pending-removal-in-future.rst
-@@ -0,0 +1,152 @@
-+Pending Removal in Future Versions
-+----------------------------------
-+
-+The following APIs will be removed in the future,
-+although there is currently no date scheduled for their removal.
-+
-+* :mod:`argparse`: Nesting argument groups and nesting mutually exclusive
-+ groups are deprecated.
-+
-+* :mod:`array`'s ``'u'`` format code (:gh:`57281`)
-+
-+* :mod:`builtins`:
-+
-+ * ``bool(NotImplemented)``.
-+ * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)``
-+ signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead,
-+ the single argument signature.
-+ * Currently Python accepts numeric literals immediately followed by keywords,
-+ for example ``0in x``, ``1or x``, ``0if 1else 2``. It allows confusing and
-+ ambiguous expressions like ``[0x1for x in y]`` (which can be interpreted as
-+ ``[0x1 for x in y]`` or ``[0x1f or x in y]``). A syntax warning is raised
-+ if the numeric literal is immediately followed by one of keywords
-+ :keyword:`and`, :keyword:`else`, :keyword:`for`, :keyword:`if`,
-+ :keyword:`in`, :keyword:`is` and :keyword:`or`. In a future release it
-+ will be changed to a syntax error. (:gh:`87999`)
-+ * Support for ``__index__()`` and ``__int__()`` method returning non-int type:
-+ these methods will be required to return an instance of a strict subclass of
-+ :class:`int`.
-+ * Support for ``__float__()`` method returning a strict subclass of
-+ :class:`float`: these methods will be required to return an instance of
-+ :class:`float`.
-+ * Support for ``__complex__()`` method returning a strict subclass of
-+ :class:`complex`: these methods will be required to return an instance of
-+ :class:`complex`.
-+ * Delegation of ``int()`` to ``__trunc__()`` method.
-+ * Passing a complex number as the *real* or *imag* argument in the
-+ :func:`complex` constructor is now deprecated; it should only be passed
-+ as a single positional argument.
-+ (Contributed by Serhiy Storchaka in :gh:`109218`.)
-+
-+* :mod:`calendar`: ``calendar.January`` and ``calendar.February`` constants are
-+ deprecated and replaced by :data:`calendar.JANUARY` and
-+ :data:`calendar.FEBRUARY`.
-+ (Contributed by Prince Roshan in :gh:`103636`.)
-+
-+* :attr:`codeobject.co_lnotab`: use the :meth:`codeobject.co_lines` method
-+ instead.
-+
-+* :mod:`datetime`:
-+
-+ * :meth:`~datetime.datetime.utcnow`:
-+ use ``datetime.datetime.now(tz=datetime.UTC)``.
-+ * :meth:`~datetime.datetime.utcfromtimestamp`:
-+ use ``datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC)``.
-+
-+* :mod:`gettext`: Plural value must be an integer.
-+
-+* :mod:`importlib`:
-+
-+ * ``load_module()`` method: use ``exec_module()`` instead.
-+ * :func:`~importlib.util.cache_from_source` *debug_override* parameter is
-+ deprecated: use the *optimization* parameter instead.
-+
-+* :mod:`importlib.metadata`:
-+
-+ * ``EntryPoints`` tuple interface.
-+ * Implicit ``None`` on return values.
-+
-+* :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use
-+ BytesIO and binary mode instead.
-+
-+* :mod:`os`: Calling :func:`os.register_at_fork` in multi-threaded process.
-+
-+* :class:`!pydoc.ErrorDuringImport`: A tuple value for *exc_info* parameter is
-+ deprecated, use an exception instance.
-+
-+* :mod:`re`: More strict rules are now applied for numerical group references
-+ and group names in regular expressions. Only sequence of ASCII digits is now
-+ accepted as a numerical reference. The group name in bytes patterns and
-+ replacement strings can now only contain ASCII letters and digits and
-+ underscore.
-+ (Contributed by Serhiy Storchaka in :gh:`91760`.)
-+
-+* :mod:`!sre_compile`, :mod:`!sre_constants` and :mod:`!sre_parse` modules.
-+
-+* :mod:`shutil`: :func:`~shutil.rmtree`'s *onerror* parameter is deprecated in
-+ Python 3.12; use the *onexc* parameter instead.
-+
-+* :mod:`ssl` options and protocols:
-+
-+ * :class:`ssl.SSLContext` without protocol argument is deprecated.
-+ * :class:`ssl.SSLContext`: :meth:`~ssl.SSLContext.set_npn_protocols` and
-+ :meth:`!selected_npn_protocol` are deprecated: use ALPN
-+ instead.
-+ * ``ssl.OP_NO_SSL*`` options
-+ * ``ssl.OP_NO_TLS*`` options
-+ * ``ssl.PROTOCOL_SSLv3``
-+ * ``ssl.PROTOCOL_TLS``
-+ * ``ssl.PROTOCOL_TLSv1``
-+ * ``ssl.PROTOCOL_TLSv1_1``
-+ * ``ssl.PROTOCOL_TLSv1_2``
-+ * ``ssl.TLSVersion.SSLv3``
-+ * ``ssl.TLSVersion.TLSv1``
-+ * ``ssl.TLSVersion.TLSv1_1``
-+
-+* :func:`sysconfig.is_python_build` *check_home* parameter is deprecated and
-+ ignored.
-+
-+* :mod:`threading` methods:
-+
-+ * :meth:`!threading.Condition.notifyAll`: use :meth:`~threading.Condition.notify_all`.
-+ * :meth:`!threading.Event.isSet`: use :meth:`~threading.Event.is_set`.
-+ * :meth:`!threading.Thread.isDaemon`, :meth:`threading.Thread.setDaemon`:
-+ use :attr:`threading.Thread.daemon` attribute.
-+ * :meth:`!threading.Thread.getName`, :meth:`threading.Thread.setName`:
-+ use :attr:`threading.Thread.name` attribute.
-+ * :meth:`!threading.currentThread`: use :meth:`threading.current_thread`.
-+ * :meth:`!threading.activeCount`: use :meth:`threading.active_count`.
-+
-+* :class:`typing.Text` (:gh:`92332`).
-+
-+* :class:`unittest.IsolatedAsyncioTestCase`: it is deprecated to return a value
-+ that is not ``None`` from a test case.
-+
-+* :mod:`urllib.parse` deprecated functions: :func:`~urllib.parse.urlparse` instead
-+
-+ * ``splitattr()``
-+ * ``splithost()``
-+ * ``splitnport()``
-+ * ``splitpasswd()``
-+ * ``splitport()``
-+ * ``splitquery()``
-+ * ``splittag()``
-+ * ``splittype()``
-+ * ``splituser()``
-+ * ``splitvalue()``
-+ * ``to_bytes()``
-+
-+* :mod:`urllib.request`: :class:`~urllib.request.URLopener` and
-+ :class:`~urllib.request.FancyURLopener` style of invoking requests is
-+ deprecated. Use newer :func:`~urllib.request.urlopen` functions and methods.
-+
-+* :mod:`wsgiref`: ``SimpleHandler.stdout.write()`` should not do partial
-+ writes.
-+
-+* :mod:`xml.etree.ElementTree`: Testing the truth value of an
-+ :class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it
-+ will always return ``True``. Prefer explicit ``len(elem)`` or
-+ ``elem is not None`` tests instead.
-+
-+* :meth:`zipimport.zipimporter.load_module` is deprecated:
-+ use :meth:`~zipimport.zipimporter.exec_module` instead.
-diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst
-index c2bc5f699a1..f10dba7b97b 100644
---- a/Doc/extending/newtypes_tutorial.rst
-+++ b/Doc/extending/newtypes_tutorial.rst
-@@ -449,7 +449,7 @@
- though we can make sure the members are initialized to non-``NULL`` values, the
- members can be set to ``NULL`` if the attributes are deleted.
-
--We define a single method, :meth:`!Custom.name()`, that outputs the objects name as the
-+We define a single method, :meth:`!Custom.name`, that outputs the objects name as the
- concatenation of the first and last names. ::
-
- static PyObject *
-diff --git a/Doc/faq/design.rst b/Doc/faq/design.rst
-index c8beb64e39b..ebb6d5ed128 100644
---- a/Doc/faq/design.rst
-+++ b/Doc/faq/design.rst
-@@ -70,7 +70,7 @@
- Python behaves like many popular languages including C and Java.
-
- Many numbers that can be written easily in decimal notation cannot be expressed
--exactly in binary floating-point. For example, after::
-+exactly in binary floating point. For example, after::
-
- >>> x = 1.2
-
-@@ -87,7 +87,7 @@
- The typical precision of 53 bits provides Python floats with 15--16
- decimal digits of accuracy.
-
--For a fuller explanation, please see the :ref:`floating point arithmetic
-+For a fuller explanation, please see the :ref:`floating-point arithmetic
- ` chapter in the Python tutorial.
-
-
-diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst
-index ac10a04d50d..45fd7eb1140 100644
---- a/Doc/faq/library.rst
-+++ b/Doc/faq/library.rst
-@@ -825,12 +825,12 @@
- import random
- random.random()
-
--This returns a random floating point number in the range [0, 1).
-+This returns a random floating-point number in the range [0, 1).
-
- There are also many other specialized generators in this module, such as:
-
- * ``randrange(a, b)`` chooses an integer in the range [a, b).
--* ``uniform(a, b)`` chooses a floating point number in the range [a, b).
-+* ``uniform(a, b)`` chooses a floating-point number in the range [a, b).
- * ``normalvariate(mean, sdev)`` samples the normal (Gaussian) distribution.
-
- Some higher-level functions operate on sequences directly, such as:
-diff --git a/Doc/faq/programming.rst b/Doc/faq/programming.rst
-index f43f69b8a1e..ddfb25d5526 100644
---- a/Doc/faq/programming.rst
-+++ b/Doc/faq/programming.rst
-@@ -869,7 +869,7 @@
- --------------------------------------
-
- For integers, use the built-in :func:`int` type constructor, e.g. ``int('144')
--== 144``. Similarly, :func:`float` converts to floating-point,
-+== 144``. Similarly, :func:`float` converts to a floating-point number,
- e.g. ``float('144') == 144.0``.
-
- By default, these interpret the number as decimal, so that ``int('0144') ==
-@@ -1013,7 +1013,7 @@
- For simple input parsing, the easiest approach is usually to split the line into
- whitespace-delimited words using the :meth:`~str.split` method of string objects
- and then convert decimal strings to numeric values using :func:`int` or
--:func:`float`. :meth:`!split()` supports an optional "sep" parameter which is useful
-+:func:`float`. :meth:`!split` supports an optional "sep" parameter which is useful
- if the line uses something other than whitespace as a separator.
-
- For more complicated input parsing, regular expressions are more powerful
-@@ -1741,11 +1741,31 @@
- is textually replaced with ``_classname__spam``, where ``classname`` is the
- current class name with any leading underscores stripped.
-
--This doesn't guarantee privacy: an outside user can still deliberately access
--the "_classname__spam" attribute, and private values are visible in the object's
--``__dict__``. Many Python programmers never bother to use private variable
--names at all.
-+The identifier can be used unchanged within the class, but to access it outside
-+the class, the mangled name must be used:
-
-+.. code-block:: python
-+
-+ class A:
-+ def __one(self):
-+ return 1
-+ def two(self):
-+ return 2 * self.__one()
-+
-+ class B(A):
-+ def three(self):
-+ return 3 * self._A__one()
-+
-+ four = 4 * A()._A__one()
-+
-+In particular, this does not guarantee privacy since an outside user can still
-+deliberately access the private attribute; many Python programmers never bother
-+to use private variable names at all.
-+
-+.. seealso::
-+
-+ The :ref:`private name mangling specifications `
-+ for details and special cases.
-
- My class defines __del__ but it is not called when I delete the object.
- -----------------------------------------------------------------------
-diff --git a/Doc/glossary.rst b/Doc/glossary.rst
-index d1745bf5ccd..c85370fec84 100644
---- a/Doc/glossary.rst
-+++ b/Doc/glossary.rst
-@@ -591,6 +591,14 @@
- :ref:`idle` is a basic editor and interpreter environment
- which ships with the standard distribution of Python.
-
-+ immortal
-+ *Immortal objects* are a CPython implementation detail introduced
-+ in :pep:`683`.
-+
-+ If an object is immortal, its :term:`reference count` is never modified,
-+ and therefore it is never deallocated while the interpreter is running.
-+ For example, :const:`True` and :const:`None` are immortal in CPython.
-+
- immutable
- An object with a fixed value. Immutable objects include numbers, strings and
- tuples. Such an object cannot be altered. A new object has to
-diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
-index 330402d1835..8be1be3450f 100644
---- a/Doc/howto/descriptor.rst
-+++ b/Doc/howto/descriptor.rst
-@@ -513,7 +513,7 @@
-
- Descriptors are a powerful, general purpose protocol. They are the mechanism
- behind properties, methods, static methods, class methods, and
--:func:`super()`. They are used throughout Python itself. Descriptors
-+:func:`super`. They are used throughout Python itself. Descriptors
- simplify the underlying C code and offer a flexible set of new tools for
- everyday Python programs.
-
-@@ -787,7 +787,7 @@
- ---------------------
-
- The logic for super's dotted lookup is in the :meth:`__getattribute__` method for
--object returned by :class:`super()`.
-+object returned by :func:`super`.
-
- A dotted lookup such as ``super(A, obj).m`` searches ``obj.__class__.__mro__``
- for the base class ``B`` immediately following ``A`` and then returns
-@@ -803,7 +803,7 @@
- Summary of invocation logic
- ---------------------------
-
--The mechanism for descriptors is embedded in the :meth:`__getattribute__()`
-+The mechanism for descriptors is embedded in the :meth:`__getattribute__`
- methods for :class:`object`, :class:`type`, and :func:`super`.
-
- The important points to remember are:
-diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst
-index ffdafb749c7..b575e00bc7c 100644
---- a/Doc/howto/enum.rst
-+++ b/Doc/howto/enum.rst
-@@ -7,7 +7,7 @@
- .. currentmodule:: enum
-
- An :class:`Enum` is a set of symbolic names bound to unique values. They are
--similar to global variables, but they offer a more useful :func:`repr()`,
-+similar to global variables, but they offer a more useful :func:`repr`,
- grouping, type-safety, and a few other features.
-
- They are most useful when you have a variable that can take one of a limited
-@@ -165,7 +165,7 @@
- answer SO questions
-
- In cases where the actual values of the members do not matter, you can save
--yourself some work and use :func:`auto()` for the values::
-+yourself some work and use :func:`auto` for the values::
-
- >>> from enum import auto
- >>> class Weekday(Flag):
-@@ -1129,6 +1129,14 @@
- >>> (Color.RED | Color.GREEN).name
- 'RED|GREEN'
-
-+ >>> class Perm(IntFlag):
-+ ... R = 4
-+ ... W = 2
-+ ... X = 1
-+ ...
-+ >>> (Perm.R & Perm.W).name is None # effectively Perm(0)
-+ True
-+
- - multi-bit flags, aka aliases, can be returned from operations::
-
- >>> Color.RED | Color.BLUE
-diff --git a/Doc/howto/instrumentation.rst b/Doc/howto/instrumentation.rst
-index 9c99fcecce1..6e03ef20a21 100644
---- a/Doc/howto/instrumentation.rst
-+++ b/Doc/howto/instrumentation.rst
-@@ -307,7 +307,7 @@
- .. object:: gc__start(int generation)
-
- Fires when the Python interpreter starts a garbage collection cycle.
-- ``arg0`` is the generation to scan, like :func:`gc.collect()`.
-+ ``arg0`` is the generation to scan, like :func:`gc.collect`.
-
- .. object:: gc__done(long collected)
-
-diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst
-index e35855deedb..a636e06bda8 100644
---- a/Doc/howto/isolating-extensions.rst
-+++ b/Doc/howto/isolating-extensions.rst
-@@ -339,7 +339,7 @@
- - Define a traverse function using ``Py_tp_traverse``, which
- visits the type (e.g. using ``Py_VISIT(Py_TYPE(self))``).
-
--Please refer to the the documentation of
-+Please refer to the documentation of
- :c:macro:`Py_TPFLAGS_HAVE_GC` and :c:member:`~PyTypeObject.tp_traverse`
- for additional considerations.
-
-diff --git a/Doc/howto/logging-cookbook.rst b/Doc/howto/logging-cookbook.rst
-index 06a1ec18b0a..c7b463d1303 100644
---- a/Doc/howto/logging-cookbook.rst
-+++ b/Doc/howto/logging-cookbook.rst
-@@ -4022,7 +4022,7 @@
- which writes to ``sys.stderr`` makes multiple writes, each of which results in a
- separate logged line (for example, the last three lines above). To get around
- this problem, you need to buffer things and only output log lines when newlines
--are seen. Let's use a slghtly better implementation of ``LoggerWriter``:
-+are seen. Let's use a slightly better implementation of ``LoggerWriter``:
-
- .. code-block:: python
-
-diff --git a/Doc/howto/logging.rst b/Doc/howto/logging.rst
-index 877cb24328c..5a392f94da4 100644
---- a/Doc/howto/logging.rst
-+++ b/Doc/howto/logging.rst
-@@ -381,8 +381,52 @@
- The flow of log event information in loggers and handlers is illustrated in the
- following diagram.
-
--.. image:: logging_flow.png
-- :class: invert-in-dark-mode
-+.. only:: not html
-+
-+ .. image:: logging_flow.*
-+
-+.. raw:: html
-+ :file: logging_flow.svg
-+
-+.. raw:: html
-+
-+
-
- Loggers
- ^^^^^^^
---- /dev/null
-+++ b/Doc/howto/logging_flow.svg
-@@ -0,0 +1,327 @@
-+
--- /dev/null
+++ b/Doc/includes/wasm-ios-notavail.rst
@@ -0,0 +1,8 @@
@@ -4137,526 +23,6 @@ index e680e1f9b43..c1b79d2a4a0 100644
- ``wasm32-emscripten`` and ``wasm32-wasi``. See
+ This module does not work or is not available on WebAssembly. See
:ref:`wasm-availability` for more information.
-diff --git a/Doc/library/__main__.rst b/Doc/library/__main__.rst
-index 6232e173d95..647ff9da04d 100644
---- a/Doc/library/__main__.rst
-+++ b/Doc/library/__main__.rst
-@@ -251,9 +251,9 @@
- >>> asyncio.__main__.__name__
- 'asyncio.__main__'
-
--This won't work for ``__main__.py`` files in the root directory of a .zip file
--though. Hence, for consistency, minimal ``__main__.py`` like the :mod:`venv`
--one mentioned below are preferred.
-+This won't work for ``__main__.py`` files in the root directory of a
-+``.zip`` file though. Hence, for consistency, a minimal ``__main__.py``
-+without a ``__name__`` check is preferred.
-
- .. seealso::
-
-diff --git a/Doc/library/array.rst b/Doc/library/array.rst
-index beaa8cdadda..b4e656a7a83 100644
---- a/Doc/library/array.rst
-+++ b/Doc/library/array.rst
-@@ -9,7 +9,7 @@
- --------------
-
- This module defines an object type which can compactly represent an array of
--basic values: characters, integers, floating point numbers. Arrays are sequence
-+basic values: characters, integers, floating-point numbers. Arrays are sequence
- types and behave very much like lists, except that the type of objects stored in
- them is constrained. The type is specified at object creation time by using a
- :dfn:`type code`, which is a single character. The following type codes are
-@@ -253,7 +253,7 @@
- array with the same type and value using :func:`eval`, so long as the
- :class:`~array.array` class has been imported using ``from array import array``.
- Variables ``inf`` and ``nan`` must also be defined if it contains
--corresponding floating point values.
-+corresponding floating-point values.
- Examples::
-
- array('l')
-diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst
-index 1c0c808e273..46e5e8f63da 100644
---- a/Doc/library/ast.rst
-+++ b/Doc/library/ast.rst
-@@ -881,11 +881,15 @@
- .. class:: AnnAssign(target, annotation, value, simple)
-
- An assignment with a type annotation. ``target`` is a single node and can
-- be a :class:`Name`, a :class:`Attribute` or a :class:`Subscript`.
-+ be a :class:`Name`, an :class:`Attribute` or a :class:`Subscript`.
- ``annotation`` is the annotation, such as a :class:`Constant` or :class:`Name`
-- node. ``value`` is a single optional node. ``simple`` is a boolean integer
-- set to True for a :class:`Name` node in ``target`` that do not appear in
-- between parenthesis and are hence pure names and not expressions.
-+ node. ``value`` is a single optional node.
-+
-+ ``simple`` is always either 0 (indicating a "complex" target) or 1
-+ (indicating a "simple" target). A "simple" target consists solely of a
-+ :class:`Name` node that does not appear between parentheses; all other
-+ targets are considered complex. Only simple targets appear in
-+ the :attr:`__annotations__` dictionary of modules and classes.
-
- .. doctest::
-
-@@ -2000,7 +2004,7 @@
- YieldFrom(value)
-
- A ``yield`` or ``yield from`` expression. Because these are expressions, they
-- must be wrapped in a :class:`Expr` node if the value sent back is not used.
-+ must be wrapped in an :class:`Expr` node if the value sent back is not used.
-
- .. doctest::
-
-@@ -2167,7 +2171,7 @@
- If ``type_comments=True`` is given, the parser is modified to check
- and return type comments as specified by :pep:`484` and :pep:`526`.
- This is equivalent to adding :data:`ast.PyCF_TYPE_COMMENTS` to the
-- flags passed to :func:`compile()`. This will report syntax errors
-+ flags passed to :func:`compile`. This will report syntax errors
- for misplaced type comments. Without this flag, type comments will
- be ignored, and the ``type_comment`` field on selected AST nodes
- will always be ``None``. In addition, the locations of ``# type:
-diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
-index ba0ee1b6c2c..bdcea54f6a0 100644
---- a/Doc/library/asyncio-eventloop.rst
-+++ b/Doc/library/asyncio-eventloop.rst
-@@ -126,7 +126,7 @@
-
- Run the event loop until :meth:`stop` is called.
-
-- If :meth:`stop` is called before :meth:`run_forever()` is called,
-+ If :meth:`stop` is called before :meth:`run_forever` is called,
- the loop will poll the I/O selector once with a timeout of zero,
- run all callbacks scheduled in response to I/O events (and
- those that were already scheduled), and then exit.
-@@ -165,7 +165,7 @@
- .. coroutinemethod:: loop.shutdown_asyncgens()
-
- Schedule all currently open :term:`asynchronous generator` objects to
-- close with an :meth:`~agen.aclose()` call. After calling this method,
-+ close with an :meth:`~agen.aclose` call. After calling this method,
- the event loop will issue a warning if a new asynchronous generator
- is iterated. This should be used to reliably finalize all scheduled
- asynchronous generators.
-@@ -1139,6 +1139,14 @@
-
- Asynchronous version of :meth:`socket.getnameinfo`.
-
-+.. note::
-+ Both *getaddrinfo* and *getnameinfo* internally utilize their synchronous
-+ versions through the loop's default thread pool executor.
-+ When this executor is saturated, these methods may experience delays,
-+ which higher-level networking libraries may report as increased timeouts.
-+ To mitigate this, consider using a custom executor for other user tasks,
-+ or setting a default executor with a larger number of workers.
-+
- .. versionchanged:: 3.7
- Both *getaddrinfo* and *getnameinfo* methods were always documented
- to return a coroutine, but prior to Python 3.7 they were, in fact,
-@@ -1238,6 +1246,9 @@
-
- The *executor* argument should be an :class:`concurrent.futures.Executor`
- instance. The default executor is used if *executor* is ``None``.
-+ The default executor can be set by :meth:`loop.set_default_executor`,
-+ otherwise, a :class:`concurrent.futures.ThreadPoolExecutor` will be
-+ lazy-initialized and used by :func:`run_in_executor` if needed.
-
- Example::
-
-@@ -1375,7 +1386,7 @@
-
- This method should not be overloaded in subclassed
- event loops. For custom exception handling, use
-- the :meth:`set_exception_handler()` method.
-+ the :meth:`set_exception_handler` method.
-
- Enabling debug mode
- ^^^^^^^^^^^^^^^^^^^
-@@ -1458,7 +1469,7 @@
- * *stdin* can be any of these:
-
- * a file-like object
-- * an existing file descriptor (a positive integer), for example those created with :meth:`os.pipe()`
-+ * an existing file descriptor (a positive integer), for example those created with :meth:`os.pipe`
- * the :const:`subprocess.PIPE` constant (default) which will create a new
- pipe and connect it,
- * the value ``None`` which will make the subprocess inherit the file
-diff --git a/Doc/library/asyncio-future.rst b/Doc/library/asyncio-future.rst
-index 893ae5518f7..9dce0731411 100644
---- a/Doc/library/asyncio-future.rst
-+++ b/Doc/library/asyncio-future.rst
-@@ -120,20 +120,20 @@
- a :exc:`CancelledError` exception.
-
- If the Future's result isn't yet available, this method raises
-- a :exc:`InvalidStateError` exception.
-+ an :exc:`InvalidStateError` exception.
-
- .. method:: set_result(result)
-
- Mark the Future as *done* and set its result.
-
-- Raises a :exc:`InvalidStateError` error if the Future is
-+ Raises an :exc:`InvalidStateError` error if the Future is
- already *done*.
-
- .. method:: set_exception(exception)
-
- Mark the Future as *done* and set an exception.
-
-- Raises a :exc:`InvalidStateError` error if the Future is
-+ Raises an :exc:`InvalidStateError` error if the Future is
- already *done*.
-
- .. method:: done()
-diff --git a/Doc/library/asyncio-llapi-index.rst b/Doc/library/asyncio-llapi-index.rst
-index 67136ba69ec..3e21054aa4f 100644
---- a/Doc/library/asyncio-llapi-index.rst
-+++ b/Doc/library/asyncio-llapi-index.rst
-@@ -56,10 +56,10 @@
- * - :meth:`loop.close`
- - Close the event loop.
-
-- * - :meth:`loop.is_running()`
-+ * - :meth:`loop.is_running`
- - Return ``True`` if the event loop is running.
-
-- * - :meth:`loop.is_closed()`
-+ * - :meth:`loop.is_closed`
- - Return ``True`` if the event loop is closed.
-
- * - ``await`` :meth:`loop.shutdown_asyncgens`
-diff --git a/Doc/library/asyncio-queue.rst b/Doc/library/asyncio-queue.rst
-index d86fbc21351..63afc411d96 100644
---- a/Doc/library/asyncio-queue.rst
-+++ b/Doc/library/asyncio-queue.rst
-@@ -55,7 +55,7 @@
- Return ``True`` if there are :attr:`maxsize` items in the queue.
-
- If the queue was initialized with ``maxsize=0`` (the default),
-- then :meth:`full()` never returns ``True``.
-+ then :meth:`full` never returns ``True``.
-
- .. coroutinemethod:: get()
-
-diff --git a/Doc/library/asyncio-runner.rst b/Doc/library/asyncio-runner.rst
-index b68b2570ef0..e2cff48ee41 100644
---- a/Doc/library/asyncio-runner.rst
-+++ b/Doc/library/asyncio-runner.rst
-@@ -89,7 +89,7 @@
- current one. By default :func:`asyncio.new_event_loop` is used and set as
- current event loop with :func:`asyncio.set_event_loop` if *loop_factory* is ``None``.
-
-- Basically, :func:`asyncio.run()` example can be rewritten with the runner usage::
-+ Basically, :func:`asyncio.run` example can be rewritten with the runner usage::
-
- async def main():
- await asyncio.sleep(1)
-diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
-index 6c046ebec96..48cd2f247ad 100644
---- a/Doc/library/asyncio-task.rst
-+++ b/Doc/library/asyncio-task.rst
-@@ -1104,7 +1104,7 @@
- a :exc:`CancelledError` exception.
-
- If the Task's result isn't yet available, this method raises
-- a :exc:`InvalidStateError` exception.
-+ an :exc:`InvalidStateError` exception.
-
- .. method:: exception()
-
-diff --git a/Doc/library/asyncio.rst b/Doc/library/asyncio.rst
-index 184f981c102..1fb575d77f3 100644
---- a/Doc/library/asyncio.rst
-+++ b/Doc/library/asyncio.rst
-@@ -56,8 +56,12 @@
- * :ref:`bridge ` callback-based libraries and code
- with async/await syntax.
-
-+.. include:: ../includes/wasm-notavail.rst
-+
- .. _asyncio-cli:
-
-+.. rubric:: asyncio REPL
-+
- You can experiment with an ``asyncio`` concurrent context in the REPL:
-
- .. code-block:: pycon
-@@ -70,7 +74,10 @@
- >>> await asyncio.sleep(10, result='hello')
- 'hello'
-
--.. include:: ../includes/wasm-notavail.rst
-+.. audit-event:: cpython.run_stdin "" ""
-+
-+.. versionchanged:: 3.12.5 (also 3.11.10, 3.10.15, 3.9.20, and 3.8.20)
-+ Emits audit events.
-
- .. We use the "rubric" directive here to avoid creating
- the "Reference" subsection in the TOC.
-diff --git a/Doc/library/collections.abc.rst b/Doc/library/collections.abc.rst
-index ea27436f67f..0adbd305b46 100644
---- a/Doc/library/collections.abc.rst
-+++ b/Doc/library/collections.abc.rst
-@@ -216,6 +216,9 @@
-
- ABC for classes that provide the :meth:`~object.__call__` method.
-
-+ See :ref:`annotating-callables` for details on how to use
-+ :class:`!Callable` in type annotations.
-+
- .. class:: Iterable
-
- ABC for classes that provide the :meth:`~container.__iter__` method.
-@@ -253,6 +256,9 @@
- :meth:`~generator.send`,
- :meth:`~generator.throw` and :meth:`~generator.close` methods.
-
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`!Generator` in type annotations.
-+
- .. versionadded:: 3.5
-
- .. class:: Sequence
-@@ -331,6 +337,11 @@
- Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``.
- Use :func:`inspect.isawaitable` to detect them.
-
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`!Coroutine` in type annotations.
-+ The variance and order of type parameters correspond to those of
-+ :class:`Generator`.
-+
- .. versionadded:: 3.5
-
- .. class:: AsyncIterable
-@@ -352,6 +363,9 @@
- ABC for :term:`asynchronous generator` classes that implement the protocol
- defined in :pep:`525` and :pep:`492`.
-
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`!AsyncGenerator` in type annotations.
-+
- .. versionadded:: 3.6
-
- .. class:: Buffer
-diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst
-index fedf1914145..fe9a35ecfb0 100644
---- a/Doc/library/collections.rst
-+++ b/Doc/library/collections.rst
-@@ -99,7 +99,7 @@
- :func:`super` function. A reference to ``d.parents`` is equivalent to:
- ``ChainMap(*d.maps[1:])``.
-
-- Note, the iteration order of a :class:`ChainMap()` is determined by
-+ Note, the iteration order of a :class:`ChainMap` is determined by
- scanning the mappings last to first::
-
- >>> baseline = {'music': 'bach', 'art': 'rembrandt'}
-diff --git a/Doc/library/colorsys.rst b/Doc/library/colorsys.rst
-index 125d62b1740..ffebf4e40dd 100644
---- a/Doc/library/colorsys.rst
-+++ b/Doc/library/colorsys.rst
-@@ -14,7 +14,7 @@
- between colors expressed in the RGB (Red Green Blue) color space used in
- computer monitors and three other coordinate systems: YIQ, HLS (Hue Lightness
- Saturation) and HSV (Hue Saturation Value). Coordinates in all of these color
--spaces are floating point values. In the YIQ space, the Y coordinate is between
-+spaces are floating-point values. In the YIQ space, the Y coordinate is between
- 0 and 1, but the I and Q coordinates can be positive or negative. In all other
- spaces, the coordinates are all between 0 and 1.
-
-diff --git a/Doc/library/compileall.rst b/Doc/library/compileall.rst
-index f2c6433408e..1cf40fa6424 100644
---- a/Doc/library/compileall.rst
-+++ b/Doc/library/compileall.rst
-@@ -90,7 +90,7 @@
- .. option:: -j N
-
- Use *N* workers to compile the files within the given directory.
-- If ``0`` is used, then the result of :func:`os.cpu_count()`
-+ If ``0`` is used, then the result of :func:`os.cpu_count`
- will be used.
-
- .. option:: --invalidation-mode [timestamp|checked-hash|unchecked-hash]
-diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst
-index 560260e8a4b..5f04cbc42bf 100644
---- a/Doc/library/configparser.rst
-+++ b/Doc/library/configparser.rst
-@@ -147,23 +147,28 @@
- It is possible to read several configurations into a single
- :class:`ConfigParser`, where the most recently added configuration has the
- highest priority. Any conflicting keys are taken from the more recent
--configuration while the previously existing keys are retained.
-+configuration while the previously existing keys are retained. The example
-+below reads in an ``override.ini`` file, which will override any conflicting
-+keys from the ``example.ini`` file.
-+
-+.. code-block:: ini
-+
-+ [DEFAULT]
-+ ServerAliveInterval = -1
-
- .. doctest::
-
-- >>> another_config = configparser.ConfigParser()
-- >>> another_config.read('example.ini')
-- ['example.ini']
-- >>> another_config['topsecret.server.example']['Port']
-- '50022'
-- >>> another_config.read_string("[topsecret.server.example]\nPort=48484")
-- >>> another_config['topsecret.server.example']['Port']
-- '48484'
-- >>> another_config.read_dict({"topsecret.server.example": {"Port": 21212}})
-- >>> another_config['topsecret.server.example']['Port']
-- '21212'
-- >>> another_config['topsecret.server.example']['ForwardX11']
-- 'no'
-+ >>> config_override = configparser.ConfigParser()
-+ >>> config_override['DEFAULT'] = {'ServerAliveInterval': '-1'}
-+ >>> with open('override.ini', 'w') as configfile:
-+ ... config_override.write(configfile)
-+ ...
-+ >>> config_override = configparser.ConfigParser()
-+ >>> config_override.read(['example.ini', 'override.ini'])
-+ ['example.ini', 'override.ini']
-+ >>> print(config_override.get('DEFAULT', 'ServerAliveInterval'))
-+ -1
-+
-
- This behaviour is equivalent to a :meth:`ConfigParser.read` call with several
- files passed to the *filenames* parameter.
-@@ -955,9 +960,34 @@
- When *converters* is given, it should be a dictionary where each key
- represents the name of a type converter and each value is a callable
- implementing the conversion from string to the desired datatype. Every
-- converter gets its own corresponding :meth:`!get*()` method on the parser
-+ converter gets its own corresponding :meth:`!get*` method on the parser
- object and section proxies.
-
-+ It is possible to read several configurations into a single
-+ :class:`ConfigParser`, where the most recently added configuration has the
-+ highest priority. Any conflicting keys are taken from the more recent
-+ configuration while the previously existing keys are retained. The example
-+ below reads in an ``override.ini`` file, which will override any conflicting
-+ keys from the ``example.ini`` file.
-+
-+ .. code-block:: ini
-+
-+ [DEFAULT]
-+ ServerAliveInterval = -1
-+
-+ .. doctest::
-+
-+ >>> config_override = configparser.ConfigParser()
-+ >>> config_override['DEFAULT'] = {'ServerAliveInterval': '-1'}
-+ >>> with open('override.ini', 'w') as configfile:
-+ ... config_override.write(configfile)
-+ ...
-+ >>> config_override = configparser.ConfigParser()
-+ >>> config_override.read(['example.ini', 'override.ini'])
-+ ['example.ini', 'override.ini']
-+ >>> print(config_override.get('DEFAULT', 'ServerAliveInterval'))
-+ -1
-+
- .. versionchanged:: 3.1
- The default *dict_type* is :class:`collections.OrderedDict`.
-
-@@ -970,7 +1000,7 @@
- The *converters* argument was added.
-
- .. versionchanged:: 3.7
-- The *defaults* argument is read with :meth:`read_dict()`,
-+ The *defaults* argument is read with :meth:`read_dict`,
- providing consistent behavior across the parser: non-string
- keys and values are implicitly converted to strings.
-
-@@ -1123,7 +1153,7 @@
- .. method:: getfloat(section, option, *, raw=False, vars=None[, fallback])
-
- A convenience method which coerces the *option* in the specified *section*
-- to a floating point number. See :meth:`get` for explanation of *raw*,
-+ to a floating-point number. See :meth:`get` for explanation of *raw*,
- *vars* and *fallback*.
-
-
-diff --git a/Doc/library/constants.rst b/Doc/library/constants.rst
-index 93a7244f87d..3eceecc4e0a 100644
---- a/Doc/library/constants.rst
-+++ b/Doc/library/constants.rst
-@@ -79,6 +79,8 @@
- :exc:`SyntaxError`), so they can be considered "true" constants.
-
-
-+.. _site-consts:
-+
- Constants added by the :mod:`site` module
- -----------------------------------------
-
-@@ -94,6 +96,13 @@
- (i.e. EOF) to exit", and when called, raise :exc:`SystemExit` with the
- specified exit code.
-
-+.. data:: help
-+ :noindex:
-+
-+ Object that when printed, prints the message "Type help() for interactive
-+ help, or help(object) for help about object.", and when called,
-+ acts as described :func:`elsewhere `.
-+
- .. data:: copyright
- credits
-
-diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst
-index 27cf99446e5..f5b349441bc 100644
---- a/Doc/library/contextlib.rst
-+++ b/Doc/library/contextlib.rst
-@@ -322,7 +322,7 @@
-
- .. versionchanged:: 3.12
- ``suppress`` now supports suppressing exceptions raised as
-- part of an :exc:`BaseExceptionGroup`.
-+ part of a :exc:`BaseExceptionGroup`.
-
- .. function:: redirect_stdout(new_target)
-
-diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst
-index 8ae386b489f..b2261ea5127 100644
---- a/Doc/library/contextvars.rst
-+++ b/Doc/library/contextvars.rst
-@@ -15,7 +15,7 @@
- manage the current context in asynchronous frameworks.
-
- Context managers that have state should use Context Variables
--instead of :func:`threading.local()` to prevent their state from
-+instead of :func:`threading.local` to prevent their state from
- bleeding to other code unexpectedly, when used in concurrent code.
-
- See also :pep:`567` for additional details.
-@@ -146,7 +146,7 @@
-
- Every thread will have a different top-level :class:`~contextvars.Context`
- object. This means that a :class:`ContextVar` object behaves in a similar
-- fashion to :func:`threading.local()` when values are assigned in different
-+ fashion to :func:`threading.local` when values are assigned in different
- threads.
-
- Context implements the :class:`collections.abc.Mapping` interface.
-diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
-index e01bd9277b1..130f9b9cab4 100644
---- a/Doc/library/ctypes.rst
-+++ b/Doc/library/ctypes.rst
-@@ -107,7 +107,7 @@
-
- Note that win32 system dlls like ``kernel32`` and ``user32`` often export ANSI
- as well as UNICODE versions of a function. The UNICODE version is exported with
--an ``W`` appended to the name, while the ANSI version is exported with an ``A``
-+a ``W`` appended to the name, while the ANSI version is exported with an ``A``
- appended to the name. The win32 ``GetModuleHandle`` function, which returns a
- *module handle* for a given module name, has the following C prototype, and a
- macro is used to expose one of them as ``GetModuleHandle`` depending on whether
diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst
index 2ebda3d3396..91ea6150fb1 100644
--- a/Doc/library/curses.rst
@@ -4670,722 +36,36 @@ index 2ebda3d3396..91ea6150fb1 100644
.. note::
Whenever the documentation mentions a *character* it can be specified
-diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst
-index e4a9cd4ebcb..87b532fb4f8 100644
---- a/Doc/library/dataclasses.rst
-+++ b/Doc/library/dataclasses.rst
-@@ -124,7 +124,7 @@
- - *unsafe_hash*: If ``False`` (the default), a :meth:`~object.__hash__` method
- is generated according to how *eq* and *frozen* are set.
-
-- :meth:`!__hash__` is used by built-in :meth:`hash()`, and when objects are
-+ :meth:`!__hash__` is used by built-in :meth:`hash`, and when objects are
- added to hashed collections such as dictionaries and sets. Having a
- :meth:`!__hash__` implies that instances of the class are immutable.
- Mutability is a complicated property that depends on the programmer's
-@@ -185,10 +185,21 @@
- - *slots*: If true (the default is ``False``), :attr:`~object.__slots__` attribute
- will be generated and new class will be returned instead of the original one.
- If :attr:`!__slots__` is already defined in the class, then :exc:`TypeError`
-- is raised. Calling no-arg :func:`super` in dataclasses using ``slots=True`` will result in
-- the following exception being raised:
-- ``TypeError: super(type, obj): obj must be an instance or subtype of type``.
-- The two-arg :func:`super` is a valid workaround. See :gh:`90562` for full details.
-+ is raised.
-+
-+ .. warning::
-+ Calling no-arg :func:`super` in dataclasses using ``slots=True``
-+ will result in the following exception being raised:
-+ ``TypeError: super(type, obj): obj must be an instance or subtype of type``.
-+ The two-arg :func:`super` is a valid workaround.
-+ See :gh:`90562` for full details.
-+
-+ .. warning::
-+ Passing parameters to a base class :meth:`~object.__init_subclass__`
-+ when using ``slots=True`` will result in a :exc:`TypeError`.
-+ Either use ``__init_subclass__`` with no parameters
-+ or use default values as a workaround.
-+ See :gh:`91126` for full details.
-
- .. versionadded:: 3.10
-
-@@ -204,7 +215,8 @@
-
- - *weakref_slot*: If true (the default is ``False``), add a slot
- named "__weakref__", which is required to make an instance
-- weakref-able. It is an error to specify ``weakref_slot=True``
-+ :func:`weakref-able `.
-+ It is an error to specify ``weakref_slot=True``
- without also specifying ``slots=True``.
-
- .. versionadded:: 3.11
-diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst
-index 4ba9d6df890..e3ddd8ca82e 100644
---- a/Doc/library/datetime.rst
-+++ b/Doc/library/datetime.rst
-@@ -48,7 +48,7 @@
- -----------------------
+diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst
+index 500e831908f..7f7d650bf5d 100644
+--- a/Doc/library/dbm.rst
++++ b/Doc/library/dbm.rst
+@@ -14,6 +14,7 @@
+ is a `third party interface `_ to
+ the Oracle Berkeley DB.
- Date and time objects may be categorized as "aware" or "naive" depending on
--whether or not they include timezone information.
-+whether or not they include time zone information.
++.. include:: ../includes/wasm-ios-notavail.rst
- With sufficient knowledge of applicable algorithmic and political time
- adjustments, such as time zone and daylight saving time information,
-@@ -58,7 +58,7 @@
+ .. exception:: error
- A **naive** object does not contain enough information to unambiguously locate
- itself relative to other date/time objects. Whether a naive object represents
--Coordinated Universal Time (UTC), local time, or time in some other timezone is
-+Coordinated Universal Time (UTC), local time, or time in some other time zone is
- purely up to the program, just like it is up to the program whether a
- particular number represents metres, miles, or mass. Naive objects are easy to
- understand and to work with, at the cost of ignoring some aspects of reality.
-@@ -70,9 +70,9 @@
- time, the time zone name, and whether daylight saving time is in effect.
+@@ -398,4 +399,3 @@
+ .. method:: dumbdbm.close()
- Only one concrete :class:`tzinfo` class, the :class:`timezone` class, is
--supplied by the :mod:`!datetime` module. The :class:`timezone` class can
--represent simple timezones with fixed offsets from UTC, such as UTC itself or
--North American EST and EDT timezones. Supporting timezones at deeper levels of
-+supplied by the :mod:`!datetime` module. The :class:`!timezone` class can
-+represent simple time zones with fixed offsets from UTC, such as UTC itself or
-+North American EST and EDT time zones. Supporting time zones at deeper levels of
- detail is up to the application. The rules for time adjustment across the
- world are more political than rational, change frequently, and there is no
- standard suitable for every application aside from UTC.
-@@ -95,7 +95,7 @@
-
- .. attribute:: UTC
-
-- Alias for the UTC timezone singleton :attr:`datetime.timezone.utc`.
-+ Alias for the UTC time zone singleton :attr:`datetime.timezone.utc`.
-
- .. versionadded:: 3.11
-
-@@ -283,17 +283,23 @@
- Note that, because of normalization, ``timedelta.max`` is greater than ``-timedelta.min``.
- ``-timedelta.max`` is not representable as a :class:`timedelta` object.
-
-+
- Instance attributes (read-only):
-
--+------------------+--------------------------------------------+
--| Attribute | Value |
--+==================+============================================+
--| ``days`` | Between -999999999 and 999999999 inclusive |
--+------------------+--------------------------------------------+
--| ``seconds`` | Between 0 and 86399 inclusive |
--+------------------+--------------------------------------------+
--| ``microseconds`` | Between 0 and 999999 inclusive |
--+------------------+--------------------------------------------+
-+.. attribute:: timedelta.days
-+
-+ Between -999,999,999 and 999,999,999 inclusive.
-+
-+
-+.. attribute:: timedelta.seconds
-+
-+ Between 0 and 86,399 inclusive.
-+
-+
-+.. attribute:: timedelta.microseconds
-+
-+ Between 0 and 999,999 inclusive.
-+
-
- Supported operations:
-
-@@ -850,7 +856,7 @@
-
- .. classmethod:: datetime.today()
-
-- Return the current local datetime, with :attr:`.tzinfo` ``None``.
-+ Return the current local date and time, with :attr:`.tzinfo` ``None``.
-
- Equivalent to::
-
-@@ -1034,7 +1040,7 @@
- .. versionadded:: 3.7
- .. versionchanged:: 3.11
- Previously, this method only supported formats that could be emitted by
-- :meth:`date.isoformat()` or :meth:`datetime.isoformat()`.
-+ :meth:`date.isoformat` or :meth:`datetime.isoformat`.
-
-
- .. classmethod:: datetime.fromisocalendar(year, week, day)
-@@ -1051,7 +1057,7 @@
- Return a :class:`.datetime` corresponding to *date_string*, parsed according to
- *format*.
-
-- If *format* does not contain microseconds or timezone information, this is equivalent to::
-+ If *format* does not contain microseconds or time zone information, this is equivalent to::
-
- datetime(*(time.strptime(date_string, format)[0:6]))
-
-@@ -1267,22 +1273,22 @@
-
- If provided, *tz* must be an instance of a :class:`tzinfo` subclass, and its
- :meth:`utcoffset` and :meth:`dst` methods must not return ``None``. If *self*
-- is naive, it is presumed to represent time in the system timezone.
-+ is naive, it is presumed to represent time in the system time zone.
-
- If called without arguments (or with ``tz=None``) the system local
-- timezone is assumed for the target timezone. The ``.tzinfo`` attribute of the converted
-+ time zone is assumed for the target time zone. The ``.tzinfo`` attribute of the converted
- datetime instance will be set to an instance of :class:`timezone`
- with the zone name and offset obtained from the OS.
-
- If ``self.tzinfo`` is *tz*, ``self.astimezone(tz)`` is equal to *self*: no
- adjustment of date or time data is performed. Else the result is local
-- time in the timezone *tz*, representing the same UTC time as *self*: after
-+ time in the time zone *tz*, representing the same UTC time as *self*: after
- ``astz = dt.astimezone(tz)``, ``astz - astz.utcoffset()`` will have
- the same date and time data as ``dt - dt.utcoffset()``.
-
-- If you merely want to attach a time zone object *tz* to a datetime *dt* without
-+ If you merely want to attach a :class:`timezone` object *tz* to a datetime *dt* without
- adjustment of date and time data, use ``dt.replace(tzinfo=tz)``. If you
-- merely want to remove the time zone object from an aware datetime *dt* without
-+ merely want to remove the :class:`!timezone` object from an aware datetime *dt* without
- conversion of date and time data, use ``dt.replace(tzinfo=None)``.
-
- Note that the default :meth:`tzinfo.fromutc` method can be overridden in a
-@@ -1292,7 +1298,7 @@
- def astimezone(self, tz):
- if self.tzinfo is tz:
- return self
-- # Convert self to UTC, and attach the new time zone object.
-+ # Convert self to UTC, and attach the new timezone object.
- utc = (self - self.utcoffset()).replace(tzinfo=tz)
- # Convert from UTC to tz's local time.
- return tz.fromutc(utc)
-@@ -1406,7 +1412,7 @@
-
- There is no method to obtain the POSIX timestamp directly from a
- naive :class:`.datetime` instance representing UTC time. If your
-- application uses this convention and your system timezone is not
-+ application uses this convention and your system time zone is not
- set to UTC, you can obtain the POSIX timestamp by supplying
- ``tzinfo=timezone.utc``::
-
-@@ -1817,7 +1823,7 @@
- .. versionadded:: 3.7
- .. versionchanged:: 3.11
- Previously, this method only supported formats that could be emitted by
-- :meth:`time.isoformat()`.
-+ :meth:`time.isoformat`.
-
-
- Instance methods:
-@@ -1974,7 +1980,7 @@
- supply implementations of the standard :class:`tzinfo` methods needed by the
- :class:`.datetime` methods you use. The :mod:`!datetime` module provides
- :class:`timezone`, a simple concrete subclass of :class:`tzinfo` which can
-- represent timezones with fixed offset from UTC such as UTC itself or North
-+ represent time zones with fixed offset from UTC such as UTC itself or North
- American EST and EDT.
-
- Special requirement for pickling: A :class:`tzinfo` subclass must have an
-@@ -2099,14 +2105,14 @@
- method, ``dt.tzinfo`` is the same object as *self*. :class:`tzinfo` methods can
- rely on this, unless user code calls :class:`tzinfo` methods directly. The
- intent is that the :class:`tzinfo` methods interpret *dt* as being in local
--time, and not need worry about objects in other timezones.
-+time, and not need worry about objects in other time zones.
-
- There is one more :class:`tzinfo` method that a subclass may wish to override:
-
-
- .. method:: tzinfo.fromutc(dt)
-
-- This is called from the default :class:`datetime.astimezone()`
-+ This is called from the default :meth:`datetime.astimezone`
- implementation. When called from that, ``dt.tzinfo`` is *self*, and *dt*'s
- date and time data are to be viewed as expressing a UTC time. The purpose
- of :meth:`fromutc` is to adjust the date and time data, returning an
-@@ -2216,12 +2222,12 @@
- :mod:`zoneinfo`
- The :mod:`!datetime` module has a basic :class:`timezone` class (for
- handling arbitrary fixed offsets from UTC) and its :attr:`timezone.utc`
-- attribute (a UTC timezone instance).
-+ attribute (a UTC :class:`!timezone` instance).
-
-- ``zoneinfo`` brings the *IANA timezone database* (also known as the Olson
-+ ``zoneinfo`` brings the *IANA time zone database* (also known as the Olson
- database) to Python, and its usage is recommended.
-
-- `IANA timezone database `_
-+ `IANA time zone database `_
- The Time Zone Database (often called tz, tzdata or zoneinfo) contains code
- and data that represent the history of local time for many representative
- locations around the globe. It is updated periodically to reflect changes
-@@ -2235,10 +2241,10 @@
- -------------------------
-
- The :class:`timezone` class is a subclass of :class:`tzinfo`, each
--instance of which represents a timezone defined by a fixed offset from
-+instance of which represents a time zone defined by a fixed offset from
- UTC.
-
--Objects of this class cannot be used to represent timezone information in the
-+Objects of this class cannot be used to represent time zone information in the
- locations where different offsets are used in different days of the year or
- where historical changes have been made to civil time.
-
-@@ -2299,7 +2305,7 @@
-
- .. attribute:: timezone.utc
-
-- The UTC timezone, ``timezone(timedelta(0))``.
-+ The UTC time zone, ``timezone(timedelta(0))``.
-
-
- .. index::
-@@ -2508,7 +2514,7 @@
-
- datetime(*(time.strptime(date_string, format)[0:6]))
-
--except when the format includes sub-second components or timezone offset
-+except when the format includes sub-second components or time zone offset
- information, which are supported in ``datetime.strptime`` but are discarded by
- ``time.strptime``.
-
-diff --git a/Doc/library/dbm.rst b/Doc/library/dbm.rst
-index 500e831908f..7f7d650bf5d 100644
---- a/Doc/library/dbm.rst
-+++ b/Doc/library/dbm.rst
-@@ -14,6 +14,7 @@
- is a `third party interface `_ to
- the Oracle Berkeley DB.
-
-+.. include:: ../includes/wasm-ios-notavail.rst
-
- .. exception:: error
-
-@@ -398,4 +399,3 @@
- .. method:: dumbdbm.close()
-
- Close the database.
--
-diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
-index 9aa4254ab80..c5544f6216f 100644
---- a/Doc/library/decimal.rst
-+++ b/Doc/library/decimal.rst
-@@ -1,4 +1,4 @@
--:mod:`!decimal` --- Decimal fixed point and floating point arithmetic
-+:mod:`!decimal` --- Decimal fixed-point and floating-point arithmetic
- =====================================================================
-
- .. module:: decimal
-@@ -31,7 +31,7 @@
- --------------
-
- The :mod:`decimal` module provides support for fast correctly rounded
--decimal floating point arithmetic. It offers several advantages over the
-+decimal floating-point arithmetic. It offers several advantages over the
- :class:`float` datatype:
-
- * Decimal "is based on a floating-point model which was designed with people
-@@ -207,7 +207,7 @@
- .. versionchanged:: 3.3
-
- Decimals interact well with much of the rest of Python. Here is a small decimal
--floating point flying circus:
-+floating-point flying circus:
-
- .. doctest::
- :options: +NORMALIZE_WHITESPACE
-@@ -373,7 +373,7 @@
- digits, and an integer exponent. For example, ``Decimal((0, (1, 4, 1, 4), -3))``
- returns ``Decimal('1.414')``.
-
-- If *value* is a :class:`float`, the binary floating point value is losslessly
-+ If *value* is a :class:`float`, the binary floating-point value is losslessly
- converted to its exact decimal equivalent. This conversion can often require
- 53 or more digits of precision. For example, ``Decimal(float('1.1'))``
- converts to
-@@ -403,7 +403,7 @@
- Underscores are allowed for grouping, as with integral and floating-point
- literals in code.
-
-- Decimal floating point objects share many properties with the other built-in
-+ Decimal floating-point objects share many properties with the other built-in
- numeric types such as :class:`float` and :class:`int`. All of the usual math
- operations and special methods apply. Likewise, decimal objects can be
- copied, pickled, printed, used as dictionary keys, used as set elements,
-@@ -445,7 +445,7 @@
- Mixed-type comparisons between :class:`Decimal` instances and other
- numeric types are now fully supported.
-
-- In addition to the standard numeric properties, decimal floating point
-+ In addition to the standard numeric properties, decimal floating-point
- objects also have a number of specialized methods:
-
-
-@@ -897,6 +897,48 @@
- :const:`Rounded`. If given, applies *rounding*; otherwise, uses the
- rounding method in either the supplied *context* or the current context.
-
-+ Decimal numbers can be rounded using the :func:`.round` function:
-+
-+ .. describe:: round(number)
-+ .. describe:: round(number, ndigits)
-+
-+ If *ndigits* is not given or ``None``,
-+ returns the nearest :class:`int` to *number*,
-+ rounding ties to even, and ignoring the rounding mode of the
-+ :class:`Decimal` context. Raises :exc:`OverflowError` if *number* is an
-+ infinity or :exc:`ValueError` if it is a (quiet or signaling) NaN.
-+
-+ If *ndigits* is an :class:`int`, the context's rounding mode is respected
-+ and a :class:`Decimal` representing *number* rounded to the nearest
-+ multiple of ``Decimal('1E-ndigits')`` is returned; in this case,
-+ ``round(number, ndigits)`` is equivalent to
-+ ``self.quantize(Decimal('1E-ndigits'))``. Returns ``Decimal('NaN')`` if
-+ *number* is a quiet NaN. Raises :class:`InvalidOperation` if *number*
-+ is an infinity, a signaling NaN, or if the length of the coefficient after
-+ the quantize operation would be greater than the current context's
-+ precision. In other words, for the non-corner cases:
-+
-+ * if *ndigits* is positive, return *number* rounded to *ndigits* decimal
-+ places;
-+ * if *ndigits* is zero, return *number* rounded to the nearest integer;
-+ * if *ndigits* is negative, return *number* rounded to the nearest
-+ multiple of ``10**abs(ndigits)``.
-+
-+ For example::
-+
-+ >>> from decimal import Decimal, getcontext, ROUND_DOWN
-+ >>> getcontext().rounding = ROUND_DOWN
-+ >>> round(Decimal('3.75')) # context rounding ignored
-+ 4
-+ >>> round(Decimal('3.5')) # round-ties-to-even
-+ 4
-+ >>> round(Decimal('3.75'), 0) # uses the context rounding
-+ Decimal('3')
-+ >>> round(Decimal('3.75'), 1)
-+ Decimal('3.7')
-+ >>> round(Decimal('3.75'), -1)
-+ Decimal('0E+1')
-+
-
- .. _logical_operands_label:
-
-@@ -1699,7 +1741,7 @@
-
- .. _decimal-notes:
-
--Floating Point Notes
-+Floating-Point Notes
- --------------------
-
-
-@@ -1712,7 +1754,7 @@
-
- The effects of round-off error can be amplified by the addition or subtraction
- of nearly offsetting quantities resulting in loss of significance. Knuth
--provides two instructive examples where rounded floating point arithmetic with
-+provides two instructive examples where rounded floating-point arithmetic with
- insufficient precision causes the breakdown of the associative and distributive
- properties of addition:
-
-@@ -1802,7 +1844,7 @@
- In addition to the two signed zeros which are distinct yet equal, there are
- various representations of zero with differing precisions yet equivalent in
- value. This takes a bit of getting used to. For an eye accustomed to
--normalized floating point representations, it is not immediately obvious that
-+normalized floating-point representations, it is not immediately obvious that
- the following calculation returns a value equal to zero:
-
- >>> 1 / Decimal('Infinity')
-@@ -2129,7 +2171,7 @@
-
- Q. Is there a way to convert a regular float to a :class:`Decimal`?
-
--A. Yes, any binary floating point number can be exactly expressed as a
-+A. Yes, any binary floating-point number can be exactly expressed as a
- Decimal though an exact conversion may take more precision than intuition would
- suggest:
-
-@@ -2183,7 +2225,7 @@
- A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of
- the decimal module integrate the high speed `libmpdec
- `_ library for
--arbitrary precision correctly rounded decimal floating point arithmetic [#]_.
-+arbitrary precision correctly rounded decimal floating-point arithmetic [#]_.
- ``libmpdec`` uses `Karatsuba multiplication
- `_
- for medium-sized numbers and the `Number Theoretic Transform
-diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
-index e3920587099..82b4aa28857 100644
---- a/Doc/library/dis.rst
-+++ b/Doc/library/dis.rst
-@@ -995,11 +995,15 @@
- .. opcode:: BUILD_TUPLE (count)
-
- Creates a tuple consuming *count* items from the stack, and pushes the
-- resulting tuple onto the stack.::
-+ resulting tuple onto the stack::
-
-- assert count > 0
-- STACK, values = STACK[:-count], STACK[-count:]
-- STACK.append(tuple(values))
-+ if count == 0:
-+ value = ()
-+ else:
-+ value = tuple(STACK[-count:])
-+ STACK = STACK[:-count]
-+
-+ STACK.append(value)
-
-
- .. opcode:: BUILD_LIST (count)
-@@ -1128,7 +1132,10 @@
- .. opcode:: COMPARE_OP (opname)
-
- Performs a Boolean operation. The operation name can be found in
-- ``cmp_op[opname]``.
-+ ``cmp_op[opname >> 4]``.
-+
-+ .. versionchanged:: 3.12
-+ The cmp_op index is now stored in the four-highest bits of oparg instead of the four-lowest bits of oparg.
-
-
- .. opcode:: IS_OP (invert)
-@@ -1455,7 +1462,7 @@
-
- end = STACK.pop()
- start = STACK.pop()
-- STACK.append(slice(start, stop))
-+ STACK.append(slice(start, end))
-
- if it is 3, implements::
-
-@@ -1592,7 +1599,7 @@
- | ``INTRINSIC_STOPITERATION_ERROR`` | Extracts the return value from a |
- | | ``StopIteration`` exception. |
- +-----------------------------------+-----------------------------------+
-- | ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an aync generator value |
-+ | ``INTRINSIC_ASYNC_GEN_WRAP`` | Wraps an async generator value |
- +-----------------------------------+-----------------------------------+
- | ``INTRINSIC_UNARY_POSITIVE`` | Performs the unary ``+`` |
- | | operation |
-diff --git a/Doc/library/email.compat32-message.rst b/Doc/library/email.compat32-message.rst
-index c4c322a82e1..4285c436e8d 100644
---- a/Doc/library/email.compat32-message.rst
-+++ b/Doc/library/email.compat32-message.rst
-@@ -7,6 +7,7 @@
- :synopsis: The base class representing email messages in a fashion
- backward compatible with Python 3.2
- :noindex:
-+ :no-index:
-
-
- The :class:`Message` class is very similar to the
-@@ -104,7 +105,7 @@
-
- .. method:: __str__()
-
-- Equivalent to :meth:`.as_string()`. Allows ``str(msg)`` to produce a
-+ Equivalent to :meth:`.as_string`. Allows ``str(msg)`` to produce a
- string containing the formatted message.
-
-
-@@ -142,7 +143,7 @@
-
- .. method:: __bytes__()
-
-- Equivalent to :meth:`.as_bytes()`. Allows ``bytes(msg)`` to produce a
-+ Equivalent to :meth:`.as_bytes`. Allows ``bytes(msg)`` to produce a
- bytes object containing the formatted message.
-
- .. versionadded:: 3.4
-diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst
-index 33ab4265116..f8f43d82a3d 100644
---- a/Doc/library/email.errors.rst
-+++ b/Doc/library/email.errors.rst
-@@ -58,6 +58,13 @@
- :class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g.
- :class:`~email.mime.image.MIMEImage`).
-
-+
-+.. exception:: HeaderWriteError()
-+
-+ Raised when an error occurs when the :mod:`~email.generator` outputs
-+ headers.
-+
-+
- .. exception:: MessageDefect()
-
- This is the base class for all defects found when parsing email messages.
-diff --git a/Doc/library/email.header.rst b/Doc/library/email.header.rst
-index 6e230d5faf1..219fad0d2f6 100644
---- a/Doc/library/email.header.rst
-+++ b/Doc/library/email.header.rst
-@@ -77,7 +77,7 @@
- The maximum line length can be specified explicitly via *maxlinelen*. For
- splitting the first line to a shorter value (to account for the field header
- which isn't included in *s*, e.g. :mailheader:`Subject`) pass in the name of the
-- field in *header_name*. The default *maxlinelen* is 76, and the default value
-+ field in *header_name*. The default *maxlinelen* is 78, and the default value
- for *header_name* is ``None``, meaning it is not taken into account for the
- first line of a long, split header.
-
-diff --git a/Doc/library/email.message.rst b/Doc/library/email.message.rst
-index e9cce1af186..71d6e321f38 100644
---- a/Doc/library/email.message.rst
-+++ b/Doc/library/email.message.rst
-@@ -124,7 +124,7 @@
-
- .. method:: __bytes__()
-
-- Equivalent to :meth:`.as_bytes()`. Allows ``bytes(msg)`` to produce a
-+ Equivalent to :meth:`.as_bytes`. Allows ``bytes(msg)`` to produce a
- bytes object containing the serialized message.
-
-
-diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst
-index 83feedf7283..51d65dc5ba9 100644
---- a/Doc/library/email.policy.rst
-+++ b/Doc/library/email.policy.rst
-@@ -229,6 +229,24 @@
-
- .. versionadded:: 3.6
-
-+
-+ .. attribute:: verify_generated_headers
-+
-+ If ``True`` (the default), the generator will raise
-+ :exc:`~email.errors.HeaderWriteError` instead of writing a header
-+ that is improperly folded or delimited, such that it would
-+ be parsed as multiple headers or joined with adjacent data.
-+ Such headers can be generated by custom header classes or bugs
-+ in the ``email`` module.
-+
-+ As it's a security feature, this defaults to ``True`` even in the
-+ :class:`~email.policy.Compat32` policy.
-+ For backwards compatible, but unsafe, behavior, it must be set to
-+ ``False`` explicitly.
-+
-+ .. versionadded:: 3.12.5
-+
-+
- The following :class:`Policy` method is intended to be called by code using
- the email library to create policy instances with custom settings:
-
-diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst
-index 092bfa81462..1cb744b545d 100644
---- a/Doc/library/email.utils.rst
-+++ b/Doc/library/email.utils.rst
-@@ -58,13 +58,18 @@
- begins with angle brackets, they are stripped off.
-
-
--.. function:: parseaddr(address)
-+.. function:: parseaddr(address, *, strict=True)
-
- Parse address -- which should be the value of some address-containing field such
- as :mailheader:`To` or :mailheader:`Cc` -- into its constituent *realname* and
- *email address* parts. Returns a tuple of that information, unless the parse
- fails, in which case a 2-tuple of ``('', '')`` is returned.
-
-+ If *strict* is true, use a strict parser which rejects malformed inputs.
-+
-+ .. versionchanged:: 3.12.6
-+ Add *strict* optional parameter and reject malformed inputs by default.
-+
-
- .. function:: formataddr(pair, charset='utf-8')
-
-@@ -82,12 +87,15 @@
- Added the *charset* option.
-
-
--.. function:: getaddresses(fieldvalues)
-+.. function:: getaddresses(fieldvalues, *, strict=True)
-
- This method returns a list of 2-tuples of the form returned by ``parseaddr()``.
- *fieldvalues* is a sequence of header field values as might be returned by
-- :meth:`Message.get_all `. Here's a simple
-- example that gets all the recipients of a message::
-+ :meth:`Message.get_all `.
-+
-+ If *strict* is true, use a strict parser which rejects malformed inputs.
-+
-+ Here's a simple example that gets all the recipients of a message::
-
- from email.utils import getaddresses
-
-@@ -97,6 +105,9 @@
- resent_ccs = msg.get_all('resent-cc', [])
- all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)
-
-+ .. versionchanged:: 3.12.6
-+ Add *strict* optional parameter and reject malformed inputs by default.
-+
-
- .. function:: parsedate(date)
-
-@@ -148,7 +159,7 @@
-
- Fri, 09 Nov 2001 01:08:47 -0000
-
-- Optional *timeval* if given is a floating point time value as accepted by
-+ Optional *timeval* if given is a floating-point time value as accepted by
- :func:`time.gmtime` and :func:`time.localtime`, otherwise the current time is
- used.
-
-diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst
-index 3726028492a..518a2940edc 100644
---- a/Doc/library/ensurepip.rst
-+++ b/Doc/library/ensurepip.rst
-@@ -38,7 +38,7 @@
- :pep:`453`: Explicit bootstrapping of pip in Python installations
- The original rationale and specification for this module.
+ Close the database.
+-
+diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst
+index 3726028492a..518a2940edc 100644
+--- a/Doc/library/ensurepip.rst
++++ b/Doc/library/ensurepip.rst
+@@ -38,7 +38,7 @@
+ :pep:`453`: Explicit bootstrapping of pip in Python installations
+ The original rationale and specification for this module.
-.. include:: ../includes/wasm-notavail.rst
+.. include:: ../includes/wasm-ios-notavail.rst
Command line interface
----------------------
-diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
-index 10acff619f9..6e2872b9c70 100644
---- a/Doc/library/enum.rst
-+++ b/Doc/library/enum.rst
-@@ -517,7 +517,7 @@
-
- ``Flag`` is the same as :class:`Enum`, but its members support the bitwise
- operators ``&`` (*AND*), ``|`` (*OR*), ``^`` (*XOR*), and ``~`` (*INVERT*);
-- the results of those operators are members of the enumeration.
-+ the results of those operations are (aliases of) members of the enumeration.
-
- .. method:: __contains__(self, value)
-
-@@ -560,6 +560,8 @@
- >>> len(white)
- 3
-
-+ .. versionadded:: 3.11
-+
- .. method:: __bool__(self):
-
- Returns *True* if any members in flag, *False* otherwise::
-diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
-index de46518e673..537547f6c9c 100644
---- a/Doc/library/exceptions.rst
-+++ b/Doc/library/exceptions.rst
-@@ -412,8 +412,8 @@
- represented. This cannot occur for integers (which would rather raise
- :exc:`MemoryError` than give up). However, for historical reasons,
- OverflowError is sometimes raised for integers that are outside a required
-- range. Because of the lack of standardization of floating point exception
-- handling in C, most floating point operations are not checked.
-+ range. Because of the lack of standardization of floating-point exception
-+ handling in C, most floating-point operations are not checked.
-
-
- .. exception:: RecursionError
diff --git a/Doc/library/fcntl.rst b/Doc/library/fcntl.rst
index d23a105cd5b..1faef54c116 100644
--- a/Doc/library/fcntl.rst
@@ -5399,190 +79,6 @@ index d23a105cd5b..1faef54c116 100644
All functions in this module take a file descriptor *fd* as their first
argument. This can be an integer file descriptor, such as returned by
-diff --git a/Doc/library/fileinput.rst b/Doc/library/fileinput.rst
-index 94a4139f64c..8f32b11e565 100644
---- a/Doc/library/fileinput.rst
-+++ b/Doc/library/fileinput.rst
-@@ -47,7 +47,7 @@
- a file may not have one.
-
- You can control how files are opened by providing an opening hook via the
--*openhook* parameter to :func:`fileinput.input` or :class:`FileInput()`. The
-+*openhook* parameter to :func:`fileinput.input` or :func:`FileInput`. The
- hook must be a function that takes two arguments, *filename* and *mode*, and
- returns an accordingly opened file-like object. If *encoding* and/or *errors*
- are specified, they will be passed to the hook as additional keyword arguments.
-diff --git a/Doc/library/fractions.rst b/Doc/library/fractions.rst
-index 42569ec8e65..11591cb348d 100644
---- a/Doc/library/fractions.rst
-+++ b/Doc/library/fractions.rst
-@@ -31,7 +31,7 @@
- :class:`Fraction` instance with the same value. The next two versions accept
- either a :class:`float` or a :class:`decimal.Decimal` instance, and return a
- :class:`Fraction` instance with exactly the same value. Note that due to the
-- usual issues with binary floating-point (see :ref:`tut-fp-issues`), the
-+ usual issues with binary floating point (see :ref:`tut-fp-issues`), the
- argument to ``Fraction(1.1)`` is not exactly equal to 11/10, and so
- ``Fraction(1.1)`` does *not* return ``Fraction(11, 10)`` as one might expect.
- (But see the documentation for the :meth:`limit_denominator` method below.)
-@@ -87,7 +87,7 @@
-
- .. versionchanged:: 3.9
- The :func:`math.gcd` function is now used to normalize the *numerator*
-- and *denominator*. :func:`math.gcd` always return a :class:`int` type.
-+ and *denominator*. :func:`math.gcd` always returns an :class:`int` type.
- Previously, the GCD type depended on *numerator* and *denominator*.
-
- .. versionchanged:: 3.11
-diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst
-index 8c39dc00f5d..bb153220672 100644
---- a/Doc/library/ftplib.rst
-+++ b/Doc/library/ftplib.rst
-@@ -243,7 +243,7 @@
- Retrieve a file in binary transfer mode.
-
- :param str cmd:
-- An appropriate ``STOR`` command: :samp:`"STOR {filename}"`.
-+ An appropriate ``RETR`` command: :samp:`"RETR {filename}"`.
-
- :param callback:
- A single parameter callable that is called
-diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
-index 6901c021d7b..51b6a2f2941 100644
---- a/Doc/library/functions.rst
-+++ b/Doc/library/functions.rst
-@@ -57,7 +57,7 @@
- .. function:: abs(x)
-
- Return the absolute value of a number. The argument may be an
-- integer, a floating point number, or an object implementing
-+ integer, a floating-point number, or an object implementing
- :meth:`~object.__abs__`.
- If the argument is a complex number, its magnitude is returned.
-
-@@ -161,7 +161,7 @@
- This function drops you into the debugger at the call site. Specifically,
- it calls :func:`sys.breakpointhook`, passing ``args`` and ``kws`` straight
- through. By default, ``sys.breakpointhook()`` calls
-- :func:`pdb.set_trace()` expecting no arguments. In this case, it is
-+ :func:`pdb.set_trace` expecting no arguments. In this case, it is
- purely a convenience function so you don't have to explicitly import
- :mod:`pdb` or type as much code to enter the debugger. However,
- :func:`sys.breakpointhook` can be set to some other function and
-@@ -538,7 +538,7 @@
- Take two (non-complex) numbers as arguments and return a pair of numbers
- consisting of their quotient and remainder when using integer division. With
- mixed operand types, the rules for binary arithmetic operators apply. For
-- integers, the result is the same as ``(a // b, a % b)``. For floating point
-+ integers, the result is the same as ``(a // b, a % b)``. For floating-point
- numbers the result is ``(q, a % b)``, where *q* is usually ``math.floor(a /
- b)`` but may be 1 less than that. In any case ``q * b + a % b`` is very
- close to *a*, if ``a % b`` is non-zero it has the same sign as *b*, and ``0
-@@ -714,7 +714,7 @@
- single: NaN
- single: Infinity
-
-- Return a floating point number constructed from a number or a string.
-+ Return a floating-point number constructed from a number or a string.
-
- Examples:
-
-@@ -755,8 +755,8 @@
- Case is not significant, so, for example, "inf", "Inf", "INFINITY", and
- "iNfINity" are all acceptable spellings for positive infinity.
-
-- Otherwise, if the argument is an integer or a floating point number, a
-- floating point number with the same value (within Python's floating point
-+ Otherwise, if the argument is an integer or a floating-point number, a
-+ floating-point number with the same value (within Python's floating-point
- precision) is returned. If the argument is outside the range of a Python
- float, an :exc:`OverflowError` will be raised.
-
-@@ -983,7 +983,7 @@
- ``int(x)`` returns ``x.__int__()``. If the argument defines :meth:`~object.__index__`,
- it returns ``x.__index__()``. If the argument defines :meth:`~object.__trunc__`,
- it returns ``x.__trunc__()``.
-- For floating point numbers, this truncates towards zero.
-+ For floating-point numbers, this truncates towards zero.
-
- If the argument is not a number or if *base* is given, then it must be a string,
- :class:`bytes`, or :class:`bytearray` instance representing an integer
-@@ -1267,7 +1267,7 @@
- (which on *some* Unix systems, means that *all* writes append to the end of
- the file regardless of the current seek position). In text mode, if
- *encoding* is not specified the encoding used is platform-dependent:
-- :func:`locale.getencoding()` is called to get the current locale encoding.
-+ :func:`locale.getencoding` is called to get the current locale encoding.
- (For reading and writing raw bytes use binary mode and leave
- *encoding* unspecified.) The available modes are:
-
-@@ -1440,7 +1440,7 @@
- (where :func:`open` is declared), :mod:`os`, :mod:`os.path`, :mod:`tempfile`,
- and :mod:`shutil`.
-
-- .. audit-event:: open file,mode,flags open
-+ .. audit-event:: open path,mode,flags open
-
- The ``mode`` and ``flags`` arguments may have been modified or inferred from
- the original call.
-@@ -1496,7 +1496,9 @@
- returns ``100``, but ``pow(10, -2)`` returns ``0.01``. For a negative base of
- type :class:`int` or :class:`float` and a non-integral exponent, a complex
- result is delivered. For example, ``pow(-9, 0.5)`` returns a value close
-- to ``3j``.
-+ to ``3j``. Whereas, for a negative base of type :class:`int` or :class:`float`
-+ with an integral exponent, a float result is delivered. For example,
-+ ``pow(-9, 2.0)`` returns ``81.0``.
-
- For :class:`int` operands *base* and *exp*, if *mod* is present, *mod* must
- also be of integer type and *mod* must be nonzero. If *mod* is present and
-@@ -1857,7 +1859,7 @@
-
- For some use cases, there are good alternatives to :func:`sum`.
- The preferred, fast way to concatenate a sequence of strings is by calling
-- ``''.join(sequence)``. To add floating point values with extended precision,
-+ ``''.join(sequence)``. To add floating-point values with extended precision,
- see :func:`math.fsum`\. To concatenate a series of iterables, consider using
- :func:`itertools.chain`.
-
-@@ -1883,10 +1885,10 @@
- ``D -> B -> C -> A -> object`` and the value of *type* is ``B``,
- then :func:`super` searches ``C -> A -> object``.
-
-- The :attr:`~class.__mro__` attribute of the *object_or_type* lists the method
-- resolution search order used by both :func:`getattr` and :func:`super`. The
-- attribute is dynamic and can change whenever the inheritance hierarchy is
-- updated.
-+ The :attr:`~class.__mro__` attribute of the class corresponding to
-+ *object_or_type* lists the method resolution search order used by both
-+ :func:`getattr` and :func:`super`. The attribute is dynamic and can change
-+ whenever the inheritance hierarchy is updated.
-
- If the second argument is omitted, the super object returned is unbound. If
- the second argument is an object, ``isinstance(obj, type)`` must be true. If
-diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst
-index 655e05f4ce2..6b6e599842d 100644
---- a/Doc/library/functools.rst
-+++ b/Doc/library/functools.rst
-@@ -34,7 +34,7 @@
- Returns the same as ``lru_cache(maxsize=None)``, creating a thin
- wrapper around a dictionary lookup for the function arguments. Because it
- never needs to evict old values, this is smaller and faster than
-- :func:`lru_cache()` with a size limit.
-+ :func:`lru_cache` with a size limit.
-
- For example::
-
-diff --git a/Doc/library/getpass.rst b/Doc/library/getpass.rst
-index b364b1fe031..5c0de1889e5 100644
---- a/Doc/library/getpass.rst
-+++ b/Doc/library/getpass.rst
-@@ -49,4 +49,4 @@
- systems which support the :mod:`pwd` module, otherwise, an exception is
- raised.
-
-- In general, this function should be preferred over :func:`os.getlogin()`.
-+ In general, this function should be preferred over :func:`os.getlogin`.
diff --git a/Doc/library/grp.rst b/Doc/library/grp.rst
index 57a77d51a02..f1157e189a3 100644
--- a/Doc/library/grp.rst
@@ -5596,69 +92,10 @@ index 57a77d51a02..f1157e189a3 100644
Group database entries are reported as a tuple-like object, whose attributes
correspond to the members of the ``group`` structure (Attribute field below, see
-diff --git a/Doc/library/gzip.rst b/Doc/library/gzip.rst
-index a2fff0f9fcb..30088666716 100644
---- a/Doc/library/gzip.rst
-+++ b/Doc/library/gzip.rst
-@@ -194,7 +194,9 @@
- .. versionchanged:: 3.11
- Speed is improved by compressing all data at once instead of in a
- streamed fashion. Calls with *mtime* set to ``0`` are delegated to
-- :func:`zlib.compress` for better speed.
-+ :func:`zlib.compress` for better speed. In this situation the
-+ output may contain a gzip header "OS" byte value other than 255
-+ "unknown" as supplied by the underlying zlib implementation.
-
- .. function:: decompress(data)
-
-diff --git a/Doc/library/http.server.rst b/Doc/library/http.server.rst
-index fcc314a8d88..d2e43f03f94 100644
---- a/Doc/library/http.server.rst
-+++ b/Doc/library/http.server.rst
-@@ -263,7 +263,7 @@
-
- Adds a blank line
- (indicating the end of the HTTP headers in the response)
-- to the headers buffer and calls :meth:`flush_headers()`.
-+ to the headers buffer and calls :meth:`flush_headers`.
-
- .. versionchanged:: 3.2
- The buffered headers are written to the output stream.
-@@ -378,7 +378,7 @@
-
- If the request was mapped to a file, it is opened. Any :exc:`OSError`
- exception in opening the requested file is mapped to a ``404``,
-- ``'File not found'`` error. If there was a ``'If-Modified-Since'``
-+ ``'File not found'`` error. If there was an ``'If-Modified-Since'``
- header in the request, and the file was not modified after this time,
- a ``304``, ``'Not Modified'`` response is sent. Otherwise, the content
- type is guessed by calling the :meth:`guess_type` method, which in turn
-diff --git a/Doc/library/importlib.resources.abc.rst b/Doc/library/importlib.resources.abc.rst
-index 5ea8044e1ec..54995ddbfbc 100644
---- a/Doc/library/importlib.resources.abc.rst
-+++ b/Doc/library/importlib.resources.abc.rst
-@@ -22,7 +22,7 @@
- something like a data file that lives next to the ``__init__.py``
- file of the package. The purpose of this class is to help abstract
- out the accessing of such data files so that it does not matter if
-- the package and its data file(s) are stored in a e.g. zip file
-+ the package and its data file(s) are stored e.g. in a zip file
- versus on the file system.
-
- For any of methods of this class, a *resource* argument is
diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
-index d92bb2f8e5c..c7faf8ba218 100644
+index b100e6c8e85..c7faf8ba218 100644
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
-@@ -657,7 +657,7 @@
- something like a data file that lives next to the ``__init__.py``
- file of the package. The purpose of this class is to help abstract
- out the accessing of such data files so that it does not matter if
-- the package and its data file(s) are stored in a e.g. zip file
-+ the package and its data file(s) are stored e.g. in a zip file
- versus on the file system.
-
- For any of methods of this class, a *resource* argument is
@@ -1241,6 +1241,69 @@
and how the module's :attr:`__file__` is populated.
@@ -5729,507 +166,6 @@ index d92bb2f8e5c..c7faf8ba218 100644
:mod:`importlib.util` -- Utility code for importers
---------------------------------------------------
-diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst
-index 7d1aab8e299..dbf7d6868b0 100644
---- a/Doc/library/inspect.rst
-+++ b/Doc/library/inspect.rst
-@@ -42,220 +42,233 @@
- .. this function name is too big to fit in the ascii-art table below
- .. |coroutine-origin-link| replace:: :func:`sys.set_coroutine_origin_tracking_depth`
-
--+-----------+-------------------+---------------------------+
--| Type | Attribute | Description |
--+===========+===================+===========================+
--| class | __doc__ | documentation string |
--+-----------+-------------------+---------------------------+
--| | __name__ | name with which this |
--| | | class was defined |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | __module__ | name of module in which |
--| | | this class was defined |
--+-----------+-------------------+---------------------------+
--| | __type_params__ | A tuple containing the |
--| | | :ref:`type parameters |
--| | | ` of |
--| | | a generic class |
--+-----------+-------------------+---------------------------+
--| method | __doc__ | documentation string |
--+-----------+-------------------+---------------------------+
--| | __name__ | name with which this |
--| | | method was defined |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | __func__ | function object |
--| | | containing implementation |
--| | | of method |
--+-----------+-------------------+---------------------------+
--| | __self__ | instance to which this |
--| | | method is bound, or |
--| | | ``None`` |
--+-----------+-------------------+---------------------------+
--| | __module__ | name of module in which |
--| | | this method was defined |
--+-----------+-------------------+---------------------------+
--| function | __doc__ | documentation string |
--+-----------+-------------------+---------------------------+
--| | __name__ | name with which this |
--| | | function was defined |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | __code__ | code object containing |
--| | | compiled function |
--| | | :term:`bytecode` |
--+-----------+-------------------+---------------------------+
--| | __defaults__ | tuple of any default |
--| | | values for positional or |
--| | | keyword parameters |
--+-----------+-------------------+---------------------------+
--| | __kwdefaults__ | mapping of any default |
--| | | values for keyword-only |
--| | | parameters |
--+-----------+-------------------+---------------------------+
--| | __globals__ | global namespace in which |
--| | | this function was defined |
--+-----------+-------------------+---------------------------+
--| | __builtins__ | builtins namespace |
--+-----------+-------------------+---------------------------+
--| | __annotations__ | mapping of parameters |
--| | | names to annotations; |
--| | | ``"return"`` key is |
--| | | reserved for return |
--| | | annotations. |
--+-----------+-------------------+---------------------------+
--| | __type_params__ | A tuple containing the |
--| | | :ref:`type parameters |
--| | | ` of |
--| | | a generic function |
--+-----------+-------------------+---------------------------+
--| | __module__ | name of module in which |
--| | | this function was defined |
--+-----------+-------------------+---------------------------+
--| traceback | tb_frame | frame object at this |
--| | | level |
--+-----------+-------------------+---------------------------+
--| | tb_lasti | index of last attempted |
--| | | instruction in bytecode |
--+-----------+-------------------+---------------------------+
--| | tb_lineno | current line number in |
--| | | Python source code |
--+-----------+-------------------+---------------------------+
--| | tb_next | next inner traceback |
--| | | object (called by this |
--| | | level) |
--+-----------+-------------------+---------------------------+
--| frame | f_back | next outer frame object |
--| | | (this frame's caller) |
--+-----------+-------------------+---------------------------+
--| | f_builtins | builtins namespace seen |
--| | | by this frame |
--+-----------+-------------------+---------------------------+
--| | f_code | code object being |
--| | | executed in this frame |
--+-----------+-------------------+---------------------------+
--| | f_globals | global namespace seen by |
--| | | this frame |
--+-----------+-------------------+---------------------------+
--| | f_lasti | index of last attempted |
--| | | instruction in bytecode |
--+-----------+-------------------+---------------------------+
--| | f_lineno | current line number in |
--| | | Python source code |
--+-----------+-------------------+---------------------------+
--| | f_locals | local namespace seen by |
--| | | this frame |
--+-----------+-------------------+---------------------------+
--| | f_trace | tracing function for this |
--| | | frame, or ``None`` |
--+-----------+-------------------+---------------------------+
--| code | co_argcount | number of arguments (not |
--| | | including keyword only |
--| | | arguments, \* or \*\* |
--| | | args) |
--+-----------+-------------------+---------------------------+
--| | co_code | string of raw compiled |
--| | | bytecode |
--+-----------+-------------------+---------------------------+
--| | co_cellvars | tuple of names of cell |
--| | | variables (referenced by |
--| | | containing scopes) |
--+-----------+-------------------+---------------------------+
--| | co_consts | tuple of constants used |
--| | | in the bytecode |
--+-----------+-------------------+---------------------------+
--| | co_filename | name of file in which |
--| | | this code object was |
--| | | created |
--+-----------+-------------------+---------------------------+
--| | co_firstlineno | number of first line in |
--| | | Python source code |
--+-----------+-------------------+---------------------------+
--| | co_flags | bitmap of ``CO_*`` flags, |
--| | | read more :ref:`here |
--| | | `|
--+-----------+-------------------+---------------------------+
--| | co_lnotab | encoded mapping of line |
--| | | numbers to bytecode |
--| | | indices |
--+-----------+-------------------+---------------------------+
--| | co_freevars | tuple of names of free |
--| | | variables (referenced via |
--| | | a function's closure) |
--+-----------+-------------------+---------------------------+
--| | co_posonlyargcount| number of positional only |
--| | | arguments |
--+-----------+-------------------+---------------------------+
--| | co_kwonlyargcount | number of keyword only |
--| | | arguments (not including |
--| | | \*\* arg) |
--+-----------+-------------------+---------------------------+
--| | co_name | name with which this code |
--| | | object was defined |
--+-----------+-------------------+---------------------------+
--| | co_qualname | fully qualified name with |
--| | | which this code object |
--| | | was defined |
--+-----------+-------------------+---------------------------+
--| | co_names | tuple of names other |
--| | | than arguments and |
--| | | function locals |
--+-----------+-------------------+---------------------------+
--| | co_nlocals | number of local variables |
--+-----------+-------------------+---------------------------+
--| | co_stacksize | virtual machine stack |
--| | | space required |
--+-----------+-------------------+---------------------------+
--| | co_varnames | tuple of names of |
--| | | arguments and local |
--| | | variables |
--+-----------+-------------------+---------------------------+
--| generator | __name__ | name |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | gi_frame | frame |
--+-----------+-------------------+---------------------------+
--| | gi_running | is the generator running? |
--+-----------+-------------------+---------------------------+
--| | gi_code | code |
--+-----------+-------------------+---------------------------+
--| | gi_yieldfrom | object being iterated by |
--| | | ``yield from``, or |
--| | | ``None`` |
--+-----------+-------------------+---------------------------+
--| coroutine | __name__ | name |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | cr_await | object being awaited on, |
--| | | or ``None`` |
--+-----------+-------------------+---------------------------+
--| | cr_frame | frame |
--+-----------+-------------------+---------------------------+
--| | cr_running | is the coroutine running? |
--+-----------+-------------------+---------------------------+
--| | cr_code | code |
--+-----------+-------------------+---------------------------+
--| | cr_origin | where coroutine was |
--| | | created, or ``None``. See |
--| | | |coroutine-origin-link| |
--+-----------+-------------------+---------------------------+
--| builtin | __doc__ | documentation string |
--+-----------+-------------------+---------------------------+
--| | __name__ | original name of this |
--| | | function or method |
--+-----------+-------------------+---------------------------+
--| | __qualname__ | qualified name |
--+-----------+-------------------+---------------------------+
--| | __self__ | instance to which a |
--| | | method is bound, or |
--| | | ``None`` |
--+-----------+-------------------+---------------------------+
-++-----------------+-------------------+---------------------------+
-+| Type | Attribute | Description |
-++=================+===================+===========================+
-+| class | __doc__ | documentation string |
-++-----------------+-------------------+---------------------------+
-+| | __name__ | name with which this |
-+| | | class was defined |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | __module__ | name of module in which |
-+| | | this class was defined |
-++-----------------+-------------------+---------------------------+
-+| | __type_params__ | A tuple containing the |
-+| | | :ref:`type parameters |
-+| | | ` of |
-+| | | a generic class |
-++-----------------+-------------------+---------------------------+
-+| method | __doc__ | documentation string |
-++-----------------+-------------------+---------------------------+
-+| | __name__ | name with which this |
-+| | | method was defined |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | __func__ | function object |
-+| | | containing implementation |
-+| | | of method |
-++-----------------+-------------------+---------------------------+
-+| | __self__ | instance to which this |
-+| | | method is bound, or |
-+| | | ``None`` |
-++-----------------+-------------------+---------------------------+
-+| | __module__ | name of module in which |
-+| | | this method was defined |
-++-----------------+-------------------+---------------------------+
-+| function | __doc__ | documentation string |
-++-----------------+-------------------+---------------------------+
-+| | __name__ | name with which this |
-+| | | function was defined |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | __code__ | code object containing |
-+| | | compiled function |
-+| | | :term:`bytecode` |
-++-----------------+-------------------+---------------------------+
-+| | __defaults__ | tuple of any default |
-+| | | values for positional or |
-+| | | keyword parameters |
-++-----------------+-------------------+---------------------------+
-+| | __kwdefaults__ | mapping of any default |
-+| | | values for keyword-only |
-+| | | parameters |
-++-----------------+-------------------+---------------------------+
-+| | __globals__ | global namespace in which |
-+| | | this function was defined |
-++-----------------+-------------------+---------------------------+
-+| | __builtins__ | builtins namespace |
-++-----------------+-------------------+---------------------------+
-+| | __annotations__ | mapping of parameters |
-+| | | names to annotations; |
-+| | | ``"return"`` key is |
-+| | | reserved for return |
-+| | | annotations. |
-++-----------------+-------------------+---------------------------+
-+| | __type_params__ | A tuple containing the |
-+| | | :ref:`type parameters |
-+| | | ` of |
-+| | | a generic function |
-++-----------------+-------------------+---------------------------+
-+| | __module__ | name of module in which |
-+| | | this function was defined |
-++-----------------+-------------------+---------------------------+
-+| traceback | tb_frame | frame object at this |
-+| | | level |
-++-----------------+-------------------+---------------------------+
-+| | tb_lasti | index of last attempted |
-+| | | instruction in bytecode |
-++-----------------+-------------------+---------------------------+
-+| | tb_lineno | current line number in |
-+| | | Python source code |
-++-----------------+-------------------+---------------------------+
-+| | tb_next | next inner traceback |
-+| | | object (called by this |
-+| | | level) |
-++-----------------+-------------------+---------------------------+
-+| frame | f_back | next outer frame object |
-+| | | (this frame's caller) |
-++-----------------+-------------------+---------------------------+
-+| | f_builtins | builtins namespace seen |
-+| | | by this frame |
-++-----------------+-------------------+---------------------------+
-+| | f_code | code object being |
-+| | | executed in this frame |
-++-----------------+-------------------+---------------------------+
-+| | f_globals | global namespace seen by |
-+| | | this frame |
-++-----------------+-------------------+---------------------------+
-+| | f_lasti | index of last attempted |
-+| | | instruction in bytecode |
-++-----------------+-------------------+---------------------------+
-+| | f_lineno | current line number in |
-+| | | Python source code |
-++-----------------+-------------------+---------------------------+
-+| | f_locals | local namespace seen by |
-+| | | this frame |
-++-----------------+-------------------+---------------------------+
-+| | f_trace | tracing function for this |
-+| | | frame, or ``None`` |
-++-----------------+-------------------+---------------------------+
-+| code | co_argcount | number of arguments (not |
-+| | | including keyword only |
-+| | | arguments, \* or \*\* |
-+| | | args) |
-++-----------------+-------------------+---------------------------+
-+| | co_code | string of raw compiled |
-+| | | bytecode |
-++-----------------+-------------------+---------------------------+
-+| | co_cellvars | tuple of names of cell |
-+| | | variables (referenced by |
-+| | | containing scopes) |
-++-----------------+-------------------+---------------------------+
-+| | co_consts | tuple of constants used |
-+| | | in the bytecode |
-++-----------------+-------------------+---------------------------+
-+| | co_filename | name of file in which |
-+| | | this code object was |
-+| | | created |
-++-----------------+-------------------+---------------------------+
-+| | co_firstlineno | number of first line in |
-+| | | Python source code |
-++-----------------+-------------------+---------------------------+
-+| | co_flags | bitmap of ``CO_*`` flags, |
-+| | | read more :ref:`here |
-+| | | `|
-++-----------------+-------------------+---------------------------+
-+| | co_lnotab | encoded mapping of line |
-+| | | numbers to bytecode |
-+| | | indices |
-++-----------------+-------------------+---------------------------+
-+| | co_freevars | tuple of names of free |
-+| | | variables (referenced via |
-+| | | a function's closure) |
-++-----------------+-------------------+---------------------------+
-+| | co_posonlyargcount| number of positional only |
-+| | | arguments |
-++-----------------+-------------------+---------------------------+
-+| | co_kwonlyargcount | number of keyword only |
-+| | | arguments (not including |
-+| | | \*\* arg) |
-++-----------------+-------------------+---------------------------+
-+| | co_name | name with which this code |
-+| | | object was defined |
-++-----------------+-------------------+---------------------------+
-+| | co_qualname | fully qualified name with |
-+| | | which this code object |
-+| | | was defined |
-++-----------------+-------------------+---------------------------+
-+| | co_names | tuple of names other |
-+| | | than arguments and |
-+| | | function locals |
-++-----------------+-------------------+---------------------------+
-+| | co_nlocals | number of local variables |
-++-----------------+-------------------+---------------------------+
-+| | co_stacksize | virtual machine stack |
-+| | | space required |
-++-----------------+-------------------+---------------------------+
-+| | co_varnames | tuple of names of |
-+| | | arguments and local |
-+| | | variables |
-++-----------------+-------------------+---------------------------+
-+| generator | __name__ | name |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | gi_frame | frame |
-++-----------------+-------------------+---------------------------+
-+| | gi_running | is the generator running? |
-++-----------------+-------------------+---------------------------+
-+| | gi_code | code |
-++-----------------+-------------------+---------------------------+
-+| | gi_yieldfrom | object being iterated by |
-+| | | ``yield from``, or |
-+| | | ``None`` |
-++-----------------+-------------------+---------------------------+
-+| async generator | __name__ | name |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | ag_await | object being awaited on, |
-+| | | or ``None`` |
-++-----------------+-------------------+---------------------------+
-+| | ag_frame | frame |
-++-----------------+-------------------+---------------------------+
-+| | ag_running | is the generator running? |
-++-----------------+-------------------+---------------------------+
-+| | ag_code | code |
-++-----------------+-------------------+---------------------------+
-+| coroutine | __name__ | name |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | cr_await | object being awaited on, |
-+| | | or ``None`` |
-++-----------------+-------------------+---------------------------+
-+| | cr_frame | frame |
-++-----------------+-------------------+---------------------------+
-+| | cr_running | is the coroutine running? |
-++-----------------+-------------------+---------------------------+
-+| | cr_code | code |
-++-----------------+-------------------+---------------------------+
-+| | cr_origin | where coroutine was |
-+| | | created, or ``None``. See |
-+| | | |coroutine-origin-link| |
-++-----------------+-------------------+---------------------------+
-+| builtin | __doc__ | documentation string |
-++-----------------+-------------------+---------------------------+
-+| | __name__ | original name of this |
-+| | | function or method |
-++-----------------+-------------------+---------------------------+
-+| | __qualname__ | qualified name |
-++-----------------+-------------------+---------------------------+
-+| | __self__ | instance to which a |
-+| | | method is bound, or |
-+| | | ``None`` |
-++-----------------+-------------------+---------------------------+
-
- .. versionchanged:: 3.5
-
-@@ -437,7 +450,7 @@
-
- .. versionchanged:: 3.8
- Functions wrapped in :func:`functools.partial` now return ``True`` if the
-- wrapped function is a :term:`asynchronous generator` function.
-+ wrapped function is an :term:`asynchronous generator` function.
-
-
- .. function:: isasyncgen(object)
-@@ -896,7 +909,7 @@
-
- .. attribute:: Parameter.kind.description
-
-- Describes a enum value of :attr:`Parameter.kind`.
-+ Describes an enum value of :attr:`Parameter.kind`.
-
- .. versionadded:: 3.8
-
-@@ -1191,7 +1204,7 @@
- This function handles several details for you:
-
- * If ``eval_str`` is true, values of type ``str`` will
-- be un-stringized using :func:`eval()`. This is intended
-+ be un-stringized using :func:`eval`. This is intended
- for use with stringized annotations
- (``from __future__ import annotations``).
- * If ``obj`` doesn't have an annotations dict, returns an
-@@ -1205,16 +1218,16 @@
- * Always, always, always returns a freshly created dict.
-
- ``eval_str`` controls whether or not values of type ``str`` are replaced
-- with the result of calling :func:`eval()` on those values:
-+ with the result of calling :func:`eval` on those values:
-
-- * If eval_str is true, :func:`eval()` is called on values of type ``str``.
-- (Note that ``get_annotations`` doesn't catch exceptions; if :func:`eval()`
-+ * If eval_str is true, :func:`eval` is called on values of type ``str``.
-+ (Note that ``get_annotations`` doesn't catch exceptions; if :func:`eval`
- raises an exception, it will unwind the stack past the ``get_annotations``
- call.)
- * If eval_str is false (the default), values of type ``str`` are unchanged.
-
-- ``globals`` and ``locals`` are passed in to :func:`eval()`; see the documentation
-- for :func:`eval()` for more information. If ``globals`` or ``locals``
-+ ``globals`` and ``locals`` are passed in to :func:`eval`; see the documentation
-+ for :func:`eval` for more information. If ``globals`` or ``locals``
- is ``None``, this function may replace that value with a context-specific
- default, contingent on ``type(obj)``:
-
diff --git a/Doc/library/intro.rst b/Doc/library/intro.rst
index 5a4c9b8b16a..ffc8939d211 100644
--- a/Doc/library/intro.rst
@@ -6288,336 +224,8 @@ index 5a4c9b8b16a..ffc8939d211 100644
+
+ As a result, Python library that involve console manipulation (such as
+ :mod:`curses` and :mod:`readline`) are not available on iOS.
-diff --git a/Doc/library/io.rst b/Doc/library/io.rst
-index 748c49968f5..f793d7a7ef9 100644
---- a/Doc/library/io.rst
-+++ b/Doc/library/io.rst
-@@ -55,7 +55,7 @@
- encoding and decoding of data is made transparently as well as optional
- translation of platform-specific newline characters.
-
--The easiest way to create a text stream is with :meth:`open()`, optionally
-+The easiest way to create a text stream is with :meth:`open`, optionally
- specifying an encoding::
-
- f = open("myfile.txt", "r", encoding="utf-8")
-@@ -77,7 +77,7 @@
- category of streams can be used for all kinds of non-text data, and also when
- manual control over the handling of text data is desired.
-
--The easiest way to create a binary stream is with :meth:`open()` with ``'b'`` in
-+The easiest way to create a binary stream is with :meth:`open` with ``'b'`` in
- the mode string::
-
- f = open("myfile.jpg", "rb")
-@@ -950,7 +950,7 @@
- :class:`TextIOBase`.
-
- *encoding* gives the name of the encoding that the stream will be decoded or
-- encoded with. It defaults to :func:`locale.getencoding()`.
-+ encoded with. It defaults to :func:`locale.getencoding`.
- ``encoding="locale"`` can be used to specify the current locale's encoding
- explicitly. See :ref:`io-text-encoding` for more information.
-
-@@ -1182,7 +1182,7 @@
- is raised. Note this doesn't prohibit a different thread from entering the
- buffered object.
-
--The above implicitly extends to text files, since the :func:`open()` function
-+The above implicitly extends to text files, since the :func:`open` function
- will wrap a buffered object inside a :class:`TextIOWrapper`. This includes
--standard streams and therefore affects the built-in :func:`print()` function as
-+standard streams and therefore affects the built-in :func:`print` function as
- well.
-diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
-index d359451b397..d780969ca4d 100644
---- a/Doc/library/ipaddress.rst
-+++ b/Doc/library/ipaddress.rst
-@@ -983,7 +983,7 @@
- .. function:: collapse_addresses(addresses)
-
- Return an iterator of the collapsed :class:`IPv4Network` or
-- :class:`IPv6Network` objects. *addresses* is an iterator of
-+ :class:`IPv6Network` objects. *addresses* is an :term:`iterable` of
- :class:`IPv4Network` or :class:`IPv6Network` objects. A :exc:`TypeError` is
- raised if *addresses* contains mixed version objects.
-
-@@ -1003,7 +1003,7 @@
-
- doesn't make sense. There are some times however, where you may wish to
- have :mod:`ipaddress` sort these anyway. If you need to do this, you can use
-- this function as the *key* argument to :func:`sorted()`.
-+ this function as the *key* argument to :func:`sorted`.
-
- *obj* is either a network or address object.
-
-diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst
-index 21bb3f1f840..3fab46c3c0a 100644
---- a/Doc/library/itertools.rst
-+++ b/Doc/library/itertools.rst
-@@ -329,7 +329,7 @@
- yield n
- n += step
-
-- When counting with floating point numbers, better accuracy can sometimes be
-+ When counting with floating-point numbers, better accuracy can sometimes be
- achieved by substituting multiplicative code such as: ``(start + step * i
- for i in count())``.
-
-diff --git a/Doc/library/json.rst b/Doc/library/json.rst
-index a1aba65cecf..892972d297c 100644
---- a/Doc/library/json.rst
-+++ b/Doc/library/json.rst
-@@ -230,28 +230,28 @@
-
- *object_hook* is an optional function that will be called with the result of
- any object literal decoded (a :class:`dict`). The return value of
-- *object_hook* will be used instead of the :class:`dict`. This feature can be used
-- to implement custom decoders (e.g. `JSON-RPC `_
-- class hinting).
-+ *object_hook* will be used instead of the :class:`dict`. This feature can
-+ be used to implement custom decoders (e.g. `JSON-RPC
-+ `_ class hinting).
-
- *object_pairs_hook* is an optional function that will be called with the
- result of any object literal decoded with an ordered list of pairs. The
- return value of *object_pairs_hook* will be used instead of the
-- :class:`dict`. This feature can be used to implement custom decoders.
-- If *object_hook* is also defined, the *object_pairs_hook* takes priority.
-+ :class:`dict`. This feature can be used to implement custom decoders. If
-+ *object_hook* is also defined, the *object_pairs_hook* takes priority.
-
- .. versionchanged:: 3.1
- Added support for *object_pairs_hook*.
-
-- *parse_float*, if specified, will be called with the string of every JSON
-- float to be decoded. By default, this is equivalent to ``float(num_str)``.
-- This can be used to use another datatype or parser for JSON floats
-- (e.g. :class:`decimal.Decimal`).
-+ *parse_float* is an optional function that will be called with the string of
-+ every JSON float to be decoded. By default, this is equivalent to
-+ ``float(num_str)``. This can be used to use another datatype or parser for
-+ JSON floats (e.g. :class:`decimal.Decimal`).
-
-- *parse_int*, if specified, will be called with the string of every JSON int
-- to be decoded. By default, this is equivalent to ``int(num_str)``. This can
-- be used to use another datatype or parser for JSON integers
-- (e.g. :class:`float`).
-+ *parse_int* is an optional function that will be called with the string of
-+ every JSON int to be decoded. By default, this is equivalent to
-+ ``int(num_str)``. This can be used to use another datatype or parser for
-+ JSON integers (e.g. :class:`float`).
-
- .. versionchanged:: 3.11
- The default *parse_int* of :func:`int` now limits the maximum length of
-@@ -259,10 +259,9 @@
- conversion length limitation ` to help avoid denial
- of service attacks.
-
-- *parse_constant*, if specified, will be called with one of the following
-- strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.
-- This can be used to raise an exception if invalid JSON numbers
-- are encountered.
-+ *parse_constant* is an optional function that will be called with one of the
-+ following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be
-+ used to raise an exception if invalid JSON numbers are encountered.
-
- .. versionchanged:: 3.1
- *parse_constant* doesn't get called on 'null', 'true', 'false' anymore.
-@@ -334,34 +333,33 @@
- It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as their
- corresponding ``float`` values, which is outside the JSON spec.
-
-- *object_hook*, if specified, will be called with the result of every JSON
-- object decoded and its return value will be used in place of the given
-- :class:`dict`. This can be used to provide custom deserializations (e.g. to
-- support `JSON-RPC `_ class hinting).
-+ *object_hook* is an optional function that will be called with the result of
-+ every JSON object decoded and its return value will be used in place of the
-+ given :class:`dict`. This can be used to provide custom deserializations
-+ (e.g. to support `JSON-RPC `_ class hinting).
-
-- *object_pairs_hook*, if specified will be called with the result of every
-- JSON object decoded with an ordered list of pairs. The return value of
-- *object_pairs_hook* will be used instead of the :class:`dict`. This
-- feature can be used to implement custom decoders. If *object_hook* is also
-- defined, the *object_pairs_hook* takes priority.
-+ *object_pairs_hook* is an optional function that will be called with the
-+ result of every JSON object decoded with an ordered list of pairs. The
-+ return value of *object_pairs_hook* will be used instead of the
-+ :class:`dict`. This feature can be used to implement custom decoders. If
-+ *object_hook* is also defined, the *object_pairs_hook* takes priority.
-
- .. versionchanged:: 3.1
- Added support for *object_pairs_hook*.
-
-- *parse_float*, if specified, will be called with the string of every JSON
-- float to be decoded. By default, this is equivalent to ``float(num_str)``.
-- This can be used to use another datatype or parser for JSON floats
-- (e.g. :class:`decimal.Decimal`).
-+ *parse_float* is an optional function that will be called with the string of
-+ every JSON float to be decoded. By default, this is equivalent to
-+ ``float(num_str)``. This can be used to use another datatype or parser for
-+ JSON floats (e.g. :class:`decimal.Decimal`).
-
-- *parse_int*, if specified, will be called with the string of every JSON int
-- to be decoded. By default, this is equivalent to ``int(num_str)``. This can
-- be used to use another datatype or parser for JSON integers
-- (e.g. :class:`float`).
-+ *parse_int* is an optional function that will be called with the string of
-+ every JSON int to be decoded. By default, this is equivalent to
-+ ``int(num_str)``. This can be used to use another datatype or parser for
-+ JSON integers (e.g. :class:`float`).
-
-- *parse_constant*, if specified, will be called with one of the following
-- strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``.
-- This can be used to raise an exception if invalid JSON numbers
-- are encountered.
-+ *parse_constant* is an optional function that will be called with one of the
-+ following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This can be
-+ used to raise an exception if invalid JSON numbers are encountered.
-
- If *strict* is false (``True`` is the default), then control characters
- will be allowed inside strings. Control characters in this context are
-diff --git a/Doc/library/locale.rst b/Doc/library/locale.rst
-index 10c376397cf..60975bf9177 100644
---- a/Doc/library/locale.rst
-+++ b/Doc/library/locale.rst
-@@ -434,7 +434,7 @@
- .. function:: format_string(format, val, grouping=False, monetary=False)
-
- Formats a number *val* according to the current :const:`LC_NUMERIC` setting.
-- The format follows the conventions of the ``%`` operator. For floating point
-+ The format follows the conventions of the ``%`` operator. For floating-point
- values, the decimal point is modified if appropriate. If *grouping* is ``True``,
- also takes the grouping into account.
-
-@@ -465,7 +465,7 @@
-
- .. function:: str(float)
-
-- Formats a floating point number using the same format as the built-in function
-+ Formats a floating-point number using the same format as the built-in function
- ``str(float)``, but takes the decimal point into account.
-
-
-diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst
-index 23aac191f05..50ffff60250 100644
---- a/Doc/library/logging.config.rst
-+++ b/Doc/library/logging.config.rst
-@@ -69,7 +69,7 @@
- dictConfigClass(config).configure()
-
- For example, a subclass of :class:`DictConfigurator` could call
-- ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then
-+ ``DictConfigurator.__init__()`` in its own :meth:`__init__`, then
- set up custom prefixes which would be usable in the subsequent
- :meth:`configure` call. :attr:`dictConfigClass` would be bound to
- this new subclass, and then :func:`dictConfig` could be called exactly as
-@@ -752,9 +752,12 @@
-
- If the ``queue`` key is present, the corresponding value can be one of the following:
-
--* An actual instance of :class:`queue.Queue` or a subclass thereof. This is of course
-- only possible if you are constructing or modifying the configuration dictionary in
-- code.
-+* An object implementing the :class:`queue.Queue` public API. For instance,
-+ this may be an actual instance of :class:`queue.Queue` or a subclass thereof,
-+ or a proxy obtained by :meth:`multiprocessing.managers.SyncManager.Queue`.
-+
-+ This is of course only possible if you are constructing or modifying
-+ the configuration dictionary in code.
-
- * A string that resolves to a callable which, when called with no arguments, returns
- the :class:`queue.Queue` instance to use. That callable could be a
-diff --git a/Doc/library/mailbox.rst b/Doc/library/mailbox.rst
-index 1e4e728395b..6eb8dec44eb 100644
---- a/Doc/library/mailbox.rst
-+++ b/Doc/library/mailbox.rst
-@@ -1278,7 +1278,7 @@
-
- .. method:: get_visible()
-
-- Return an :class:`Message` instance whose headers are the message's
-+ Return a :class:`Message` instance whose headers are the message's
- visible headers and whose body is empty.
-
-
-diff --git a/Doc/library/marshal.rst b/Doc/library/marshal.rst
-index ce549b73fe5..a85d9206810 100644
---- a/Doc/library/marshal.rst
-+++ b/Doc/library/marshal.rst
-@@ -38,8 +38,8 @@
-
- Not all Python object types are supported; in general, only objects whose value
- is independent from a particular invocation of Python can be written and read by
--this module. The following types are supported: booleans, integers, floating
--point numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets,
-+this module. The following types are supported: booleans, integers, floating-point
-+numbers, complex numbers, strings, bytes, bytearrays, tuples, lists, sets,
- frozensets, dictionaries, and code objects, where it should be understood that
- tuples, lists, sets, frozensets and dictionaries are only supported as long as
- the values contained therein are themselves supported. The
-@@ -121,7 +121,7 @@
-
- Indicates the format that the module uses. Version 0 is the historical
- format, version 1 shares interned strings and version 2 uses a binary format
-- for floating point numbers.
-+ for floating-point numbers.
- Version 3 adds support for object instancing and recursion.
- The current version is 4.
-
-diff --git a/Doc/library/math.rst b/Doc/library/math.rst
-index b6a7d98a295..40742fdafea 100644
---- a/Doc/library/math.rst
-+++ b/Doc/library/math.rst
-@@ -107,7 +107,7 @@
-
- .. function:: fsum(iterable)
-
-- Return an accurate floating point sum of values in the iterable. Avoids
-+ Return an accurate floating-point sum of values in the iterable. Avoids
- loss of precision by tracking multiple intermediate partial sums.
-
- The algorithm's accuracy depends on IEEE-754 arithmetic guarantees and the
-@@ -117,7 +117,7 @@
- least significant bit.
-
- For further discussion and two alternative approaches, see the `ASPN cookbook
-- recipes for accurate floating point summation
-+ recipes for accurate floating-point summation
- `_\.
-
-
-@@ -288,7 +288,7 @@
- If the result of the remainder operation is zero, that zero will have
- the same sign as *x*.
-
-- On platforms using IEEE 754 binary floating-point, the result of this
-+ On platforms using IEEE 754 binary floating point, the result of this
- operation is always exactly representable: no rounding error is introduced.
-
- .. versionadded:: 3.7
-diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst
-index 930b4793189..1522285b4ef 100644
---- a/Doc/library/mimetypes.rst
-+++ b/Doc/library/mimetypes.rst
-@@ -272,3 +272,13 @@
- types, else to the list of non-standard types.
-
- .. versionadded:: 3.2
-+
-+
-+ .. method:: MimeTypes.add_type(type, ext, strict=True)
-+
-+ Add a mapping from the MIME type *type* to the extension *ext*. When the
-+ extension is already known, the new type will replace the old one. When the type
-+ is already known the extension will be added to the list of known extensions.
-+
-+ When *strict* is ``True`` (the default), the mapping will be added to the
-+ official MIME types, otherwise to the non-standard ones.
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
-index d6474ef975b..cd9ace02f6d 100644
+index f2a9ada85e2..cd9ace02f6d 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -8,7 +8,7 @@
@@ -6629,218 +237,8 @@ index d6474ef975b..cd9ace02f6d 100644
Introduction
------------
-@@ -254,6 +254,7 @@
- p.join()
-
- Queues are thread and process safe.
-+ Any object put into a :mod:`~multiprocessing` queue will be serialized.
-
- **Pipes**
-
-@@ -281,6 +282,8 @@
- of corruption from processes using different ends of the pipe at the same
- time.
-
-+ The :meth:`~Connection.send` method serializes the the object and
-+ :meth:`~Connection.recv` re-creates the object.
-
- Synchronization between processes
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-@@ -502,7 +505,7 @@
- The constructor should always be called with keyword arguments. *group*
- should always be ``None``; it exists solely for compatibility with
- :class:`threading.Thread`. *target* is the callable object to be invoked by
-- the :meth:`run()` method. It defaults to ``None``, meaning nothing is
-+ the :meth:`run` method. It defaults to ``None``, meaning nothing is
- called. *name* is the process name (see :attr:`name` for more details).
- *args* is the argument tuple for the target invocation. *kwargs* is a
- dictionary of keyword arguments for the target invocation. If provided,
-@@ -639,7 +642,7 @@
-
- You can use this value if you want to wait on several events at
- once using :func:`multiprocessing.connection.wait`. Otherwise
-- calling :meth:`join()` is simpler.
-+ calling :meth:`join` is simpler.
-
- On Windows, this is an OS handle usable with the ``WaitForSingleObject``
- and ``WaitForMultipleObjects`` family of API calls. On POSIX, this is
-@@ -666,7 +669,7 @@
-
- .. method:: kill()
-
-- Same as :meth:`terminate()` but using the ``SIGKILL`` signal on POSIX.
-+ Same as :meth:`terminate` but using the ``SIGKILL`` signal on POSIX.
-
- .. versionadded:: 3.7
-
-@@ -709,7 +712,7 @@
-
- .. exception:: BufferTooShort
-
-- Exception raised by :meth:`Connection.recv_bytes_into()` when the supplied
-+ Exception raised by :meth:`Connection.recv_bytes_into` when the supplied
- buffer object is too small for the message read.
-
- If ``e`` is an instance of :exc:`BufferTooShort` then ``e.args[0]`` will give
-@@ -745,6 +748,11 @@
- semaphore used to count the number of unfinished tasks may eventually overflow,
- raising an exception.
-
-+One difference from other Python queue implementations, is that :mod:`multiprocessing`
-+queues serializes all objects that are put into them using :mod:`pickle`.
-+The object return by the get method is a re-created object that does not share memory
-+with the original object.
-+
- Note that one can also create a shared queue by using a manager object -- see
- :ref:`multiprocessing-managers`.
-
-@@ -811,6 +819,8 @@
- used for receiving messages and ``conn2`` can only be used for sending
- messages.
-
-+ The :meth:`~multiprocessing.Connection.send` method serializes the the object using
-+ :mod:`pickle` and the :meth:`~multiprocessing.Connection.recv` re-creates the object.
-
- .. class:: Queue([maxsize])
-
-@@ -837,6 +847,8 @@
- Return ``True`` if the queue is empty, ``False`` otherwise. Because of
- multithreading/multiprocessing semantics, this is not reliable.
-
-+ May raise an :exc:`OSError` on closed queues. (not guaranteed)
-+
- .. method:: full()
-
- Return ``True`` if the queue is full, ``False`` otherwise. Because of
-@@ -940,6 +952,8 @@
-
- Return ``True`` if the queue is empty, ``False`` otherwise.
-
-+ Always raises an :exc:`OSError` if the SimpleQueue is closed.
-+
- .. method:: get()
-
- Remove and return an item from the queue.
-@@ -1452,17 +1466,6 @@
- On macOS, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with
- a timeout will emulate that function's behavior using a sleeping loop.
-
--.. note::
--
-- If the SIGINT signal generated by :kbd:`Ctrl-C` arrives while the main thread is
-- blocked by a call to :meth:`BoundedSemaphore.acquire`, :meth:`Lock.acquire`,
-- :meth:`RLock.acquire`, :meth:`Semaphore.acquire`, :meth:`Condition.acquire`
-- or :meth:`Condition.wait` then the call will be immediately interrupted and
-- :exc:`KeyboardInterrupt` will be raised.
--
-- This differs from the behaviour of :mod:`threading` where SIGINT will be
-- ignored while the equivalent blocking calls are in progress.
--
- .. note::
-
- Some of this package's functionality requires a functioning shared semaphore
-@@ -2948,7 +2951,7 @@
- resulting in a bad file descriptor error, but introduces a potential danger
- to applications which replace :func:`sys.stdin` with a "file-like object"
- with output buffering. This danger is that if multiple processes call
-- :meth:`~io.IOBase.close()` on this file-like object, it could result in the same
-+ :meth:`~io.IOBase.close` on this file-like object, it could result in the same
- data being flushed to the object multiple times, resulting in corruption.
-
- If you write a file-like object and implement your own caching, you can
-diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst
-index 143e4e0c427..fde0bfc9f38 100644
---- a/Doc/library/nntplib.rst
-+++ b/Doc/library/nntplib.rst
-@@ -484,14 +484,14 @@
-
- .. method:: NNTP.head(message_spec=None, *, file=None)
-
-- Same as :meth:`article()`, but sends a ``HEAD`` command. The *lines*
-+ Same as :meth:`article`, but sends a ``HEAD`` command. The *lines*
- returned (or written to *file*) will only contain the message headers, not
- the body.
-
-
- .. method:: NNTP.body(message_spec=None, *, file=None)
-
-- Same as :meth:`article()`, but sends a ``BODY`` command. The *lines*
-+ Same as :meth:`article`, but sends a ``BODY`` command. The *lines*
- returned (or written to *file*) will only contain the message body, not the
- headers.
-
-@@ -513,7 +513,7 @@
-
- Send an ``IHAVE`` command. *message_id* is the id of the message to send
- to the server (enclosed in ``'<'`` and ``'>'``). The *data* parameter
-- and the return value are the same as for :meth:`post()`.
-+ and the return value are the same as for :meth:`post`.
-
-
- .. method:: NNTP.date()
-@@ -560,7 +560,7 @@
-
- Send an ``XOVER`` command. *start* and *end* are article numbers
- delimiting the range of articles to select. The return value is the
-- same of for :meth:`over()`. It is recommended to use :meth:`over()`
-+ same of for :meth:`over`. It is recommended to use :meth:`over`
- instead, since it will automatically use the newer ``OVER`` command
- if available.
-
-diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst
-index fc652d23f4f..15b5d5c3466 100644
---- a/Doc/library/optparse.rst
-+++ b/Doc/library/optparse.rst
-@@ -1351,7 +1351,7 @@
- the list of arguments to process (default: ``sys.argv[1:]``)
-
- ``values``
-- an :class:`Values` object to store option arguments in (default: a
-+ a :class:`Values` object to store option arguments in (default: a
- new instance of :class:`Values`) -- if you give an existing object, the
- option defaults will not be initialized on it
-
-diff --git a/Doc/library/os.path.rst b/Doc/library/os.path.rst
-index c5004c3f0df..51e89087e7f 100644
---- a/Doc/library/os.path.rst
-+++ b/Doc/library/os.path.rst
-@@ -81,7 +81,7 @@
-
- Return the longest common sub-path of each pathname in the sequence
- *paths*. Raise :exc:`ValueError` if *paths* contain both absolute
-- and relative pathnames, the *paths* are on the different drives or
-+ and relative pathnames, if *paths* are on different drives, or
- if *paths* is empty. Unlike :func:`commonprefix`, this returns a
- valid path.
-
-@@ -198,14 +198,14 @@
-
- .. function:: getatime(path)
-
-- Return the time of last access of *path*. The return value is a floating point number giving
-+ Return the time of last access of *path*. The return value is a floating-point number giving
- the number of seconds since the epoch (see the :mod:`time` module). Raise
- :exc:`OSError` if the file does not exist or is inaccessible.
-
-
- .. function:: getmtime(path)
-
-- Return the time of last modification of *path*. The return value is a floating point number
-+ Return the time of last modification of *path*. The return value is a floating-point number
- giving the number of seconds since the epoch (see the :mod:`time` module).
- Raise :exc:`OSError` if the file does not exist or is inaccessible.
-
-@@ -359,7 +359,7 @@
- that contains symbolic links. On Windows, it converts forward slashes to
- backward slashes. To normalize case, use :func:`normcase`.
-
-- .. note::
-+ .. note::
- On POSIX systems, in accordance with `IEEE Std 1003.1 2013 Edition; 4.13
- Pathname Resolution `_,
- if a pathname begins with exactly two slashes, the first component
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
-index a793d244de9..6beafbd9d00 100644
+index 3a5deaa1d69..6beafbd9d00 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -34,12 +34,13 @@
@@ -6863,28 +261,6 @@ index a793d244de9..6beafbd9d00 100644
.. note::
-@@ -113,8 +114,8 @@
-
- * Use UTF-8 as the :term:`filesystem encoding `.
--* :func:`sys.getfilesystemencoding()` returns ``'utf-8'``.
--* :func:`locale.getpreferredencoding()` returns ``'utf-8'`` (the *do_setlocale*
-+* :func:`sys.getfilesystemencoding` returns ``'utf-8'``.
-+* :func:`locale.getpreferredencoding` returns ``'utf-8'`` (the *do_setlocale*
- argument has no effect).
- * :data:`sys.stdin`, :data:`sys.stdout`, and :data:`sys.stderr` all use
- UTF-8 as their text encoding, with the ``surrogateescape``
-@@ -133,8 +134,8 @@
-
- * Command line arguments, environment variables and filenames are decoded
- to text using the UTF-8 encoding.
--* :func:`os.fsdecode()` and :func:`os.fsencode()` use the UTF-8 encoding.
--* :func:`open()`, :func:`io.open()`, and :func:`codecs.open()` use the UTF-8
-+* :func:`os.fsdecode` and :func:`os.fsencode` use the UTF-8 encoding.
-+* :func:`open`, :func:`io.open`, and :func:`codecs.open` use the UTF-8
- encoding by default. However, they still use the strict error handler by
- default so that attempting to open a binary file in text mode is likely
- to raise an exception rather than producing nonsense data.
@@ -784,6 +785,11 @@
:func:`socket.gethostname` or even
``socket.gethostbyaddr(socket.gethostname())``.
@@ -6897,42 +273,6 @@ index a793d244de9..6beafbd9d00 100644
.. availability:: Unix.
.. versionchanged:: 3.3
-@@ -1497,7 +1503,7 @@
-
- .. function:: pwritev(fd, buffers, offset, flags=0, /)
-
-- Write the *buffers* contents to file descriptor *fd* at a offset *offset*,
-+ Write the *buffers* contents to file descriptor *fd* at an offset *offset*,
- leaving the file offset unchanged. *buffers* must be a sequence of
- :term:`bytes-like objects `. Buffers are processed in
- array order. Entire contents of the first buffer is written before
-@@ -2756,7 +2762,7 @@
-
- .. versionchanged:: 3.6
- Added support for the :term:`context manager` protocol and the
-- :func:`~scandir.close()` method. If a :func:`scandir` iterator is neither
-+ :func:`~scandir.close` method. If a :func:`scandir` iterator is neither
- exhausted nor explicitly closed a :exc:`ResourceWarning` will be emitted
- in its destructor.
-
-@@ -3701,7 +3707,7 @@
- new file descriptor is :ref:`non-inheritable `.
-
- *initval* is the initial value of the event counter. The initial value
-- must be an 32 bit unsigned integer. Please note that the initial value is
-+ must be a 32 bit unsigned integer. Please note that the initial value is
- limited to a 32 bit unsigned int although the event counter is an unsigned
- 64 bit integer with a maximum value of 2\ :sup:`64`\ -\ 2.
-
-@@ -3780,7 +3786,7 @@
-
- .. data:: EFD_SEMAPHORE
-
-- Provide semaphore-like semantics for reads from a :func:`eventfd` file
-+ Provide semaphore-like semantics for reads from an :func:`eventfd` file
- descriptor. On read the internal counter is decremented by one.
-
- .. availability:: Linux >= 2.6.30
@@ -3997,7 +4003,7 @@
.. audit-event:: os.exec path,args,env os.execl
@@ -7241,1276 +581,90 @@ index a793d244de9..6beafbd9d00 100644
Interface to the scheduler
-diff --git a/Doc/library/pathlib.rst b/Doc/library/pathlib.rst
-index d4b0e072084..c5cf406372d 100644
---- a/Doc/library/pathlib.rst
-+++ b/Doc/library/pathlib.rst
-@@ -21,6 +21,12 @@
- .. image:: pathlib-inheritance.png
- :align: center
- :class: invert-in-dark-mode
-+ :alt: Inheritance diagram showing the classes available in pathlib. The
-+ most basic class is PurePath, which has three direct subclasses:
-+ PurePosixPath, PureWindowsPath, and Path. Further to these four
-+ classes, there are two classes that use multiple inheritance:
-+ PosixPath subclasses PurePosixPath and Path, and WindowsPath
-+ subclasses PureWindowsPath and Path.
-
- If you've never used this module before or just aren't sure which class is
- right for your task, :class:`Path` is most likely what you need. It instantiates
-@@ -161,8 +167,8 @@
- A subclass of :class:`PurePath`, this path flavour represents non-Windows
- filesystem paths::
-
-- >>> PurePosixPath('/etc')
-- PurePosixPath('/etc')
-+ >>> PurePosixPath('/etc/hosts')
-+ PurePosixPath('/etc/hosts')
-
- *pathsegments* is specified similarly to :class:`PurePath`.
-
-@@ -171,8 +177,8 @@
- A subclass of :class:`PurePath`, this path flavour represents Windows
- filesystem paths, including `UNC paths`_::
+diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst
+index 2f5bf53bc5c..0cc5e532711 100644
+--- a/Doc/library/platform.rst
++++ b/Doc/library/platform.rst
+@@ -148,6 +148,9 @@
+ Returns the system/OS name, such as ``'Linux'``, ``'Darwin'``, ``'Java'``,
+ ``'Windows'``. An empty string is returned if the value cannot be determined.
-- >>> PureWindowsPath('c:/Program Files/')
-- PureWindowsPath('c:/Program Files')
-+ >>> PureWindowsPath('c:/', 'Users', 'Ximénez')
-+ PureWindowsPath('c:/Users/Ximénez')
- >>> PureWindowsPath('//server/share/file')
- PureWindowsPath('//server/share/file')
++ On iOS and Android, this returns the user-facing OS name (i.e, ``'iOS``,
++ ``'iPadOS'`` or ``'Android'``). To obtain the kernel name (``'Darwin'`` or
++ ``'Linux'``), use :func:`os.uname()`.
-@@ -756,8 +762,8 @@
- A subclass of :class:`Path` and :class:`PurePosixPath`, this class
- represents concrete non-Windows filesystem paths::
+ .. function:: system_alias(system, release, version)
-- >>> PosixPath('/etc')
-- PosixPath('/etc')
-+ >>> PosixPath('/etc/hosts')
-+ PosixPath('/etc/hosts')
+@@ -161,6 +164,8 @@
+ Returns the system's release version, e.g. ``'#3 on degas'``. An empty string is
+ returned if the value cannot be determined.
- *pathsegments* is specified similarly to :class:`PurePath`.
++ On iOS and Android, this is the user-facing OS version. To obtain the
++ Darwin or Linux kernel version, use :func:`os.uname()`.
-@@ -766,8 +772,8 @@
- A subclass of :class:`Path` and :class:`PureWindowsPath`, this class
- represents concrete Windows filesystem paths::
+ .. function:: uname()
-- >>> WindowsPath('c:/Program Files/')
-- WindowsPath('c:/Program Files')
-+ >>> WindowsPath('c:/', 'Users', 'Ximénez')
-+ WindowsPath('c:/Users/Ximénez')
+@@ -234,7 +239,6 @@
+ macOS Platform
+ --------------
- *pathsegments* is specified similarly to :class:`PurePath`.
+-
+ .. function:: mac_ver(release='', versioninfo=('','',''), machine='')
-@@ -789,23 +795,119 @@
- % (cls.__name__,))
- NotImplementedError: cannot instantiate 'WindowsPath' on your system
+ Get macOS version information and return it as tuple ``(release, versioninfo,
+@@ -244,6 +248,24 @@
+ Entries which cannot be determined are set to ``''``. All tuple entries are
+ strings.
-+Some concrete path methods can raise an :exc:`OSError` if a system call fails
-+(for example because the path doesn't exist).
-+
-+
-+Expanding and resolving paths
-+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+
-+.. classmethod:: Path.home()
++iOS Platform
++------------
+
-+ Return a new path object representing the user's home directory (as
-+ returned by :func:`os.path.expanduser` with ``~`` construct). If the home
-+ directory can't be resolved, :exc:`RuntimeError` is raised.
++.. function:: ios_ver(system='', release='', model='', is_simulator=False)
+
-+ ::
++ Get iOS version information and return it as a
++ :func:`~collections.namedtuple` with the following attributes:
+
-+ >>> Path.home()
-+ PosixPath('/home/antoine')
++ * ``system`` is the OS name; either ``'iOS'`` or ``'iPadOS'``.
++ * ``release`` is the iOS version number as a string (e.g., ``'17.2'``).
++ * ``model`` is the device model identifier; this will be a string like
++ ``'iPhone13,2'`` for a physical device, or ``'iPhone'`` on a simulator.
++ * ``is_simulator`` is a boolean describing if the app is running on a
++ simulator or a physical device.
+
-+ .. versionadded:: 3.5
++ Entries which cannot be determined are set to the defaults given as
++ parameters.
+
-+
-+.. method:: Path.expanduser()
-+
-+ Return a new path with expanded ``~`` and ``~user`` constructs,
-+ as returned by :meth:`os.path.expanduser`. If a home directory can't be
-+ resolved, :exc:`RuntimeError` is raised.
-+
-+ ::
-+
-+ >>> p = PosixPath('~/films/Monty Python')
-+ >>> p.expanduser()
-+ PosixPath('/home/eric/films/Monty Python')
-+
-+ .. versionadded:: 3.5
-+
-+
-+.. classmethod:: Path.cwd()
-+
-+ Return a new path object representing the current directory (as returned
-+ by :func:`os.getcwd`)::
-+
-+ >>> Path.cwd()
-+ PosixPath('/home/antoine/pathlib')
-+
-+
-+.. method:: Path.absolute()
-+
-+ Make the path absolute, without normalization or resolving symlinks.
-+ Returns a new path object::
-+
-+ >>> p = Path('tests')
-+ >>> p
-+ PosixPath('tests')
-+ >>> p.absolute()
-+ PosixPath('/home/antoine/pathlib/tests')
-+
-+
-+.. method:: Path.resolve(strict=False)
-+
-+ Make the path absolute, resolving any symlinks. A new path object is
-+ returned::
-+
-+ >>> p = Path()
-+ >>> p
-+ PosixPath('.')
-+ >>> p.resolve()
-+ PosixPath('/home/antoine/pathlib')
-+
-+ "``..``" components are also eliminated (this is the only method to do so)::
-+
-+ >>> p = Path('docs/../setup.py')
-+ >>> p.resolve()
-+ PosixPath('/home/antoine/pathlib/setup.py')
-+
-+ If the path doesn't exist and *strict* is ``True``, :exc:`FileNotFoundError`
-+ is raised. If *strict* is ``False``, the path is resolved as far as possible
-+ and any remainder is appended without checking whether it exists. If an
-+ infinite loop is encountered along the resolution path, :exc:`RuntimeError`
-+ is raised.
-+
-+ .. versionchanged:: 3.6
-+ The *strict* parameter was added (pre-3.6 behavior is strict).
-+
-+
-+.. method:: Path.readlink()
-+
-+ Return the path to which the symbolic link points (as returned by
-+ :func:`os.readlink`)::
-+
-+ >>> p = Path('mylink')
-+ >>> p.symlink_to('setup.py')
-+ >>> p.readlink()
-+ PosixPath('setup.py')
-+
-+ .. versionadded:: 3.9
-+
-
- Querying file type and status
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- .. versionchanged:: 3.8
-
-- :meth:`~Path.exists()`, :meth:`~Path.is_dir()`, :meth:`~Path.is_file()`,
-- :meth:`~Path.is_mount()`, :meth:`~Path.is_symlink()`,
-- :meth:`~Path.is_block_device()`, :meth:`~Path.is_char_device()`,
-- :meth:`~Path.is_fifo()`, :meth:`~Path.is_socket()` now return ``False``
-+ :meth:`~Path.exists`, :meth:`~Path.is_dir`, :meth:`~Path.is_file`,
-+ :meth:`~Path.is_mount`, :meth:`~Path.is_symlink`,
-+ :meth:`~Path.is_block_device`, :meth:`~Path.is_char_device`,
-+ :meth:`~Path.is_fifo`, :meth:`~Path.is_socket` now return ``False``
- instead of raising an exception for paths that contain characters
- unrepresentable at the OS level.
-
-
- .. method:: Path.stat(*, follow_symlinks=True)
-
-- Return a :class:`os.stat_result` object containing information about this path, like :func:`os.stat`.
-+ Return an :class:`os.stat_result` object containing information about this path, like :func:`os.stat`.
- The result is looked up at each call to this method.
-
- This method normally follows symlinks; to stat a symlink add the argument
-@@ -1040,71 +1142,32 @@
- .. versionadded:: 3.5
-
-
--Other methods
--^^^^^^^^^^^^^
--
--Many of these methods can raise an :exc:`OSError` if a system call fails (for
--example because the path doesn't exist).
--
--
--.. classmethod:: Path.cwd()
--
-- Return a new path object representing the current directory (as returned
-- by :func:`os.getcwd`)::
--
-- >>> Path.cwd()
-- PosixPath('/home/antoine/pathlib')
--
--
--.. classmethod:: Path.home()
--
-- Return a new path object representing the user's home directory (as
-- returned by :func:`os.path.expanduser` with ``~`` construct). If the home
-- directory can't be resolved, :exc:`RuntimeError` is raised.
--
-- ::
--
-- >>> Path.home()
-- PosixPath('/home/antoine')
--
-- .. versionadded:: 3.5
--
--
--.. method:: Path.chmod(mode, *, follow_symlinks=True)
--
-- Change the file mode and permissions, like :func:`os.chmod`.
--
-- This method normally follows symlinks. Some Unix flavours support changing
-- permissions on the symlink itself; on these platforms you may add the
-- argument ``follow_symlinks=False``, or use :meth:`~Path.lchmod`.
--
-- ::
--
-- >>> p = Path('setup.py')
-- >>> p.stat().st_mode
-- 33277
-- >>> p.chmod(0o444)
-- >>> p.stat().st_mode
-- 33060
--
-- .. versionchanged:: 3.10
-- The *follow_symlinks* parameter was added.
--
--
--.. method:: Path.expanduser()
-+Reading directories
-+^^^^^^^^^^^^^^^^^^^
-
-- Return a new path with expanded ``~`` and ``~user`` constructs,
-- as returned by :meth:`os.path.expanduser`. If a home directory can't be
-- resolved, :exc:`RuntimeError` is raised.
-+.. method:: Path.iterdir()
-
-- ::
-+ When the path points to a directory, yield path objects of the directory
-+ contents::
-
-- >>> p = PosixPath('~/films/Monty Python')
-- >>> p.expanduser()
-- PosixPath('/home/eric/films/Monty Python')
-+ >>> p = Path('docs')
-+ >>> for child in p.iterdir(): child
-+ ...
-+ PosixPath('docs/conf.py')
-+ PosixPath('docs/_templates')
-+ PosixPath('docs/make.bat')
-+ PosixPath('docs/index.rst')
-+ PosixPath('docs/_build')
-+ PosixPath('docs/_static')
-+ PosixPath('docs/Makefile')
-
-- .. versionadded:: 3.5
-+ 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, it is unspecified whether
-+ a path object for that file is included.
-
-+ If the path is not a directory or otherwise inaccessible, :exc:`OSError` is
-+ raised.
-
- .. method:: Path.glob(pattern, *, case_sensitive=None)
-
-@@ -1150,32 +1213,33 @@
- The *case_sensitive* parameter was added.
-
-
--.. method:: Path.group()
-+.. method:: Path.rglob(pattern, *, case_sensitive=None)
-
-- Return the name of the group owning the file. :exc:`KeyError` is raised
-- if the file's gid isn't found in the system database.
-+ Glob the given relative *pattern* recursively. This is like calling
-+ :func:`Path.glob` with "``**/``" added in front of the *pattern*, where
-+ *patterns* are the same as for :mod:`fnmatch`::
-
-+ >>> sorted(Path().rglob("*.py"))
-+ [PosixPath('build/lib/pathlib.py'),
-+ PosixPath('docs/conf.py'),
-+ PosixPath('pathlib.py'),
-+ PosixPath('setup.py'),
-+ PosixPath('test_pathlib.py')]
-
--.. method:: Path.iterdir()
-+ By default, or when the *case_sensitive* keyword-only argument is set to
-+ ``None``, this method matches paths using platform-specific casing rules:
-+ typically, case-sensitive on POSIX, and case-insensitive on Windows.
-+ Set *case_sensitive* to ``True`` or ``False`` to override this behaviour.
-
-- When the path points to a directory, yield path objects of the directory
-- contents::
-+ .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob
-
-- >>> p = Path('docs')
-- >>> for child in p.iterdir(): child
-- ...
-- PosixPath('docs/conf.py')
-- PosixPath('docs/_templates')
-- PosixPath('docs/make.bat')
-- PosixPath('docs/index.rst')
-- PosixPath('docs/_build')
-- PosixPath('docs/_static')
-- PosixPath('docs/Makefile')
-+ .. versionchanged:: 3.11
-+ Return only directories if *pattern* ends with a pathname components
-+ separator (:data:`~os.sep` or :data:`~os.altsep`).
-+
-+ .. versionchanged:: 3.12
-+ The *case_sensitive* parameter was added.
-
-- 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 a path object for
-- that file be included is unspecified.
-
- .. method:: Path.walk(top_down=True, on_error=None, follow_symlinks=False)
-
-@@ -1208,7 +1272,7 @@
- This can be used to prune the search, or to impose a specific order of visiting,
- or even to inform :meth:`Path.walk` about directories the caller creates or
- renames before it resumes :meth:`Path.walk` again. Modifying *dirnames* when
-- *top_down* is false has no effect on the behavior of :meth:`Path.walk()` since the
-+ *top_down* is false has no effect on the behavior of :meth:`Path.walk` since the
- directories in *dirnames* have already been generated by the time *dirnames*
- is yielded to the caller.
-
-@@ -1272,16 +1336,27 @@
-
- .. versionadded:: 3.12
-
--.. method:: Path.lchmod(mode)
-
-- Like :meth:`Path.chmod` but, if the path points to a symbolic link, the
-- symbolic link's mode is changed rather than its target's.
-+Creating files and directories
-+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-+
-+.. method:: Path.touch(mode=0o666, exist_ok=True)
-+
-+ Create a file at this given path. If *mode* is given, it is combined
-+ with the process's ``umask`` value to determine the file mode and access
-+ flags. If the file already exists, the function succeeds when *exist_ok*
-+ is true (and its modification time is updated to the current time),
-+ otherwise :exc:`FileExistsError` is raised.
-+
-+ .. seealso::
-+ The :meth:`~Path.open`, :meth:`~Path.write_text` and
-+ :meth:`~Path.write_bytes` methods are often used to create files.
-
-
- .. method:: Path.mkdir(mode=0o777, parents=False, exist_ok=False)
-
- Create a new directory at this given path. If *mode* is given, it is
-- combined with the process' ``umask`` value to determine the file mode
-+ combined with the process's ``umask`` value to determine the file mode
- and access flags. If the path already exists, :exc:`FileExistsError`
- is raised.
-
-@@ -1303,30 +1378,51 @@
- The *exist_ok* parameter was added.
-
-
--.. method:: Path.owner()
--
-- Return the name of the user owning the file. :exc:`KeyError` is raised
-- if the file's uid isn't found in the system database.
-+.. method:: Path.symlink_to(target, target_is_directory=False)
-
-+ Make this path a symbolic link pointing to *target*.
-
--.. method:: Path.readlink()
-+ On Windows, a symlink represents either a file or a directory, and does not
-+ morph to the target dynamically. If the target is present, the type of the
-+ symlink will be created to match. Otherwise, the symlink will be created
-+ as a directory if *target_is_directory* is true or a file symlink (the
-+ default) otherwise. On non-Windows platforms, *target_is_directory* is ignored.
-
-- Return the path to which the symbolic link points (as returned by
-- :func:`os.readlink`)::
-+ ::
-
- >>> p = Path('mylink')
- >>> p.symlink_to('setup.py')
-- >>> p.readlink()
-- PosixPath('setup.py')
-+ >>> p.resolve()
-+ PosixPath('/home/antoine/pathlib/setup.py')
-+ >>> p.stat().st_size
-+ 956
-+ >>> p.lstat().st_size
-+ 8
-
-- .. versionadded:: 3.9
-+ .. note::
-+ The order of arguments (link, target) is the reverse
-+ of :func:`os.symlink`'s.
-+
-+
-+.. method:: Path.hardlink_to(target)
-+
-+ Make this path a hard link to the same file as *target*.
-+
-+ .. note::
-+ The order of arguments (link, target) is the reverse
-+ of :func:`os.link`'s.
-+
-+ .. versionadded:: 3.10
-
-
-+Renaming and deleting
-+^^^^^^^^^^^^^^^^^^^^^
-+
- .. method:: Path.rename(target)
-
-- Rename this file or directory to the given *target*, and return a new Path
-- instance pointing to *target*. On Unix, if *target* exists and is a file,
-- it will be replaced silently if the user has permission.
-+ Rename this file or directory to the given *target*, and return a new
-+ :class:`!Path` instance pointing to *target*. On Unix, if *target* exists
-+ and is a file, it will be replaced silently if the user has permission.
- On Windows, if *target* exists, :exc:`FileExistsError` will be raised.
- *target* can be either a string or another path object::
-
-@@ -1340,93 +1436,42 @@
- 'some text'
-
- The target path may be absolute or relative. Relative paths are interpreted
-- relative to the current working directory, *not* the directory of the Path
-- object.
-+ relative to the current working directory, *not* the directory of the
-+ :class:`!Path` object.
-
- It is implemented in terms of :func:`os.rename` and gives the same guarantees.
-
- .. versionchanged:: 3.8
-- Added return value, return the new Path instance.
-+ Added return value, return the new :class:`!Path` instance.
-
-
- .. method:: Path.replace(target)
-
-- Rename this file or directory to the given *target*, and return a new Path
-- instance pointing to *target*. If *target* points to an existing file or
-- empty directory, it will be unconditionally replaced.
-+ Rename this file or directory to the given *target*, and return a new
-+ :class:`!Path` instance pointing to *target*. If *target* points to an
-+ existing file or empty directory, it will be unconditionally replaced.
-
- The target path may be absolute or relative. Relative paths are interpreted
-- relative to the current working directory, *not* the directory of the Path
-- object.
-+ relative to the current working directory, *not* the directory of the
-+ :class:`!Path` object.
-
- .. versionchanged:: 3.8
-- Added return value, return the new Path instance.
--
--
--.. method:: Path.absolute()
--
-- Make the path absolute, without normalization or resolving symlinks.
-- Returns a new path object::
--
-- >>> p = Path('tests')
-- >>> p
-- PosixPath('tests')
-- >>> p.absolute()
-- PosixPath('/home/antoine/pathlib/tests')
--
--
--.. method:: Path.resolve(strict=False)
--
-- Make the path absolute, resolving any symlinks. A new path object is
-- returned::
--
-- >>> p = Path()
-- >>> p
-- PosixPath('.')
-- >>> p.resolve()
-- PosixPath('/home/antoine/pathlib')
--
-- "``..``" components are also eliminated (this is the only method to do so)::
-+ Added return value, return the new :class:`!Path` instance.
-
-- >>> p = Path('docs/../setup.py')
-- >>> p.resolve()
-- PosixPath('/home/antoine/pathlib/setup.py')
--
-- If the path doesn't exist and *strict* is ``True``, :exc:`FileNotFoundError`
-- is raised. If *strict* is ``False``, the path is resolved as far as possible
-- and any remainder is appended without checking whether it exists. If an
-- infinite loop is encountered along the resolution path, :exc:`RuntimeError`
-- is raised.
--
-- .. versionchanged:: 3.6
-- The *strict* parameter was added (pre-3.6 behavior is strict).
-
--.. method:: Path.rglob(pattern, *, case_sensitive=None)
--
-- Glob the given relative *pattern* recursively. This is like calling
-- :func:`Path.glob` with "``**/``" added in front of the *pattern*, where
-- *patterns* are the same as for :mod:`fnmatch`::
--
-- >>> sorted(Path().rglob("*.py"))
-- [PosixPath('build/lib/pathlib.py'),
-- PosixPath('docs/conf.py'),
-- PosixPath('pathlib.py'),
-- PosixPath('setup.py'),
-- PosixPath('test_pathlib.py')]
-+.. method:: Path.unlink(missing_ok=False)
-
-- By default, or when the *case_sensitive* keyword-only argument is set to
-- ``None``, this method matches paths using platform-specific casing rules:
-- typically, case-sensitive on POSIX, and case-insensitive on Windows.
-- Set *case_sensitive* to ``True`` or ``False`` to override this behaviour.
-+ Remove this file or symbolic link. If the path points to a directory,
-+ use :func:`Path.rmdir` instead.
-
-- .. audit-event:: pathlib.Path.rglob self,pattern pathlib.Path.rglob
-+ If *missing_ok* is false (the default), :exc:`FileNotFoundError` is
-+ raised if the path does not exist.
-
-- .. versionchanged:: 3.11
-- Return only directories if *pattern* ends with a pathname components
-- separator (:data:`~os.sep` or :data:`~os.altsep`).
-+ If *missing_ok* is true, :exc:`FileNotFoundError` exceptions will be
-+ ignored (same behavior as the POSIX ``rm -f`` command).
-
-- .. versionchanged:: 3.12
-- The *case_sensitive* parameter was added.
-+ .. versionchanged:: 3.8
-+ The *missing_ok* parameter was added.
-
-
- .. method:: Path.rmdir()
-@@ -1434,64 +1479,46 @@
- Remove this directory. The directory must be empty.
-
-
--.. method:: Path.symlink_to(target, target_is_directory=False)
--
-- Make this path a symbolic link pointing to *target*.
--
-- On Windows, a symlink represents either a file or a directory, and does not
-- morph to the target dynamically. If the target is present, the type of the
-- symlink will be created to match. Otherwise, the symlink will be created
-- as a directory if *target_is_directory* is ``True`` or a file symlink (the
-- default) otherwise. On non-Windows platforms, *target_is_directory* is ignored.
--
-- ::
-+Permissions and ownership
-+^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- >>> p = Path('mylink')
-- >>> p.symlink_to('setup.py')
-- >>> p.resolve()
-- PosixPath('/home/antoine/pathlib/setup.py')
-- >>> p.stat().st_size
-- 956
-- >>> p.lstat().st_size
-- 8
-+.. method:: Path.owner()
-
-- .. note::
-- The order of arguments (link, target) is the reverse
-- of :func:`os.symlink`'s.
-+ Return the name of the user owning the file. :exc:`KeyError` is raised
-+ if the file's user identifier (UID) isn't found in the system database.
-
--.. method:: Path.hardlink_to(target)
-
-- Make this path a hard link to the same file as *target*.
-+.. method:: Path.group()
-
-- .. note::
-- The order of arguments (link, target) is the reverse
-- of :func:`os.link`'s.
-+ Return the name of the group owning the file. :exc:`KeyError` is raised
-+ if the file's group identifier (GID) isn't found in the system database.
-
-- .. versionadded:: 3.10
-
-+.. method:: Path.chmod(mode, *, follow_symlinks=True)
-
--.. method:: Path.touch(mode=0o666, exist_ok=True)
-+ Change the file mode and permissions, like :func:`os.chmod`.
-
-- Create a file at this given path. If *mode* is given, it is combined
-- with the process' ``umask`` value to determine the file mode and access
-- flags. If the file already exists, the function succeeds if *exist_ok*
-- is true (and its modification time is updated to the current time),
-- otherwise :exc:`FileExistsError` is raised.
-+ This method normally follows symlinks. Some Unix flavours support changing
-+ permissions on the symlink itself; on these platforms you may add the
-+ argument ``follow_symlinks=False``, or use :meth:`~Path.lchmod`.
-
-+ ::
-
--.. method:: Path.unlink(missing_ok=False)
-+ >>> p = Path('setup.py')
-+ >>> p.stat().st_mode
-+ 33277
-+ >>> p.chmod(0o444)
-+ >>> p.stat().st_mode
-+ 33060
-
-- Remove this file or symbolic link. If the path points to a directory,
-- use :func:`Path.rmdir` instead.
-+ .. versionchanged:: 3.10
-+ The *follow_symlinks* parameter was added.
-
-- If *missing_ok* is false (the default), :exc:`FileNotFoundError` is
-- raised if the path does not exist.
-
-- If *missing_ok* is true, :exc:`FileNotFoundError` exceptions will be
-- ignored (same behavior as the POSIX ``rm -f`` command).
-+.. method:: Path.lchmod(mode)
-
-- .. versionchanged:: 3.8
-- The *missing_ok* parameter was added.
-+ Like :meth:`Path.chmod` but, if the path points to a symbolic link, the
-+ symbolic link's mode is changed rather than its target's.
-
-
- Correspondence to tools in the :mod:`os` module
-@@ -1500,51 +1527,54 @@
- Below is a table mapping various :mod:`os` functions to their corresponding
- :class:`PurePath`/:class:`Path` equivalent.
-
--.. note::
--
-- Not all pairs of functions/methods below are equivalent. Some of them,
-- despite having some overlapping use-cases, have different semantics. They
-- include :func:`os.path.abspath` and :meth:`Path.absolute`,
-- :func:`os.path.relpath` and :meth:`PurePath.relative_to`.
--
--==================================== ==============================
--:mod:`os` and :mod:`os.path` :mod:`pathlib`
--==================================== ==============================
--:func:`os.path.abspath` :meth:`Path.absolute` [#]_
--:func:`os.path.realpath` :meth:`Path.resolve`
--:func:`os.chmod` :meth:`Path.chmod`
--:func:`os.mkdir` :meth:`Path.mkdir`
--:func:`os.makedirs` :meth:`Path.mkdir`
--:func:`os.rename` :meth:`Path.rename`
--:func:`os.replace` :meth:`Path.replace`
--:func:`os.rmdir` :meth:`Path.rmdir`
--:func:`os.remove`, :func:`os.unlink` :meth:`Path.unlink`
--:func:`os.getcwd` :func:`Path.cwd`
--:func:`os.path.exists` :meth:`Path.exists`
--:func:`os.path.expanduser` :meth:`Path.expanduser` and
-- :meth:`Path.home`
--:func:`os.listdir` :meth:`Path.iterdir`
--:func:`os.walk` :meth:`Path.walk`
--:func:`os.path.isdir` :meth:`Path.is_dir`
--:func:`os.path.isfile` :meth:`Path.is_file`
--:func:`os.path.islink` :meth:`Path.is_symlink`
--:func:`os.link` :meth:`Path.hardlink_to`
--:func:`os.symlink` :meth:`Path.symlink_to`
--:func:`os.readlink` :meth:`Path.readlink`
--:func:`os.path.relpath` :meth:`PurePath.relative_to` [#]_
--:func:`os.stat` :meth:`Path.stat`,
-- :meth:`Path.owner`,
-- :meth:`Path.group`
--:func:`os.path.isabs` :meth:`PurePath.is_absolute`
--:func:`os.path.join` :func:`PurePath.joinpath`
--:func:`os.path.basename` :attr:`PurePath.name`
--:func:`os.path.dirname` :attr:`PurePath.parent`
--:func:`os.path.samefile` :meth:`Path.samefile`
--:func:`os.path.splitext` :attr:`PurePath.stem` and
-- :attr:`PurePath.suffix`
--==================================== ==============================
-+===================================== ==============================================
-+:mod:`os` and :mod:`os.path` :mod:`pathlib`
-+===================================== ==============================================
-+:func:`os.path.dirname` :attr:`PurePath.parent`
-+:func:`os.path.basename` :attr:`PurePath.name`
-+:func:`os.path.splitext` :attr:`PurePath.stem`, :attr:`PurePath.suffix`
-+:func:`os.path.join` :meth:`PurePath.joinpath`
-+:func:`os.path.isabs` :meth:`PurePath.is_absolute`
-+:func:`os.path.relpath` :meth:`PurePath.relative_to` [1]_
-+:func:`os.path.expanduser` :meth:`Path.expanduser` [2]_
-+:func:`os.path.realpath` :meth:`Path.resolve`
-+:func:`os.path.abspath` :meth:`Path.absolute` [3]_
-+:func:`os.path.exists` :meth:`Path.exists`
-+:func:`os.path.isfile` :meth:`Path.is_file`
-+:func:`os.path.isdir` :meth:`Path.is_dir`
-+:func:`os.path.islink` :meth:`Path.is_symlink`
-+:func:`os.path.isjunction` :meth:`Path.is_junction`
-+:func:`os.path.ismount` :meth:`Path.is_mount`
-+:func:`os.path.samefile` :meth:`Path.samefile`
-+:func:`os.getcwd` :meth:`Path.cwd`
-+:func:`os.stat` :meth:`Path.stat`
-+:func:`os.lstat` :meth:`Path.lstat`
-+:func:`os.listdir` :meth:`Path.iterdir`
-+:func:`os.walk` :meth:`Path.walk` [4]_
-+:func:`os.mkdir`, :func:`os.makedirs` :meth:`Path.mkdir`
-+:func:`os.link` :meth:`Path.hardlink_to`
-+:func:`os.symlink` :meth:`Path.symlink_to`
-+:func:`os.readlink` :meth:`Path.readlink`
-+:func:`os.rename` :meth:`Path.rename`
-+:func:`os.replace` :meth:`Path.replace`
-+:func:`os.remove`, :func:`os.unlink` :meth:`Path.unlink`
-+:func:`os.rmdir` :meth:`Path.rmdir`
-+:func:`os.chmod` :meth:`Path.chmod`
-+:func:`os.lchmod` :meth:`Path.lchmod`
-+===================================== ==============================================
-
- .. rubric:: Footnotes
-
--.. [#] :func:`os.path.abspath` normalizes the resulting path, which may change its meaning in the presence of symlinks, while :meth:`Path.absolute` does not.
--.. [#] :meth:`PurePath.relative_to` requires ``self`` to be the subpath of the argument, but :func:`os.path.relpath` does not.
-+.. [1] :func:`os.path.relpath` calls :func:`~os.path.abspath` to make paths
-+ absolute and remove "``..``" parts, whereas :meth:`PurePath.relative_to`
-+ is a lexical operation that raises :exc:`ValueError` when its inputs'
-+ anchors differ (e.g. if one path is absolute and the other relative.)
-+.. [2] :func:`os.path.expanduser` returns the path unchanged if the home
-+ directory can't be resolved, whereas :meth:`Path.expanduser` raises
-+ :exc:`RuntimeError`.
-+.. [3] :func:`os.path.abspath` removes "``..``" components without resolving
-+ symlinks, which may change the meaning of the path, whereas
-+ :meth:`Path.absolute` leaves any "``..``" components in the path.
-+.. [4] :func:`os.walk` always follows symlinks when categorizing paths into
-+ *dirnames* and *filenames*, whereas :meth:`Path.walk` categorizes all
-+ symlinks into *filenames* when *follow_symlinks* is false (the default.)
-diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst
-index 8a6ee9c5c19..32c41b8b2c1 100644
---- a/Doc/library/pdb.rst
-+++ b/Doc/library/pdb.rst
-@@ -49,7 +49,7 @@
- running without the debugger using the :pdbcmd:`continue` command.
-
- .. versionchanged:: 3.7
-- The built-in :func:`breakpoint()`, when called with defaults, can be used
-+ The built-in :func:`breakpoint`, when called with defaults, can be used
- instead of ``import pdb; pdb.set_trace()``.
-
- ::
-diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst
-index 5d4ff34ba02..f095cc84173 100644
---- a/Doc/library/pkgutil.rst
-+++ b/Doc/library/pkgutil.rst
-@@ -34,9 +34,9 @@
- *name* argument. This feature is similar to :file:`\*.pth` files (see the
- :mod:`site` module for more information), except that it doesn't special-case
- lines starting with ``import``. A :file:`\*.pkg` file is trusted at face
-- value: apart from checking for duplicates, all entries found in a
-- :file:`\*.pkg` file are added to the path, regardless of whether they exist
-- on the filesystem. (This is a feature.)
-+ value: apart from skipping blank lines and ignoring comments, all entries
-+ found in a :file:`\*.pkg` file are added to the path, regardless of whether
-+ they exist on the filesystem (this is a feature).
-
- If the input path is not a list (as is the case for frozen packages) it is
- returned unchanged. The input path is not modified; an extended copy is
-diff --git a/Doc/library/platform.rst b/Doc/library/platform.rst
-index 2f5bf53bc5c..0cc5e532711 100644
---- a/Doc/library/platform.rst
-+++ b/Doc/library/platform.rst
-@@ -148,6 +148,9 @@
- Returns the system/OS name, such as ``'Linux'``, ``'Darwin'``, ``'Java'``,
- ``'Windows'``. An empty string is returned if the value cannot be determined.
-
-+ On iOS and Android, this returns the user-facing OS name (i.e, ``'iOS``,
-+ ``'iPadOS'`` or ``'Android'``). To obtain the kernel name (``'Darwin'`` or
-+ ``'Linux'``), use :func:`os.uname()`.
-
- .. function:: system_alias(system, release, version)
-
-@@ -161,6 +164,8 @@
- Returns the system's release version, e.g. ``'#3 on degas'``. An empty string is
- returned if the value cannot be determined.
-
-+ On iOS and Android, this is the user-facing OS version. To obtain the
-+ Darwin or Linux kernel version, use :func:`os.uname()`.
-
- .. function:: uname()
-
-@@ -234,7 +239,6 @@
- macOS Platform
- --------------
-
--
- .. function:: mac_ver(release='', versioninfo=('','',''), machine='')
-
- Get macOS version information and return it as tuple ``(release, versioninfo,
-@@ -244,6 +248,24 @@
- Entries which cannot be determined are set to ``''``. All tuple entries are
- strings.
-
-+iOS Platform
-+------------
-+
-+.. function:: ios_ver(system='', release='', model='', is_simulator=False)
-+
-+ Get iOS version information and return it as a
-+ :func:`~collections.namedtuple` with the following attributes:
-+
-+ * ``system`` is the OS name; either ``'iOS'`` or ``'iPadOS'``.
-+ * ``release`` is the iOS version number as a string (e.g., ``'17.2'``).
-+ * ``model`` is the device model identifier; this will be a string like
-+ ``'iPhone13,2'`` for a physical device, or ``'iPhone'`` on a simulator.
-+ * ``is_simulator`` is a boolean describing if the app is running on a
-+ simulator or a physical device.
-+
-+ Entries which cannot be determined are set to the defaults given as
-+ parameters.
-+
-
- Unix Platforms
- --------------
-diff --git a/Doc/library/pprint.rst b/Doc/library/pprint.rst
-index df706c10ce9..1b3498e51f7 100644
---- a/Doc/library/pprint.rst
-+++ b/Doc/library/pprint.rst
-@@ -35,24 +35,66 @@
- Functions
- ---------
-
--.. function:: pp(object, *args, sort_dicts=False, **kwargs)
--
-- Prints the formatted representation of *object* followed by a newline.
-- If *sort_dicts* is false (the default), dictionaries will be displayed with
-- their keys in insertion order, otherwise the dict keys will be sorted.
-- *args* and *kwargs* will be passed to :func:`~pprint.pprint` as formatting
-- parameters.
--
-- >>> import pprint
-- >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
-- >>> stuff.insert(0, stuff)
-- >>> pprint.pp(stuff)
-- [,
-- 'spam',
-- 'eggs',
-- 'lumberjack',
-- 'knights',
-- 'ni']
-+.. function:: pp(object, stream=None, indent=1, width=80, depth=None, *, \
-+ compact=False, sort_dicts=False, underscore_numbers=False)
-+
-+ Prints the formatted representation of *object*, followed by a newline.
-+ This function may be used in the interactive interpreter
-+ instead of the :func:`print` function for inspecting values.
-+ Tip: you can reassign ``print = pprint.pp`` for use within a scope.
-+
-+ :param object:
-+ The object to be printed.
-+
-+ :param stream:
-+ A file-like object to which the output will be written
-+ by calling its :meth:`!write` method.
-+ If ``None`` (the default), :data:`sys.stdout` is used.
-+ :type stream: :term:`file-like object` | None
-+
-+ :param int indent:
-+ The amount of indentation added for each nesting level.
-+
-+ :param int width:
-+ The desired maximum number of characters per line in the output.
-+ If a structure cannot be formatted within the width constraint,
-+ a best effort will be made.
-+
-+ :param depth:
-+ The number of nesting levels which may be printed.
-+ If the data structure being printed is too deep,
-+ the next contained level is replaced by ``...``.
-+ If ``None`` (the default), there is no constraint
-+ on the depth of the objects being formatted.
-+ :type depth: int | None
-+
-+ :param bool compact:
-+ Control the way long :term:`sequences ` are formatted.
-+ If ``False`` (the default),
-+ each item of a sequence will be formatted on a separate line,
-+ otherwise as many items as will fit within the *width*
-+ will be formatted on each output line.
-+
-+ :param bool sort_dicts:
-+ If ``True``, dictionaries will be formatted with
-+ their keys sorted, otherwise
-+ they will be displayed in insertion order (the default).
-+
-+ :param bool underscore_numbers:
-+ If ``True``,
-+ integers will be formatted with the ``_`` character for a thousands separator,
-+ otherwise underscores are not displayed (the default).
-+
-+ >>> import pprint
-+ >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
-+ >>> stuff.insert(0, stuff)
-+ >>> pprint.pp(stuff)
-+ [,
-+ 'spam',
-+ 'eggs',
-+ 'lumberjack',
-+ 'knights',
-+ 'ni']
-
- .. versionadded:: 3.8
-
-@@ -60,19 +102,10 @@
- .. function:: pprint(object, stream=None, indent=1, width=80, depth=None, *, \
- compact=False, sort_dicts=True, underscore_numbers=False)
-
-- Prints the formatted representation of *object* on *stream*, followed by a
-- newline. If *stream* is ``None``, :data:`sys.stdout` is used. This may be used
-- in the interactive interpreter instead of the :func:`print` function for
-- inspecting values (you can even reassign ``print = pprint.pprint`` for use
-- within a scope).
--
-- The configuration parameters *stream*, *indent*, *width*, *depth*,
-- *compact*, *sort_dicts* and *underscore_numbers* are passed to the
-- :class:`PrettyPrinter` constructor and their meanings are as
-- described in its documentation below.
-+ Alias for :func:`~pprint.pp` with *sort_dicts* set to ``True`` by default,
-+ which would automatically sort the dictionaries' keys,
-+ you might want to use :func:`~pprint.pp` instead where it is ``False`` by default.
-
-- Note that *sort_dicts* is ``True`` by default and you might want to use
-- :func:`~pprint.pp` instead where it is ``False`` by default.
-
- .. function:: pformat(object, indent=1, width=80, depth=None, *, \
- compact=False, sort_dicts=True, underscore_numbers=False)
-@@ -80,7 +113,7 @@
- Return the formatted representation of *object* as a string. *indent*,
- *width*, *depth*, *compact*, *sort_dicts* and *underscore_numbers* are
- passed to the :class:`PrettyPrinter` constructor as formatting parameters
-- and their meanings are as described in its documentation below.
-+ and their meanings are as described in the documentation above.
-
-
- .. function:: isreadable(object)
-@@ -119,51 +152,39 @@
- PrettyPrinter Objects
- ---------------------
-
--This module defines one class:
--
--.. First the implementation class:
--
--
- .. index:: single: ...; placeholder
-
- .. class:: PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, \
- compact=False, sort_dicts=True, underscore_numbers=False)
-
-- Construct a :class:`PrettyPrinter` instance. This constructor understands
-- several keyword parameters.
--
-- *stream* (default :data:`!sys.stdout`) is a :term:`file-like object` to
-- which the output will be written by calling its :meth:`!write` method.
-- If both *stream* and :data:`!sys.stdout` are ``None``, then
-- :meth:`~PrettyPrinter.pprint` silently returns.
-+ Construct a :class:`PrettyPrinter` instance.
-
-- Other values configure the manner in which nesting of complex data
-- structures is displayed.
-+ Arguments have the same meaning as for :func:`~pprint.pp`.
-+ Note that they are in a different order, and that *sort_dicts* defaults to ``True``.
-
-- *indent* (default 1) specifies the amount of indentation added for
-- each nesting level.
--
-- *depth* controls the number of nesting levels which may be printed; if
-- the data structure being printed is too deep, the next contained level
-- is replaced by ``...``. By default, there is no constraint on the
-- depth of the objects being formatted.
--
-- *width* (default 80) specifies the desired maximum number of characters per
-- line in the output. If a structure cannot be formatted within the width
-- constraint, a best effort will be made.
--
-- *compact* impacts the way that long sequences (lists, tuples, sets, etc)
-- are formatted. If *compact* is false (the default) then each item of a
-- sequence will be formatted on a separate line. If *compact* is true, as
-- many items as will fit within the *width* will be formatted on each output
-- line.
--
-- If *sort_dicts* is true (the default), dictionaries will be formatted with
-- their keys sorted, otherwise they will display in insertion order.
-+ >>> import pprint
-+ >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
-+ >>> stuff.insert(0, stuff[:])
-+ >>> pp = pprint.PrettyPrinter(indent=4)
-+ >>> pp.pprint(stuff)
-+ [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
-+ 'spam',
-+ 'eggs',
-+ 'lumberjack',
-+ 'knights',
-+ 'ni']
-+ >>> pp = pprint.PrettyPrinter(width=41, compact=True)
-+ >>> pp.pprint(stuff)
-+ [['spam', 'eggs', 'lumberjack',
-+ 'knights', 'ni'],
-+ 'spam', 'eggs', 'lumberjack', 'knights',
-+ 'ni']
-+ >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
-+ ... ('parrot', ('fresh fruit',))))))))
-+ >>> pp = pprint.PrettyPrinter(depth=6)
-+ >>> pp.pprint(tup)
-+ ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))
-
-- If *underscore_numbers* is true, integers will be formatted with the
-- ``_`` character for a thousands separator, otherwise underscores are not
-- displayed (the default).
-
- .. versionchanged:: 3.4
- Added the *compact* parameter.
-@@ -177,29 +198,6 @@
- .. versionchanged:: 3.11
- No longer attempts to write to :data:`!sys.stdout` if it is ``None``.
-
-- >>> import pprint
-- >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
-- >>> stuff.insert(0, stuff[:])
-- >>> pp = pprint.PrettyPrinter(indent=4)
-- >>> pp.pprint(stuff)
-- [ ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
-- 'spam',
-- 'eggs',
-- 'lumberjack',
-- 'knights',
-- 'ni']
-- >>> pp = pprint.PrettyPrinter(width=41, compact=True)
-- >>> pp.pprint(stuff)
-- [['spam', 'eggs', 'lumberjack',
-- 'knights', 'ni'],
-- 'spam', 'eggs', 'lumberjack', 'knights',
-- 'ni']
-- >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
-- ... ('parrot', ('fresh fruit',))))))))
-- >>> pp = pprint.PrettyPrinter(depth=6)
-- >>> pp.pprint(tup)
-- ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))
--
-
- :class:`PrettyPrinter` instances have the following methods:
-
-diff --git a/Doc/library/profile.rst b/Doc/library/profile.rst
-index cc059b66fcb..b89655ea472 100644
---- a/Doc/library/profile.rst
-+++ b/Doc/library/profile.rst
-@@ -675,7 +675,7 @@
- that you choose (see :ref:`profile-calibration`). For most machines, a timer
- that returns a lone integer value will provide the best results in terms of
- low overhead during profiling. (:func:`os.times` is *pretty* bad, as it
-- returns a tuple of floating point values). If you want to substitute a
-+ returns a tuple of floating-point values). If you want to substitute a
- better timer in the cleanest fashion, derive a class and hardwire a
- replacement dispatch method that best handles your timer call, along with the
- appropriate calibration constant.
-@@ -692,7 +692,7 @@
- As the :class:`cProfile.Profile` class cannot be calibrated, custom timer
- functions should be used with care and should be as fast as possible. For
- the best results with a custom timer, it might be necessary to hard-code it
-- in the C source of the internal :mod:`_lsprof` module.
-+ in the C source of the internal :mod:`!_lsprof` module.
-
- Python 3.3 adds several new functions in :mod:`time` that can be used to make
- precise measurements of process or wall-clock time. For example, see
-diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst
-index 98ca174d9e3..d71d7212cfd 100644
---- a/Doc/library/pwd.rst
-+++ b/Doc/library/pwd.rst
-@@ -10,7 +10,7 @@
- This module provides access to the Unix user account and password database. It
- is available on all Unix versions.
-
--.. availability:: Unix, not Emscripten, not WASI.
-+.. availability:: Unix, not WASI, not iOS.
-
- Password database entries are reported as a tuple-like object, whose attributes
- correspond to the members of the ``passwd`` structure (Attribute field below,
-diff --git a/Doc/library/random.rst b/Doc/library/random.rst
-index 10c88ac68a8..a589bf76b5c 100644
---- a/Doc/library/random.rst
-+++ b/Doc/library/random.rst
-@@ -194,8 +194,8 @@
-
- For a given seed, the :func:`choices` function with equal weighting
- typically produces a different sequence than repeated calls to
-- :func:`choice`. The algorithm used by :func:`choices` uses floating
-- point arithmetic for internal consistency and speed. The algorithm used
-+ :func:`choice`. The algorithm used by :func:`choices` uses floating-point
-+ arithmetic for internal consistency and speed. The algorithm used
- by :func:`choice` defaults to integer arithmetic with repeated selections
- to avoid small biases from round-off error.
-
-@@ -292,12 +292,12 @@
-
- .. function:: random()
-
-- Return the next random floating point number in the range ``0.0 <= X < 1.0``
-+ Return the next random floating-point number in the range ``0.0 <= X < 1.0``
-
-
- .. function:: uniform(a, b)
-
-- Return a random floating point number *N* such that ``a <= N <= b`` for
-+ Return a random floating-point number *N* such that ``a <= N <= b`` for
- ``a <= b`` and ``b <= N <= a`` for ``b < a``.
-
- The end-point value ``b`` may or may not be included in the range
-@@ -307,7 +307,7 @@
-
- .. function:: triangular(low, high, mode)
-
-- Return a random floating point number *N* such that ``low <= N <= high`` and
-+ Return a random floating-point number *N* such that ``low <= N <= high`` and
- with the specified *mode* between those bounds. The *low* and *high* bounds
- default to zero and one. The *mode* argument defaults to the midpoint
- between the bounds, giving a symmetric distribution.
-diff --git a/Doc/library/re.rst b/Doc/library/re.rst
-index 220bd687bc1..3c9b99c6438 100644
---- a/Doc/library/re.rst
-+++ b/Doc/library/re.rst
-@@ -101,7 +101,7 @@
- ``.``
- (Dot.) In the default mode, this matches any character except a newline. If
- the :const:`DOTALL` flag has been specified, this matches any character
-- including a newline.
-+ including a newline. ``(?s:.)`` matches any character regardless of flags.
-
- .. index:: single: ^ (caret); in regular expressions
-
-@@ -600,10 +600,9 @@
-
- ``\s``
- For Unicode (str) patterns:
-- Matches Unicode whitespace characters (which includes
-- ``[ \t\n\r\f\v]``, and also many other characters, for example the
-- non-breaking spaces mandated by typography rules in many
-- languages).
-+ Matches Unicode whitespace characters (as defined by :py:meth:`str.isspace`).
-+ This includes ``[ \t\n\r\f\v]``, and also many other characters, for example the
-+ non-breaking spaces mandated by typography rules in many languages.
-
- Matches ``[ \t\n\r\f\v]`` if the :py:const:`~re.ASCII` flag is used.
-
-@@ -911,6 +910,10 @@
- ``None`` if no position in the string matches the pattern; note that this is
- different from finding a zero-length match at some point in the string.
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
-
- .. function:: match(pattern, string, flags=0)
-
-@@ -925,6 +928,10 @@
- If you want to locate a match anywhere in *string*, use :func:`search`
- instead (see also :ref:`search-vs-match`).
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
-
- .. function:: fullmatch(pattern, string, flags=0)
-
-@@ -932,6 +939,10 @@
- corresponding :class:`~re.Match`. Return ``None`` if the string does not match
- the pattern; note that this is different from a zero-length match.
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
- .. versionadded:: 3.4
-
-
-@@ -974,6 +985,10 @@
- >>> re.split(r'(\W*)', '...words...')
- ['', '...', '', '', 'w', '', 'o', '', 'r', '', 'd', '', 's', '...', '', '', '']
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
- .. versionchanged:: 3.1
- Added the optional flags argument.
-
-@@ -999,6 +1014,10 @@
- >>> re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
- [('width', '20'), ('height', '10')]
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
- .. versionchanged:: 3.7
- Non-empty matches can now start just after a previous empty match.
-
-@@ -1010,6 +1029,10 @@
- is scanned left-to-right, and matches are returned in the order found. Empty
- matches are included in the result.
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
- .. versionchanged:: 3.7
- Non-empty matches can now start just after a previous empty match.
-
-@@ -1065,6 +1088,10 @@
- character ``'0'``. The backreference ``\g<0>`` substitutes in the entire
- substring matched by the RE.
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
- .. versionchanged:: 3.1
- Added the optional flags argument.
-
-@@ -1100,6 +1127,10 @@
- .. versionchanged:: 3.5
- Unmatched groups are replaced with an empty string.
-
-+ The expression's behaviour can be modified by specifying a *flags* value.
-+ Values can be any of the `flags`_ variables, combined using bitwise OR
-+ (the ``|`` operator).
-+
-
- .. function:: escape(pattern)
-
-diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst
-index 43cf8d5cdac..b6486576872 100644
---- a/Doc/library/readline.rst
-+++ b/Doc/library/readline.rst
-@@ -24,6 +24,8 @@
- allowable constructs of that file, and the capabilities of the
- Readline library in general.
-
-+.. include:: ../includes/wasm-ios-notavail.rst
+
+ Unix Platforms
+ --------------
+diff --git a/Doc/library/pwd.rst b/Doc/library/pwd.rst
+index 98ca174d9e3..d71d7212cfd 100644
+--- a/Doc/library/pwd.rst
++++ b/Doc/library/pwd.rst
+@@ -10,7 +10,7 @@
+ This module provides access to the Unix user account and password database. It
+ is available on all Unix versions.
+
+-.. availability:: Unix, not Emscripten, not WASI.
++.. availability:: Unix, not WASI, not iOS.
+
+ Password database entries are reported as a tuple-like object, whose attributes
+ correspond to the members of the ``passwd`` structure (Attribute field below,
+diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst
+index f02aec8a6a8..b6486576872 100644
+--- a/Doc/library/readline.rst
++++ b/Doc/library/readline.rst
+@@ -24,6 +24,8 @@
+ allowable constructs of that file, and the capabilities of the
+ Readline library in general.
+
++.. include:: ../includes/wasm-ios-notavail.rst
+
.. note::
The underlying Readline library API may be implemented by
-@@ -44,6 +46,10 @@
- python:bind -v
- python:bind ^I rl_complete
-
-+ Also note that different libraries may use different history file formats.
-+ When switching the underlying library, existing history files may become
-+ unusable.
-+
-
- Init file
- ---------
diff --git a/Doc/library/resource.rst b/Doc/library/resource.rst
-index 7465bc5402c..0515d205bbc 100644
+index 02009d82104..0515d205bbc 100644
--- a/Doc/library/resource.rst
+++ b/Doc/library/resource.rst
@@ -13,7 +13,7 @@
@@ -8522,30 +676,8 @@ index 7465bc5402c..0515d205bbc 100644
Symbolic constants are used to specify particular system resources and to
request usage information about either the current process or its children.
-@@ -305,7 +305,7 @@
- elements.
-
- The fields :attr:`ru_utime` and :attr:`ru_stime` of the return value are
-- floating point values representing the amount of time spent executing in user
-+ floating-point values representing the amount of time spent executing in user
- mode and the amount of time spent executing in system mode, respectively. The
- remaining values are integers. Consult the :manpage:`getrusage(2)` man page for
- detailed information about these values. A brief summary is presented here:
-diff --git a/Doc/library/select.rst b/Doc/library/select.rst
-index 06ebaf0201e..f23a249f44b 100644
---- a/Doc/library/select.rst
-+++ b/Doc/library/select.rst
-@@ -129,7 +129,7 @@
-
- Empty iterables are allowed, but acceptance of three empty iterables is
- platform-dependent. (It is known to work on Unix but not on Windows.) The
-- optional *timeout* argument specifies a time-out as a floating point number
-+ optional *timeout* argument specifies a time-out as a floating-point number
- in seconds. When the *timeout* argument is omitted the function blocks until
- at least one file descriptor is ready. A time-out value of zero specifies a
- poll and never blocks.
diff --git a/Doc/library/signal.rst b/Doc/library/signal.rst
-index 60f21bc9105..79c4948e99e 100644
+index 641a6c021c1..79c4948e99e 100644
--- a/Doc/library/signal.rst
+++ b/Doc/library/signal.rst
@@ -26,9 +26,9 @@
@@ -8561,109 +693,11 @@ index 60f21bc9105..79c4948e99e 100644
Execution of Python signal handlers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-@@ -425,7 +425,7 @@
- signal to a particular Python thread would be to force a running system call
- to fail with :exc:`InterruptedError`.
-
-- Use :func:`threading.get_ident()` or the :attr:`~threading.Thread.ident`
-+ Use :func:`threading.get_ident` or the :attr:`~threading.Thread.ident`
- attribute of :class:`threading.Thread` objects to get a suitable value
- for *thread_id*.
-
-diff --git a/Doc/library/site.rst b/Doc/library/site.rst
-index f5cf81fb1c9..514eed314ea 100644
---- a/Doc/library/site.rst
-+++ b/Doc/library/site.rst
-@@ -15,8 +15,9 @@
-
- .. index:: triple: module; search; path
-
--Importing this module will append site-specific paths to the module search path
--and add a few builtins, unless :option:`-S` was used. In that case, this module
-+Importing this module normally appends site-specific paths to the module search path
-+and adds :ref:`callables `, including :func:`help` to the built-in
-+namespace. However, Python startup option :option:`-S` blocks this and this module
- can be safely imported with no automatic modifications to the module search path
- or additions to the builtins. To explicitly trigger the usual site-specific
- additions, call the :func:`main` function.
-diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst
-index 2511ef7f2ad..7cd530a5fd6 100644
---- a/Doc/library/smtplib.rst
-+++ b/Doc/library/smtplib.rst
-@@ -556,34 +556,33 @@
- and 'From' addresses), and the message to be delivered. Note that the headers
- to be included with the message must be included in the message as entered; this
- example doesn't do any processing of the :rfc:`822` headers. In particular, the
--'To' and 'From' addresses must be included in the message headers explicitly. ::
-+'To' and 'From' addresses must be included in the message headers explicitly::
-
- import smtplib
-
-- def prompt(prompt):
-- return input(prompt).strip()
-+ def prompt(title):
-+ return input(title).strip()
-
-- fromaddr = prompt("From: ")
-- toaddrs = prompt("To: ").split()
-+ from_addr = prompt("From: ")
-+ to_addrs = prompt("To: ").split()
- print("Enter message, end with ^D (Unix) or ^Z (Windows):")
-
- # Add the From: and To: headers at the start!
-- msg = ("From: %s\r\nTo: %s\r\n\r\n"
-- % (fromaddr, ", ".join(toaddrs)))
-+ lines = [f"From: {from_addr}", f"To: {', '.join(to_addrs)}", ""]
- while True:
- try:
- line = input()
- except EOFError:
- break
-- if not line:
-- break
-- msg = msg + line
-+ else:
-+ lines.append(line)
-
-+ msg = "\r\n".join(lines)
- print("Message length is", len(msg))
-
-- server = smtplib.SMTP('localhost')
-+ server = smtplib.SMTP("localhost")
- server.set_debuglevel(1)
-- server.sendmail(fromaddr, toaddrs, msg)
-+ server.sendmail(from_addr, to_addrs, msg)
- server.quit()
-
- .. note::
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
-index 10f03b3fe02..337bad40c5a 100644
+index 584a12c2514..337bad40c5a 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
-@@ -695,6 +695,13 @@
-
- .. versionadded:: 3.12
-
-+.. data:: SHUT_RD
-+ SHUT_WR
-+ SHUT_RDWR
-+
-+ These constants are used by the :meth:`~socket.socket.shutdown` method of socket objects.
-+
-+ .. availability:: not WASI.
-
- Functions
- ^^^^^^^^^
-@@ -724,7 +731,7 @@
- of :meth:`socket.getpeername` but not the actual OS resource. Unlike
- :func:`socket.fromfd`, *fileno* will return the same socket and not a
- duplicate. This may help close a detached socket using
-- :meth:`socket.close()`.
-+ :meth:`socket.close`.
-
- The newly created socket is :ref:`non-inheritable `.
-
-@@ -1208,7 +1215,7 @@
+@@ -1215,7 +1215,7 @@
buffer. Raises :exc:`OverflowError` if *length* is outside the
permissible range of values.
@@ -8672,7 +706,7 @@ index 10f03b3fe02..337bad40c5a 100644
Most Unix platforms.
-@@ -1231,7 +1238,7 @@
+@@ -1238,7 +1238,7 @@
amount of ancillary data that can be received, since additional
data may be able to fit into the padding area.
@@ -8681,7 +715,7 @@ index 10f03b3fe02..337bad40c5a 100644
most Unix platforms.
-@@ -1271,7 +1278,7 @@
+@@ -1278,7 +1278,7 @@
(index int, name string) tuples.
:exc:`OSError` if the system call fails.
@@ -8690,7 +724,7 @@ index 10f03b3fe02..337bad40c5a 100644
.. versionadded:: 3.3
-@@ -1298,7 +1305,7 @@
+@@ -1305,7 +1305,7 @@
interface name.
:exc:`OSError` if no interface with the given name exists.
@@ -8699,7 +733,7 @@ index 10f03b3fe02..337bad40c5a 100644
.. versionadded:: 3.3
-@@ -1315,7 +1322,7 @@
+@@ -1322,7 +1322,7 @@
interface index number.
:exc:`OSError` if no interface with the given index exists.
@@ -8708,7 +742,7 @@ index 10f03b3fe02..337bad40c5a 100644
.. versionadded:: 3.3
-@@ -1332,7 +1339,7 @@
+@@ -1339,7 +1339,7 @@
The *fds* parameter is a sequence of file descriptors.
Consult :meth:`~socket.sendmsg` for the documentation of these parameters.
@@ -8717,7 +751,7 @@ index 10f03b3fe02..337bad40c5a 100644
Unix platforms supporting :meth:`~socket.sendmsg`
and :const:`SCM_RIGHTS` mechanism.
-@@ -1346,7 +1353,7 @@
+@@ -1353,7 +1353,7 @@
Return ``(msg, list(fds), flags, addr)``.
Consult :meth:`~socket.recvmsg` for the documentation of these parameters.
@@ -8726,435 +760,8 @@ index 10f03b3fe02..337bad40c5a 100644
Unix platforms supporting :meth:`~socket.sendmsg`
and :const:`SCM_RIGHTS` mechanism.
-@@ -1403,7 +1410,7 @@
- .. method:: socket.close()
-
- Mark the socket closed. The underlying system resource (e.g. a file
-- descriptor) is also closed when all file objects from :meth:`makefile()`
-+ descriptor) is also closed when all file objects from :meth:`makefile`
- are closed. Once that happens, all future operations on the socket
- object will fail. The remote end will receive no more data (after
- queued data is flushed).
-@@ -1418,10 +1425,10 @@
-
- .. note::
-
-- :meth:`close()` releases the resource associated with a connection but
-+ :meth:`close` releases the resource associated with a connection but
- does not necessarily close the connection immediately. If you want
-- to close the connection in a timely fashion, call :meth:`shutdown()`
-- before :meth:`close()`.
-+ to close the connection in a timely fashion, call :meth:`shutdown`
-+ before :meth:`close`.
-
-
- .. method:: socket.connect(address)
-@@ -1917,7 +1924,7 @@
- .. method:: socket.settimeout(value)
-
- Set a timeout on blocking socket operations. The *value* argument can be a
-- nonnegative floating point number expressing seconds, or ``None``.
-+ nonnegative floating-point number expressing seconds, or ``None``.
- If a non-zero value is given, subsequent socket operations will raise a
- :exc:`timeout` exception if the timeout period *value* has elapsed before
- the operation has completed. If zero is given, the socket is put in
-@@ -2030,7 +2037,7 @@
- in non-blocking mode. Also, the blocking and timeout modes are shared between
- file descriptors and socket objects that refer to the same network endpoint.
- This implementation detail can have visible consequences if e.g. you decide
-- to use the :meth:`~socket.fileno()` of a socket.
-+ to use the :meth:`~socket.fileno` of a socket.
-
- Timeouts and the ``connect`` method
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst
-index 70f1e05a653..6d078c59223 100644
---- a/Doc/library/sqlite3.rst
-+++ b/Doc/library/sqlite3.rst
-@@ -127,7 +127,7 @@
- We can see that the table has been created,
- as the query returns a :class:`tuple` containing the table's name.
- If we query ``sqlite_master`` for a non-existent table ``spam``,
--:meth:`!res.fetchone()` will return ``None``:
-+:meth:`!res.fetchone` will return ``None``:
-
- .. doctest::
-
-diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
-index 8fb0d5056c1..b7cf2b28695 100644
---- a/Doc/library/ssl.rst
-+++ b/Doc/library/ssl.rst
-@@ -1021,25 +1021,25 @@
-
- SSL sockets provide the following methods of :ref:`socket-objects`:
-
-- - :meth:`~socket.socket.accept()`
-- - :meth:`~socket.socket.bind()`
-- - :meth:`~socket.socket.close()`
-- - :meth:`~socket.socket.connect()`
-- - :meth:`~socket.socket.detach()`
-- - :meth:`~socket.socket.fileno()`
-- - :meth:`~socket.socket.getpeername()`, :meth:`~socket.socket.getsockname()`
-- - :meth:`~socket.socket.getsockopt()`, :meth:`~socket.socket.setsockopt()`
-- - :meth:`~socket.socket.gettimeout()`, :meth:`~socket.socket.settimeout()`,
-- :meth:`~socket.socket.setblocking()`
-- - :meth:`~socket.socket.listen()`
-- - :meth:`~socket.socket.makefile()`
-- - :meth:`~socket.socket.recv()`, :meth:`~socket.socket.recv_into()`
-+ - :meth:`~socket.socket.accept`
-+ - :meth:`~socket.socket.bind`
-+ - :meth:`~socket.socket.close`
-+ - :meth:`~socket.socket.connect`
-+ - :meth:`~socket.socket.detach`
-+ - :meth:`~socket.socket.fileno`
-+ - :meth:`~socket.socket.getpeername`, :meth:`~socket.socket.getsockname`
-+ - :meth:`~socket.socket.getsockopt`, :meth:`~socket.socket.setsockopt`
-+ - :meth:`~socket.socket.gettimeout`, :meth:`~socket.socket.settimeout`,
-+ :meth:`~socket.socket.setblocking`
-+ - :meth:`~socket.socket.listen`
-+ - :meth:`~socket.socket.makefile`
-+ - :meth:`~socket.socket.recv`, :meth:`~socket.socket.recv_into`
- (but passing a non-zero ``flags`` argument is not allowed)
-- - :meth:`~socket.socket.send()`, :meth:`~socket.socket.sendall()` (with
-+ - :meth:`~socket.socket.send`, :meth:`~socket.socket.sendall` (with
- the same limitation)
-- - :meth:`~socket.socket.sendfile()` (but :mod:`os.sendfile` will be used
-- for plain-text sockets only, else :meth:`~socket.socket.send()` will be used)
-- - :meth:`~socket.socket.shutdown()`
-+ - :meth:`~socket.socket.sendfile` (but :mod:`os.sendfile` will be used
-+ for plain-text sockets only, else :meth:`~socket.socket.send` will be used)
-+ - :meth:`~socket.socket.shutdown`
-
- However, since the SSL (and TLS) protocol has its own framing atop
- of TCP, the SSL sockets abstraction can, in certain respects, diverge from
-@@ -1428,6 +1428,19 @@
- :data:`PROTOCOL_TLS`, :data:`PROTOCOL_TLS_CLIENT`, and
- :data:`PROTOCOL_TLS_SERVER` use TLS 1.2 as minimum TLS version.
-
-+ .. note::
-+
-+ :class:`SSLContext` only supports limited mutation once it has been used
-+ by a connection. Adding new certificates to the internal trust store is
-+ allowed, but changing ciphers, verification settings, or mTLS
-+ certificates may result in surprising behavior.
-+
-+ .. note::
-+
-+ :class:`SSLContext` is designed to be shared and used by multiple
-+ connections.
-+ Thus, it is thread-safe as long as it is not reconfigured after being
-+ used by a connection.
-
- :class:`SSLContext` objects have the following methods and attributes:
-
-@@ -1684,7 +1697,7 @@
- IDN-encoded internationalized domain name, the *server_name_callback*
- receives a decoded U-label (``"pythön.org"``).
-
-- If there is an decoding error on the server name, the TLS connection will
-+ If there is a decoding error on the server name, the TLS connection will
- terminate with an :const:`ALERT_DESCRIPTION_INTERNAL_ERROR` fatal TLS
- alert message to the client.
-
-@@ -2556,7 +2569,7 @@
-
- When calling the :class:`SSLContext` constructor directly,
- :const:`CERT_NONE` is the default. Since it does not authenticate the other
--peer, it can be insecure, especially in client mode where most of time you
-+peer, it can be insecure, especially in client mode where most of the time you
- would like to ensure the authenticity of the server you're talking to.
- Therefore, when in client mode, it is highly recommended to use
- :const:`CERT_REQUIRED`. However, it is in itself not sufficient; you also
-diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst
-index 6da3bced99d..ce1b8a112e8 100644
---- a/Doc/library/statistics.rst
-+++ b/Doc/library/statistics.rst
-@@ -73,7 +73,7 @@
-
- ======================= ===============================================================
- :func:`mean` Arithmetic mean ("average") of data.
--:func:`fmean` Fast, floating point arithmetic mean, with optional weighting.
-+:func:`fmean` Fast, floating-point arithmetic mean, with optional weighting.
- :func:`geometric_mean` Geometric mean of data.
- :func:`harmonic_mean` Harmonic mean of data.
- :func:`median` Median (middle value) of data.
-@@ -408,6 +408,12 @@
- >>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
- 'red'
-
-+ Only hashable inputs are supported. To handle type :class:`set`,
-+ consider casting to :class:`frozenset`. To handle type :class:`list`,
-+ consider casting to :class:`tuple`. For mixed or nested inputs, consider
-+ using this slower quadratic algorithm that only depends on equality tests:
-+ ``max(data, key=data.count)``.
-+
- .. versionchanged:: 3.8
- Now handles multimodal datasets by returning the first mode encountered.
- Formerly, it raised :exc:`StatisticsError` when more than one mode was
-diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
-index d11bfb803f8..bf11e2891db 100644
---- a/Doc/library/stdtypes.rst
-+++ b/Doc/library/stdtypes.rst
-@@ -209,18 +209,18 @@
- pair: object; numeric
- pair: object; Boolean
- pair: object; integer
-- pair: object; floating point
-+ pair: object; floating-point
- pair: object; complex number
- pair: C; language
-
--There are three distinct numeric types: :dfn:`integers`, :dfn:`floating
--point numbers`, and :dfn:`complex numbers`. In addition, Booleans are a
--subtype of integers. Integers have unlimited precision. Floating point
-+There are three distinct numeric types: :dfn:`integers`, :dfn:`floating-point
-+numbers`, and :dfn:`complex numbers`. In addition, Booleans are a
-+subtype of integers. Integers have unlimited precision. Floating-point
- numbers are usually implemented using :c:expr:`double` in C; information
--about the precision and internal representation of floating point
-+about the precision and internal representation of floating-point
- numbers for the machine on which your program is running is available
- in :data:`sys.float_info`. Complex numbers have a real and imaginary
--part, which are each a floating point number. To extract these parts
-+part, which are each a floating-point number. To extract these parts
- from a complex number *z*, use ``z.real`` and ``z.imag``. (The standard
- library includes the additional numeric types :mod:`fractions.Fraction`, for
- rationals, and :mod:`decimal.Decimal`, for floating-point numbers with
-@@ -229,7 +229,7 @@
- .. index::
- pair: numeric; literals
- pair: integer; literals
-- pair: floating point; literals
-+ pair: floating-point; literals
- pair: complex number; literals
- pair: hexadecimal; literals
- pair: octal; literals
-@@ -238,7 +238,7 @@
- Numbers are created by numeric literals or as the result of built-in functions
- and operators. Unadorned integer literals (including hex, octal and binary
- numbers) yield integers. Numeric literals containing a decimal point or an
--exponent sign yield floating point numbers. Appending ``'j'`` or ``'J'`` to a
-+exponent sign yield floating-point numbers. Appending ``'j'`` or ``'J'`` to a
- numeric literal yields an imaginary number (a complex number with a zero real
- part) which you can add to an integer or float to get a complex number with real
- and imaginary parts.
-@@ -832,7 +832,7 @@
- .. deprecated:: 3.12
-
- The use of the bitwise inversion operator ``~`` is deprecated and will
-- raise an error in Python 3.14.
-+ raise an error in Python 3.16.
-
- :class:`bool` is a subclass of :class:`int` (see :ref:`typesnumeric`). In
- many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, respectively.
-@@ -1209,8 +1209,9 @@
- | ``s.pop()`` or ``s.pop(i)`` | retrieves the item at *i* and | \(2) |
- | | also removes it from *s* | |
- +------------------------------+--------------------------------+---------------------+
--| ``s.remove(x)`` | remove the first item from *s* | \(3) |
--| | where ``s[i]`` is equal to *x* | |
-+| ``s.remove(x)`` | removes the first item from | \(3) |
-+| | *s* where ``s[i]`` is equal to | |
-+| | *x* | |
- +------------------------------+--------------------------------+---------------------+
- | ``s.reverse()`` | reverses the items of *s* in | \(4) |
- | | place | |
-@@ -1220,7 +1221,7 @@
- Notes:
-
- (1)
-- *t* must have the same length as the slice it is replacing.
-+ If *k* is not equal to ``1``, *t* must have the same length as the slice it is replacing.
-
- (2)
- The optional argument *i* defaults to ``-1``, so that by default the last
-@@ -1497,8 +1498,8 @@
- .. seealso::
-
- * The `linspace recipe `_
-- shows how to implement a lazy version of range suitable for floating
-- point applications.
-+ shows how to implement a lazy version of range suitable for floating-point
-+ applications.
-
- .. index::
- single: string; text sequence type
-@@ -2092,8 +2093,9 @@
- If *sep* is given, consecutive delimiters are not grouped together and are
- deemed to delimit empty strings (for example, ``'1,,2'.split(',')`` returns
- ``['1', '', '2']``). The *sep* argument may consist of multiple characters
-- (for example, ``'1<>2<>3'.split('<>')`` returns ``['1', '2', '3']``).
-- Splitting an empty string with a specified separator returns ``['']``.
-+ as a single delimiter (to split with multiple delimiters, use
-+ :func:`re.split`). Splitting an empty string with a specified separator
-+ returns ``['']``.
-
- For example::
-
-@@ -2103,6 +2105,8 @@
- ['1', '2,3']
- >>> '1,2,,3,'.split(',')
- ['1', '2', '', '3', '']
-+ >>> '1<>2<>3<4'.split('<>')
-+ ['1', '2', '3<4']
-
- If *sep* is not specified or is ``None``, a different splitting algorithm is
- applied: runs of consecutive whitespace are regarded as a single separator,
-@@ -2430,19 +2434,19 @@
- +------------+-----------------------------------------------------+-------+
- | ``'X'`` | Signed hexadecimal (uppercase). | \(2) |
- +------------+-----------------------------------------------------+-------+
--| ``'e'`` | Floating point exponential format (lowercase). | \(3) |
-+| ``'e'`` | Floating-point exponential format (lowercase). | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'E'`` | Floating point exponential format (uppercase). | \(3) |
-+| ``'E'`` | Floating-point exponential format (uppercase). | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'f'`` | Floating point decimal format. | \(3) |
-+| ``'f'`` | Floating-point decimal format. | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'F'`` | Floating point decimal format. | \(3) |
-+| ``'F'`` | Floating-point decimal format. | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) |
-+| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) |
- | | format if exponent is less than -4 or not less than | |
- | | precision, decimal format otherwise. | |
- +------------+-----------------------------------------------------+-------+
--| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) |
-+| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) |
- | | format if exponent is less than -4 or not less than | |
- | | precision, decimal format otherwise. | |
- +------------+-----------------------------------------------------+-------+
-@@ -3140,10 +3144,9 @@
- If *sep* is given, consecutive delimiters are not grouped together and are
- deemed to delimit empty subsequences (for example, ``b'1,,2'.split(b',')``
- returns ``[b'1', b'', b'2']``). The *sep* argument may consist of a
-- multibyte sequence (for example, ``b'1<>2<>3'.split(b'<>')`` returns
-- ``[b'1', b'2', b'3']``). Splitting an empty sequence with a specified
-- separator returns ``[b'']`` or ``[bytearray(b'')]`` depending on the type
-- of object being split. The *sep* argument may be any
-+ multibyte sequence as a single delimiter. Splitting an empty sequence with
-+ a specified separator returns ``[b'']`` or ``[bytearray(b'')]`` depending
-+ on the type of object being split. The *sep* argument may be any
- :term:`bytes-like object`.
-
- For example::
-@@ -3154,6 +3157,8 @@
- [b'1', b'2,3']
- >>> b'1,2,,3,'.split(b',')
- [b'1', b'2', b'', b'3', b'']
-+ >>> b'1<>2<>3<4'.split(b'<>')
-+ [b'1', b'2', b'3<4']
-
- If *sep* is not specified or is ``None``, a different splitting algorithm
- is applied: runs of consecutive ASCII whitespace are regarded as a single
-@@ -3427,7 +3432,7 @@
- ``b'abcdefghijklmnopqrstuvwxyz'``. Uppercase ASCII characters
- are those byte values in the sequence ``b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'``.
-
-- Unlike :func:`str.swapcase()`, it is always the case that
-+ Unlike :func:`str.swapcase`, it is always the case that
- ``bin.swapcase().swapcase() == bin`` for the binary versions. Case
- conversions are symmetrical in ASCII, even though that is not generally
- true for arbitrary Unicode code points.
-@@ -3648,19 +3653,19 @@
- +------------+-----------------------------------------------------+-------+
- | ``'X'`` | Signed hexadecimal (uppercase). | \(2) |
- +------------+-----------------------------------------------------+-------+
--| ``'e'`` | Floating point exponential format (lowercase). | \(3) |
-+| ``'e'`` | Floating-point exponential format (lowercase). | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'E'`` | Floating point exponential format (uppercase). | \(3) |
-+| ``'E'`` | Floating-point exponential format (uppercase). | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'f'`` | Floating point decimal format. | \(3) |
-+| ``'f'`` | Floating-point decimal format. | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'F'`` | Floating point decimal format. | \(3) |
-+| ``'F'`` | Floating-point decimal format. | \(3) |
- +------------+-----------------------------------------------------+-------+
--| ``'g'`` | Floating point format. Uses lowercase exponential | \(4) |
-+| ``'g'`` | Floating-point format. Uses lowercase exponential | \(4) |
- | | format if exponent is less than -4 or not less than | |
- | | precision, decimal format otherwise. | |
- +------------+-----------------------------------------------------+-------+
--| ``'G'`` | Floating point format. Uses uppercase exponential | \(4) |
-+| ``'G'`` | Floating-point format. Uses uppercase exponential | \(4) |
- | | format if exponent is less than -4 or not less than | |
- | | precision, decimal format otherwise. | |
- +------------+-----------------------------------------------------+-------+
-@@ -3882,7 +3887,7 @@
- >>> a == b
- False
-
-- Note that, as with floating point numbers, ``v is w`` does *not* imply
-+ Note that, as with floating-point numbers, ``v is w`` does *not* imply
- ``v == w`` for memoryview objects.
-
- .. versionchanged:: 3.3
-@@ -3973,7 +3978,7 @@
- dangling resources) as soon as possible.
-
- After this method has been called, any further operation on the view
-- raises a :class:`ValueError` (except :meth:`release()` itself which can
-+ raises a :class:`ValueError` (except :meth:`release` itself which can
- be called multiple times)::
-
- >>> m = memoryview(b'abc')
-@@ -4556,7 +4561,7 @@
-
- Return a shallow copy of the dictionary.
-
-- .. classmethod:: fromkeys(iterable, value=None)
-+ .. classmethod:: fromkeys(iterable, value=None, /)
-
- Create a new dictionary with keys from *iterable* and values set to *value*.
-
-diff --git a/Doc/library/string.rst b/Doc/library/string.rst
-index c3c0d732cf1..1f316307965 100644
---- a/Doc/library/string.rst
-+++ b/Doc/library/string.rst
-@@ -418,7 +418,7 @@
- .. index:: single: _ (underscore); in string formatting
-
- The ``'_'`` option signals the use of an underscore for a thousands
--separator for floating point presentation types and for integer
-+separator for floating-point presentation types and for integer
- presentation type ``'d'``. For integer presentation types ``'b'``,
- ``'o'``, ``'x'``, and ``'X'``, underscores will be inserted every 4
- digits. For other presentation types, specifying this option is an
-@@ -491,9 +491,9 @@
- +---------+----------------------------------------------------------+
-
- In addition to the above presentation types, integers can be formatted
--with the floating point presentation types listed below (except
-+with the floating-point presentation types listed below (except
- ``'n'`` and ``None``). When doing so, :func:`float` is used to convert the
--integer to a floating point number before formatting.
-+integer to a floating-point number before formatting.
-
- The available presentation types for :class:`float` and
- :class:`~decimal.Decimal` values are:
-diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst
-index 346784d86e3..29bce521ee1 100644
---- a/Doc/library/struct.rst
-+++ b/Doc/library/struct.rst
-@@ -275,9 +275,9 @@
- (1)
- .. index:: single: ? (question mark); in struct format strings
-
-- The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type defined by
-- C99. If this type is not available, it is simulated using a :c:expr:`char`. In
-- standard mode, it is always represented by one byte.
-+ The ``'?'`` conversion code corresponds to the :c:expr:`_Bool` type
-+ defined by C standards since C99. In standard mode, it is
-+ represented by one byte.
-
- (2)
- When attempting to pack a non-integer using any of the integer conversion
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
-index 33f96a2f744..b03db8f3e0a 100644
+index 755ff4c6f0f..b03db8f3e0a 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -25,7 +25,7 @@
@@ -9166,128 +773,6 @@ index 33f96a2f744..b03db8f3e0a 100644
Using the :mod:`subprocess` Module
----------------------------------
-@@ -608,7 +608,7 @@
-
- If *group* is not ``None``, the setregid() system call will be made in the
- child process prior to the execution of the subprocess. If the provided
-- value is a string, it will be looked up via :func:`grp.getgrnam()` and
-+ value is a string, it will be looked up via :func:`grp.getgrnam` and
- the value in ``gr_gid`` will be used. If the value is an integer, it
- will be passed verbatim. (POSIX only)
-
-@@ -618,7 +618,7 @@
- If *extra_groups* is not ``None``, the setgroups() system call will be
- made in the child process prior to the execution of the subprocess.
- Strings provided in *extra_groups* will be looked up via
-- :func:`grp.getgrnam()` and the values in ``gr_gid`` will be used.
-+ :func:`grp.getgrnam` and the values in ``gr_gid`` will be used.
- Integer values will be passed verbatim. (POSIX only)
-
- .. availability:: POSIX
-@@ -626,7 +626,7 @@
-
- If *user* is not ``None``, the setreuid() system call will be made in the
- child process prior to the execution of the subprocess. If the provided
-- value is a string, it will be looked up via :func:`pwd.getpwnam()` and
-+ value is a string, it will be looked up via :func:`pwd.getpwnam` and
- the value in ``pw_uid`` will be used. If the value is an integer, it will
- be passed verbatim. (POSIX only)
-
-@@ -1110,7 +1110,7 @@
- .. data:: NORMAL_PRIORITY_CLASS
-
- A :class:`Popen` ``creationflags`` parameter to specify that a new process
-- will have an normal priority. (default)
-+ will have a normal priority. (default)
-
- .. versionadded:: 3.7
-
-diff --git a/Doc/library/symtable.rst b/Doc/library/symtable.rst
-index fc2d79b77cf..de9a961592a 100644
---- a/Doc/library/symtable.rst
-+++ b/Doc/library/symtable.rst
-@@ -127,8 +127,39 @@
-
- .. method:: get_methods()
-
-- Return a tuple containing the names of methods declared in the class.
--
-+ Return a tuple containing the names of method-like functions declared
-+ in the class.
-+
-+ Here, the term 'method' designates *any* function defined in the class
-+ body via :keyword:`def` or :keyword:`async def`.
-+
-+ Functions defined in a deeper scope (e.g., in an inner class) are not
-+ picked up by :meth:`get_methods`.
-+
-+ For example:
-+
-+ >>> import symtable
-+ >>> st = symtable.symtable('''
-+ ... def outer(): pass
-+ ...
-+ ... class A:
-+ ... def f():
-+ ... def w(): pass
-+ ...
-+ ... def g(self): pass
-+ ...
-+ ... @classmethod
-+ ... async def h(cls): pass
-+ ...
-+ ... global outer
-+ ... def outer(self): pass
-+ ... ''', 'test', 'exec')
-+ >>> class_A = st.get_children()[1]
-+ >>> class_A.get_methods()
-+ ('f', 'g', 'h')
-+
-+ Although ``A().f()`` raises :exc:`TypeError` at runtime, ``A.f`` is still
-+ considered as a method-like function.
-
- .. class:: Symbol
-
-diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
-index 03f1f309f65..40d0ef80a3f 100644
---- a/Doc/library/sys.rst
-+++ b/Doc/library/sys.rst
-@@ -724,11 +724,11 @@
- regardless of their size. This function is mainly useful for tracking
- and debugging memory leaks. Because of the interpreter's internal
- caches, the result can vary from call to call; you may have to call
-- :func:`_clear_type_cache()` and :func:`gc.collect()` to get more
-+ :func:`_clear_type_cache` and :func:`gc.collect` to get more
- predictable results.
-
- If a Python build or implementation cannot reasonably compute this
-- information, :func:`getallocatedblocks()` is allowed to return 0 instead.
-+ information, :func:`getallocatedblocks` is allowed to return 0 instead.
-
- .. versionadded:: 3.4
-
-diff --git a/Doc/library/sysconfig.rst b/Doc/library/sysconfig.rst
-index 75672913943..aaccc0431d7 100644
---- a/Doc/library/sysconfig.rst
-+++ b/Doc/library/sysconfig.rst
-@@ -305,7 +305,7 @@
- mix with those by the other.
-
- End users should not use this function, but :func:`get_default_scheme` and
-- :func:`get_preferred_scheme()` instead.
-+ :func:`get_preferred_scheme` instead.
-
- .. versionadded:: 3.10
-
-@@ -376,7 +376,7 @@
-
- This is used mainly to distinguish platform-specific build directories and
- platform-specific built distributions. Typically includes the OS name and
-- version and the architecture (as supplied by 'os.uname()'), although the
-+ version and the architecture (as supplied by :func:`os.uname`), although the
- exact information included depends on the OS; e.g., on Linux, the kernel
- version isn't particularly important.
-
diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst
index 79b808ab63c..332b58413d3 100644
--- a/Doc/library/syslog.rst
@@ -9301,498 +786,8 @@ index 79b808ab63c..332b58413d3 100644
This module wraps the system ``syslog`` family of routines. A pure Python
library that can speak to a syslog server is available in the
-diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst
-index bd745c78823..0352cddb16e 100644
---- a/Doc/library/tarfile.rst
-+++ b/Doc/library/tarfile.rst
-@@ -608,7 +608,7 @@
- it is best practice to only do so in top-level applications or
- :mod:`site configuration `.
- To set a global default this way, a filter function needs to be wrapped in
-- :func:`staticmethod()` to prevent injection of a ``self`` argument.
-+ :func:`staticmethod` to prevent injection of a ``self`` argument.
-
- .. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None)
-
-diff --git a/Doc/library/test.rst b/Doc/library/test.rst
-index 64bf8174478..b11bdb42907 100644
---- a/Doc/library/test.rst
-+++ b/Doc/library/test.rst
-@@ -1695,7 +1695,7 @@
-
- .. function:: check_warnings(*filters, quiet=True)
-
-- A convenience wrapper for :func:`warnings.catch_warnings()` that makes it
-+ A convenience wrapper for :func:`warnings.catch_warnings` that makes it
- easier to test that a warning was correctly raised. It is approximately
- equivalent to calling ``warnings.catch_warnings(record=True)`` with
- :meth:`warnings.simplefilter` set to ``always`` and with the option to
-diff --git a/Doc/library/threading.rst b/Doc/library/threading.rst
-index c88dcabcd91..5d94a7760f9 100644
---- a/Doc/library/threading.rst
-+++ b/Doc/library/threading.rst
-@@ -409,7 +409,7 @@
- timeout occurs.
-
- When the *timeout* argument is present and not ``None``, it should be a
-- floating point number specifying a timeout for the operation in seconds
-+ floating-point number specifying a timeout for the operation in seconds
- (or fractions thereof). As :meth:`~Thread.join` always returns ``None``,
- you must call :meth:`~Thread.is_alive` after :meth:`~Thread.join` to
- decide whether a timeout happened -- if the thread is still alive, the
-@@ -790,7 +790,7 @@
- occurs. Once awakened or timed out, it re-acquires the lock and returns.
-
- When the *timeout* argument is present and not ``None``, it should be a
-- floating point number specifying a timeout for the operation in seconds
-+ floating-point number specifying a timeout for the operation in seconds
- (or fractions thereof).
-
- When the underlying lock is an :class:`RLock`, it is not released using
-@@ -1014,10 +1014,10 @@
- has not expired. The return value represents the
- reason that this blocking method returned; ``True`` if returning because
- the internal flag is set to true, or ``False`` if a timeout is given and
-- the the internal flag did not become true within the given wait time.
-+ the internal flag did not become true within the given wait time.
-
- When the timeout argument is present and not ``None``, it should be a
-- floating point number specifying a timeout for the operation in seconds,
-+ floating-point number specifying a timeout for the operation in seconds,
- or fractions thereof.
-
- .. versionchanged:: 3.1
-diff --git a/Doc/library/time.rst b/Doc/library/time.rst
-index d792d5633dd..188dbca8fd1 100644
---- a/Doc/library/time.rst
-+++ b/Doc/library/time.rst
-@@ -69,7 +69,7 @@
- systems, the clock "ticks" only 50 or 100 times a second.
-
- * On the other hand, the precision of :func:`.time` and :func:`sleep` is better
-- than their Unix equivalents: times are expressed as floating point numbers,
-+ than their Unix equivalents: times are expressed as floating-point numbers,
- :func:`.time` returns the most accurate time available (using Unix
- :c:func:`!gettimeofday` where available), and :func:`sleep` will accept a time
- with a nonzero fraction (Unix :c:func:`!select` is used to implement this, where
-@@ -273,7 +273,7 @@
- This is the inverse function of :func:`localtime`. Its argument is the
- :class:`struct_time` or full 9-tuple (since the dst flag is needed; use ``-1``
- as the dst flag if it is unknown) which expresses the time in *local* time, not
-- UTC. It returns a floating point number, for compatibility with :func:`.time`.
-+ UTC. It returns a floating-point number, for compatibility with :func:`.time`.
- If the input value cannot be represented as a valid time, either
- :exc:`OverflowError` or :exc:`ValueError` will be raised (which depends on
- whether the invalid value is caught by Python or the underlying C libraries).
-@@ -358,7 +358,7 @@
- .. function:: sleep(secs)
-
- Suspend execution of the calling thread for the given number of seconds.
-- The argument may be a floating point number to indicate a more precise sleep
-+ The argument may be a floating-point number to indicate a more precise sleep
- time.
-
- If the sleep is interrupted by a signal and no exception is raised by the
-@@ -642,13 +642,13 @@
-
- .. function:: time() -> float
-
-- Return the time in seconds since the epoch_ as a floating point
-+ Return the time in seconds since the epoch_ as a floating-point
- number. The handling of `leap seconds`_ is platform dependent.
- On Windows and most Unix systems, the leap seconds are not counted towards
- the time in seconds since the epoch_. This is commonly referred to as `Unix
- time `_.
-
-- Note that even though the time is always returned as a floating point
-+ Note that even though the time is always returned as a floating-point
- number, not all systems provide time with a better precision than 1 second.
- While this function normally returns non-decreasing values, it can return a
- lower value than a previous call if the system clock has been set back
-diff --git a/Doc/library/token.rst b/Doc/library/token.rst
-index 9368ced97ab..e27a3b96d8f 100644
---- a/Doc/library/token.rst
-+++ b/Doc/library/token.rst
-@@ -75,7 +75,7 @@
- :noindex:
-
- Token value indicating that a type comment was recognized. Such
-- tokens are only produced when :func:`ast.parse()` is invoked with
-+ tokens are only produced when :func:`ast.parse` is invoked with
- ``type_comments=True``.
-
-
-diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst
-index 85dae82104a..d3f47b9e4fb 100644
---- a/Doc/library/traceback.rst
-+++ b/Doc/library/traceback.rst
-@@ -42,6 +42,14 @@
- :term:`file ` or :term:`file-like object` to
- receive the output.
-
-+ .. note::
-+
-+ The meaning of the *limit* parameter is different than the meaning
-+ of :const:`sys.tracebacklimit`. A negative *limit* value corresponds to
-+ a positive value of :const:`!sys.tracebacklimit`, whereas the behaviour of
-+ a positive *limit* value cannot be achieved with
-+ :const:`!sys.tracebacklimit`.
-+
- .. versionchanged:: 3.5
- Added negative *limit* support.
-
-diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
-index 1a5c21d3c94..446ee6a0ec3 100644
---- a/Doc/library/typing.rst
-+++ b/Doc/library/typing.rst
-@@ -27,12 +27,13 @@
-
- Consider the function below::
-
-- def moon_weight(earth_weight: float) -> str:
-- return f'On the moon, you would weigh {earth_weight * 0.166} kilograms.'
-+ def surface_area_of_cube(edge_length: float) -> str:
-+ return f"The surface area of the cube is {6 * edge_length ** 2}."
-
--The function ``moon_weight`` takes an argument expected to be an instance of :class:`float`,
--as indicated by the *type hint* ``earth_weight: float``. The function is expected to
--return an instance of :class:`str`, as indicated by the ``-> str`` hint.
-+The function ``surface_area_of_cube`` takes an argument expected to
-+be an instance of :class:`float`, as indicated by the :term:`type hint`
-+``edge_length: float``. The function is expected to return an instance
-+of :class:`str`, as indicated by the ``-> str`` hint.
-
- While type hints can be simple classes like :class:`float` or :class:`str`,
- they can also be more complex. The :mod:`typing` module provides a vocabulary of
-@@ -97,8 +98,9 @@
- # The static type checker will treat the previous type signature as
- # being exactly equivalent to this one.
- def broadcast_message(
-- message: str,
-- servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
-+ message: str,
-+ servers: Sequence[tuple[tuple[str, int], dict[str, str]]]
-+ ) -> None:
- ...
-
- The :keyword:`type` statement is new in Python 3.12. For backwards
-@@ -206,7 +208,7 @@
- ===========================
-
- Functions -- or other :term:`callable` objects -- can be annotated using
--:class:`collections.abc.Callable` or :data:`typing.Callable`.
-+:class:`collections.abc.Callable` or deprecated :data:`typing.Callable`.
- ``Callable[[int], str]`` signifies a function that takes a single parameter
- of type :class:`int` and returns a :class:`str`.
-
-@@ -399,7 +401,7 @@
- =========================
-
- A variable annotated with ``C`` may accept a value of type ``C``. In
--contrast, a variable annotated with ``type[C]`` (or
-+contrast, a variable annotated with ``type[C]`` (or deprecated
- :class:`typing.Type[C] `) may accept values that are classes
- themselves -- specifically, it will accept the *class object* of ``C``. For
- example::
-@@ -439,6 +441,72 @@
- ``type[Any]`` is equivalent to :class:`type`, which is the root of Python's
- :ref:`metaclass hierarchy `.
-
-+
-+.. _annotating-generators-and-coroutines:
-+
-+Annotating generators and coroutines
-+====================================
-+
-+A generator can be annotated using the generic type
-+:class:`Generator[YieldType, SendType, ReturnType] `.
-+For example::
-+
-+ def echo_round() -> Generator[int, float, str]:
-+ sent = yield 0
-+ while sent >= 0:
-+ sent = yield round(sent)
-+ return 'Done'
-+
-+Note that unlike many other generic classes in the standard library,
-+the ``SendType`` of :class:`~collections.abc.Generator` behaves
-+contravariantly, not covariantly or invariantly.
-+
-+If your generator will only yield values, set the ``SendType`` and
-+``ReturnType`` to ``None``::
-+
-+ def infinite_stream(start: int) -> Generator[int, None, None]:
-+ while True:
-+ yield start
-+ start += 1
-+
-+Alternatively, annotate your generator as having a return type of
-+either ``Iterable[YieldType]`` or ``Iterator[YieldType]``::
-+
-+ def infinite_stream(start: int) -> Iterator[int]:
-+ while True:
-+ yield start
-+ start += 1
-+
-+Async generators are handled in a similar fashion, but don't
-+expect a ``ReturnType`` type argument
-+(:class:`AsyncGenerator[YieldType, SendType] `)::
-+
-+ async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
-+ while True:
-+ yield start
-+ start = await increment(start)
-+
-+As in the synchronous case,
-+:class:`AsyncIterable[YieldType] `
-+and :class:`AsyncIterator[YieldType] ` are
-+available as well::
-+
-+ async def infinite_stream(start: int) -> AsyncIterator[int]:
-+ while True:
-+ yield start
-+ start = await increment(start)
-+
-+Coroutines can be annotated using
-+:class:`Coroutine[YieldType, SendType, ReturnType] `.
-+Generic arguments correspond to those of :class:`~collections.abc.Generator`,
-+for example::
-+
-+ from collections.abc import Coroutine
-+ c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
-+ x = c.send('hi') # Inferred type of 'x' is list[str]
-+ async def bar() -> None:
-+ y = await c # Inferred type of 'y' is int
-+
- .. _user-defined-generics:
-
- User-defined generic types
-@@ -1394,8 +1462,8 @@
- print("Not a list of strings!")
-
- If ``is_str_list`` is a class or instance method, then the type in
-- ``TypeGuard`` maps to the type of the second parameter after ``cls`` or
-- ``self``.
-+ ``TypeGuard`` maps to the type of the second parameter (after ``cls`` or
-+ ``self``).
-
- In short, the form ``def foo(arg: TypeA) -> TypeGuard[TypeB]: ...``,
- means that if ``foo(arg)`` returns ``True``, then ``arg`` narrows from
-@@ -1749,8 +1817,8 @@
- of ``*args``::
-
- def call_soon[*Ts](
-- callback: Callable[[*Ts], None],
-- *args: *Ts
-+ callback: Callable[[*Ts], None],
-+ *args: *Ts
- ) -> None:
- ...
- callback(*args)
-@@ -3071,14 +3139,9 @@
- Deprecated alias to :class:`dict`.
-
- Note that to annotate arguments, it is preferred
-- to use an abstract collection type such as :class:`Mapping`
-+ to use an abstract collection type such as :class:`~collections.abc.Mapping`
- rather than to use :class:`dict` or :class:`!typing.Dict`.
-
-- This type can be used as follows::
--
-- def count_words(text: str) -> Dict[str, int]:
-- ...
--
- .. deprecated:: 3.9
- :class:`builtins.dict ` now supports subscripting (``[]``).
- See :pep:`585` and :ref:`types-genericalias`.
-@@ -3088,16 +3151,9 @@
- Deprecated alias to :class:`list`.
-
- Note that to annotate arguments, it is preferred
-- to use an abstract collection type such as :class:`Sequence` or
-- :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`.
--
-- This type may be used as follows::
--
-- def vec2[T: (int, float)](x: T, y: T) -> List[T]:
-- return [x, y]
--
-- def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]:
-- return [item for item in vector if item > 0]
-+ to use an abstract collection type such as
-+ :class:`~collections.abc.Sequence` or :class:`~collections.abc.Iterable`
-+ rather than to use :class:`list` or :class:`!typing.List`.
-
- .. deprecated:: 3.9
- :class:`builtins.list ` now supports subscripting (``[]``).
-@@ -3108,8 +3164,8 @@
- Deprecated alias to :class:`builtins.set `.
-
- Note that to annotate arguments, it is preferred
-- to use an abstract collection type such as :class:`AbstractSet`
-- rather than to use :class:`set` or :class:`!typing.Set`.
-+ to use an abstract collection type such as :class:`collections.abc.Set`
-+ rather than to use :class:`set` or :class:`typing.Set`.
-
- .. deprecated:: 3.9
- :class:`builtins.set ` now supports subscripting (``[]``).
-@@ -3313,11 +3369,6 @@
-
- Deprecated alias to :class:`collections.abc.Mapping`.
-
-- This type can be used as follows::
--
-- def get_position_in_index(word_list: Mapping[str, int], word: str) -> int:
-- return word_list[word]
--
- .. deprecated:: 3.9
- :class:`collections.abc.Mapping` now supports subscripting (``[]``).
- See :pep:`585` and :ref:`types-genericalias`.
-@@ -3381,14 +3432,9 @@
-
- Deprecated alias to :class:`collections.abc.Coroutine`.
-
-- The variance and order of type variables
-- correspond to those of :class:`Generator`, for example::
--
-- from collections.abc import Coroutine
-- c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
-- x = c.send('hi') # Inferred type of 'x' is list[str]
-- async def bar() -> None:
-- y = await c # Inferred type of 'y' is int
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`collections.abc.Coroutine`
-+ and ``typing.Coroutine`` in type annotations.
-
- .. versionadded:: 3.5.3
-
-@@ -3400,34 +3446,9 @@
-
- Deprecated alias to :class:`collections.abc.AsyncGenerator`.
-
-- An async generator can be annotated by the generic type
-- ``AsyncGenerator[YieldType, SendType]``. For example::
--
-- async def echo_round() -> AsyncGenerator[int, float]:
-- sent = yield 0
-- while sent >= 0.0:
-- rounded = await round(sent)
-- sent = yield rounded
--
-- Unlike normal generators, async generators cannot return a value, so there
-- is no ``ReturnType`` type parameter. As with :class:`Generator`, the
-- ``SendType`` behaves contravariantly.
--
-- If your generator will only yield values, set the ``SendType`` to
-- ``None``::
--
-- async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
-- while True:
-- yield start
-- start = await increment(start)
--
-- Alternatively, annotate your generator as having a return type of
-- either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``::
--
-- async def infinite_stream(start: int) -> AsyncIterator[int]:
-- while True:
-- yield start
-- start = await increment(start)
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`collections.abc.AsyncGenerator`
-+ and ``typing.AsyncGenerator`` in type annotations.
-
- .. versionadded:: 3.6.1
-
-@@ -3506,34 +3527,9 @@
-
- Deprecated alias to :class:`collections.abc.Generator`.
-
-- A generator can be annotated by the generic type
-- ``Generator[YieldType, SendType, ReturnType]``. For example::
--
-- def echo_round() -> Generator[int, float, str]:
-- sent = yield 0
-- while sent >= 0:
-- sent = yield round(sent)
-- return 'Done'
--
-- Note that unlike many other generics in the typing module, the ``SendType``
-- of :class:`Generator` behaves contravariantly, not covariantly or
-- invariantly.
--
-- If your generator will only yield values, set the ``SendType`` and
-- ``ReturnType`` to ``None``::
--
-- def infinite_stream(start: int) -> Generator[int, None, None]:
-- while True:
-- yield start
-- start += 1
--
-- Alternatively, annotate your generator as having a return type of
-- either ``Iterable[YieldType]`` or ``Iterator[YieldType]``::
--
-- def infinite_stream(start: int) -> Iterator[int]:
-- while True:
-- yield start
-- start += 1
-+ See :ref:`annotating-generators-and-coroutines`
-+ for details on using :class:`collections.abc.Generator`
-+ and ``typing.Generator`` in type annotations.
-
- .. deprecated:: 3.9
- :class:`collections.abc.Generator` now supports subscripting (``[]``).
-diff --git a/Doc/library/unittest.mock.rst b/Doc/library/unittest.mock.rst
-index 8dcb8c2aa54..1fbef02a2c6 100644
---- a/Doc/library/unittest.mock.rst
-+++ b/Doc/library/unittest.mock.rst
-@@ -856,6 +856,20 @@
- 3
- >>> p.assert_called_once_with()
-
-+.. caution::
-+
-+ If an :exc:`AttributeError` is raised by :class:`PropertyMock`,
-+ it will be interpreted as a missing descriptor and
-+ :meth:`~object.__getattr__` will be called on the parent mock::
-+
-+ >>> m = MagicMock()
-+ >>> no_attribute = PropertyMock(side_effect=AttributeError)
-+ >>> type(m).my_property = no_attribute
-+ >>> m.my_property
-+
-+
-+ See :meth:`~object.__getattr__` for details.
-+
-
- .. class:: AsyncMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)
-
-diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
-index 68a8ddee0f2..54ea8bb40df 100644
---- a/Doc/library/unittest.rst
-+++ b/Doc/library/unittest.rst
-@@ -2308,8 +2308,8 @@
- (see :ref:`Warning control `),
- otherwise it will be set to ``'default'``.
-
-- Calling ``main`` actually returns an instance of the ``TestProgram`` class.
-- This stores the result of the tests run as the ``result`` attribute.
-+ Calling ``main`` returns an object with the ``result`` attribute that contains
-+ the result of the tests run as a :class:`unittest.TestResult`.
-
- .. versionchanged:: 3.1
- The *exit* parameter was added.
-@@ -2521,7 +2521,7 @@
- .. versionadded:: 3.2
-
- The :option:`-c/--catch ` command-line option to unittest,
--along with the ``catchbreak`` parameter to :func:`unittest.main()`, provide
-+along with the ``catchbreak`` parameter to :func:`unittest.main`, provide
- more friendly handling of control-C during a test run. With catch break
- behavior enabled control-C will allow the currently running test to complete,
- and the test run will then end and report all the results so far. A second
diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst
-index cd402e87a82..fb5353e1895 100644
+index 27909b763e9..fb5353e1895 100644
--- a/Doc/library/urllib.parse.rst
+++ b/Doc/library/urllib.parse.rst
@@ -22,11 +22,19 @@
@@ -9816,46 +811,6 @@ index cd402e87a82..fb5353e1895 100644
The :mod:`urllib.parse` module defines functions that fall into two broad
categories: URL parsing and URL quoting. These are covered in detail in
the following sections.
-@@ -173,7 +181,7 @@
- Added IPv6 URL parsing capabilities.
-
- .. versionchanged:: 3.3
-- The fragment is now parsed for all URL schemes (unless *allow_fragment* is
-+ The fragment is now parsed for all URL schemes (unless *allow_fragments* is
- false), in accordance with :rfc:`3986`. Previously, an allowlist of
- schemes that support fragments existed.
-
-diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst
-index 8705adfb892..d7de8a16438 100644
---- a/Doc/library/urllib.request.rst
-+++ b/Doc/library/urllib.request.rst
-@@ -252,7 +252,7 @@
-
- *method* should be a string that indicates the HTTP request method that
- will be used (e.g. ``'HEAD'``). If provided, its value is stored in the
-- :attr:`~Request.method` attribute and is used by :meth:`get_method()`.
-+ :attr:`~Request.method` attribute and is used by :meth:`get_method`.
- The default is ``'GET'`` if *data* is ``None`` or ``'POST'`` otherwise.
- Subclasses may indicate a different default method by setting the
- :attr:`~Request.method` attribute in the class itself.
-@@ -1103,7 +1103,7 @@
-
- .. versionchanged:: 3.2
- This method is applicable only for local hostnames. When a remote
-- hostname is given, an :exc:`~urllib.error.URLError` is raised.
-+ hostname is given, a :exc:`~urllib.error.URLError` is raised.
-
-
- .. _data-handler-objects:
-@@ -1118,7 +1118,7 @@
- ignores white spaces in base64 encoded data URLs so the URL may be wrapped
- in whatever source file it comes from. But even though some browsers don't
- mind about a missing padding at the end of a base64 encoded data URL, this
-- implementation will raise an :exc:`ValueError` in that case.
-+ implementation will raise a :exc:`ValueError` in that case.
-
-
- .. _ftp-handler-objects:
diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst
index 57b0ee7157c..c24945169e8 100644
--- a/Doc/library/venv.rst
@@ -9869,36 +824,8 @@ index 57b0ee7157c..c24945169e8 100644
Creating virtual environments
-----------------------------
-diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst
-index ba0ed23b4e6..454f05419ab 100644
---- a/Doc/library/wave.rst
-+++ b/Doc/library/wave.rst
-@@ -46,8 +46,8 @@
- the file object.
-
- The :func:`.open` function may be used in a :keyword:`with` statement. When
-- the :keyword:`!with` block completes, the :meth:`Wave_read.close()` or
-- :meth:`Wave_write.close()` method is called.
-+ the :keyword:`!with` block completes, the :meth:`Wave_read.close` or
-+ :meth:`Wave_write.close` method is called.
-
- .. versionchanged:: 3.4
- Added support for unseekable files.
-diff --git a/Doc/library/weakref.rst b/Doc/library/weakref.rst
-index d6e062df945..2a25ed045c6 100644
---- a/Doc/library/weakref.rst
-+++ b/Doc/library/weakref.rst
-@@ -197,7 +197,7 @@
- >>> del k1 # d = {k2: 2}
-
- .. versionchanged:: 3.9
-- Added support for ``|`` and ``|=`` operators, specified in :pep:`584`.
-+ Added support for ``|`` and ``|=`` operators, as specified in :pep:`584`.
-
- :class:`WeakKeyDictionary` objects have an additional method that
- exposes the internal references directly. The references are not guaranteed to
diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst
-index df22c5f5e1e..2fed2e817e8 100644
+index c34b2170f8f..2fed2e817e8 100644
--- a/Doc/library/webbrowser.rst
+++ b/Doc/library/webbrowser.rst
@@ -33,6 +33,13 @@
@@ -9915,33 +842,7 @@ index df22c5f5e1e..2fed2e817e8 100644
The script :program:`webbrowser` can be used as a command-line interface for the
module. It accepts a URL as the argument. It accepts the following optional
parameters: ``-n`` opens the URL in a new browser window, if possible;
-@@ -62,6 +69,8 @@
- (note that under many window managers this will occur regardless of the
- setting of this variable).
-
-+ Returns ``True`` if a browser was successfully launched, ``False`` otherwise.
-+
- Note that on some platforms, trying to open a filename using this function,
- may work and start the operating system's associated program. However, this
- is neither supported nor portable.
-@@ -74,11 +83,16 @@
- Open *url* in a new window of the default browser, if possible, otherwise, open
- *url* in the only browser window.
-
-+ Returns ``True`` if a browser was successfully launched, ``False`` otherwise.
-+
-+
- .. function:: open_new_tab(url)
-
- Open *url* in a new page ("tab") of the default browser, if possible, otherwise
- equivalent to :func:`open_new`.
-
-+ Returns ``True`` if a browser was successfully launched, ``False`` otherwise.
-+
-
- .. function:: get(using=None)
-
-@@ -147,6 +161,8 @@
+@@ -154,6 +161,8 @@
+------------------------+-----------------------------------------+-------+
| ``'chromium-browser'`` | :class:`Chromium('chromium-browser')` | |
+------------------------+-----------------------------------------+-------+
@@ -9950,7 +851,7 @@ index df22c5f5e1e..2fed2e817e8 100644
Notes:
-@@ -161,7 +177,11 @@
+@@ -168,7 +177,11 @@
Only on Windows platforms.
(3)
@@ -9963,7 +864,7 @@ index df22c5f5e1e..2fed2e817e8 100644
.. versionadded:: 3.3
Support for Chrome/Chromium has been added.
-@@ -174,6 +194,9 @@
+@@ -181,6 +194,9 @@
.. deprecated-removed:: 3.11 3.13
:class:`MacOSX` is deprecated, use :class:`MacOSXOSAScript` instead.
@@ -9973,1839 +874,11 @@ index df22c5f5e1e..2fed2e817e8 100644
Here are some simple examples::
url = 'https://docs.python.org/'
-diff --git a/Doc/library/xml.etree.elementtree.rst b/Doc/library/xml.etree.elementtree.rst
-index 2fedd99e8be..c3c577bc351 100644
---- a/Doc/library/xml.etree.elementtree.rst
-+++ b/Doc/library/xml.etree.elementtree.rst
-@@ -508,7 +508,7 @@
- `C14N 2.0 `_ transformation function.
-
- Canonicalization is a way to normalise XML output in a way that allows
-- byte-by-byte comparisons and digital signatures. It reduced the freedom
-+ byte-by-byte comparisons and digital signatures. It reduces the freedom
- that XML serializers have and instead generates a more constrained XML
- representation. The main restrictions regard the placement of namespace
- declarations, the ordering of attributes, and ignorable whitespace.
-@@ -869,6 +869,7 @@
-
- .. module:: xml.etree.ElementTree
- :noindex:
-+ :no-index:
-
- .. class:: Element(tag, attrib={}, **extra)
-
-@@ -965,7 +966,7 @@
-
- .. method:: extend(subelements)
-
-- Appends *subelements* from a sequence object with zero or more elements.
-+ Appends *subelements* from an iterable of elements.
- Raises :exc:`TypeError` if a subelement is not an :class:`Element`.
-
- .. versionadded:: 3.2
-@@ -1053,9 +1054,10 @@
- :meth:`~object.__getitem__`, :meth:`~object.__setitem__`,
- :meth:`~object.__len__`.
-
-- Caution: Elements with no subelements will test as ``False``. Testing the
-- truth value of an Element is deprecated and will raise an exception in
-- Python 3.14. Use specific ``len(elem)`` or ``elem is None`` test instead.::
-+ Caution: Elements with no subelements will test as ``False``. In a future
-+ release of Python, all elements will test as ``True`` regardless of whether
-+ subelements exist. Instead, prefer explicit ``len(elem)`` or
-+ ``elem is not None`` tests.::
-
- element = root.find('foo')
-
-diff --git a/Doc/library/zipapp.rst b/Doc/library/zipapp.rst
-index cf561b454e9..cdaba07ab46 100644
---- a/Doc/library/zipapp.rst
-+++ b/Doc/library/zipapp.rst
-@@ -332,7 +332,7 @@
- interpreter name, and then a newline (``b'\n'``) character. The interpreter
- name can be anything acceptable to the OS "shebang" processing, or the Python
- launcher on Windows. The interpreter should be encoded in UTF-8 on Windows,
-- and in :func:`sys.getfilesystemencoding()` on POSIX.
-+ and in :func:`sys.getfilesystemencoding` on POSIX.
- 2. Standard zipfile data, as generated by the :mod:`zipfile` module. The
- zipfile content *must* include a file called ``__main__.py`` (which must be
- in the "root" of the zipfile - i.e., it cannot be in a subdirectory). The
-diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst
-index 374404bf33a..b757cf6bee3 100644
---- a/Doc/reference/compound_stmts.rst
-+++ b/Doc/reference/compound_stmts.rst
-@@ -245,13 +245,12 @@
- until one is found that matches the exception.
- An expression-less :keyword:`!except` clause, if present, must be last;
- it matches any exception.
--For an :keyword:`!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 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.
-+
-+For an :keyword:`!except` clause with an expression, the
-+expression must evaluate to an exception type or a tuple of exception types.
-+The raised exception matches an :keyword:`!except` clause whose expression evaluates
-+to the class or a :term:`non-virtual base class ` of the exception object,
-+or to a tuple that contains such a class.
-
- If no :keyword:`!except` clause matches the exception,
- the search for an exception handler
-@@ -378,8 +377,10 @@
- ...
- ExceptionGroup('', (BlockingIOError()))
-
--An :keyword:`!except*` clause must have a matching type,
--and this type cannot be a subclass of :exc:`BaseExceptionGroup`.
-+An :keyword:`!except*` clause must have a matching expression; it cannot be ``except*:``.
-+Furthermore, this expression cannot contain exception group types, because that would
-+have ambiguous semantics.
-+
- It is not possible to mix :keyword:`except` and :keyword:`!except*`
- in the same :keyword:`try`.
- :keyword:`break`, :keyword:`continue` and :keyword:`return`
-@@ -840,7 +841,7 @@
- : | "None"
- : | "True"
- : | "False"
-- : | `signed_number`: NUMBER | "-" NUMBER
-+ signed_number: ["-"] NUMBER
-
- The rule ``strings`` and the token ``NUMBER`` are defined in the
- :doc:`standard Python grammar <./grammar>`. Triple-quoted strings are
-diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
-index 602014deeba..7cff9545dd2 100644
---- a/Doc/reference/datamodel.rst
-+++ b/Doc/reference/datamodel.rst
-@@ -106,12 +106,16 @@
- Types affect almost all aspects of object behavior. Even the importance of
- object identity is affected in some sense: for immutable types, operations that
- compute new values may actually return a reference to any existing object with
--the same type and value, while for mutable objects this is not allowed. E.g.,
--after ``a = 1; b = 1``, ``a`` and ``b`` may or may not refer to the same object
--with the value one, depending on the implementation, but after ``c = []; d =
--[]``, ``c`` and ``d`` are guaranteed to refer to two different, unique, newly
--created empty lists. (Note that ``c = d = []`` assigns the same object to both
--``c`` and ``d``.)
-+the same type and value, while for mutable objects this is not allowed.
-+For example, after ``a = 1; b = 1``, *a* and *b* may or may not refer to
-+the same object with the value one, depending on the implementation.
-+This is because :class:`int` is an immutable type, so the reference to ``1``
-+can be reused. This behaviour depends on the implementation used, so should
-+not be relied upon, but is something to be aware of when making use of object
-+identity tests.
-+However, after ``c = []; d = []``, *c* and *d* are guaranteed to refer to two
-+different, unique, newly created empty lists. (Note that ``e = f = []`` assigns
-+the *same* object to both *e* and *f*.)
-
-
- .. _types:
-@@ -215,7 +219,7 @@
-
- * A sign is shown only when the number is negative.
-
--Python distinguishes between integers, floating point numbers, and complex
-+Python distinguishes between integers, floating-point numbers, and complex
- numbers:
-
-
-@@ -259,18 +263,18 @@
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- .. index::
-- pair: object; floating point
-- pair: floating point; number
-+ pair: object; floating-point
-+ pair: floating-point; number
- pair: C; language
- pair: Java; language
-
--These represent machine-level double precision floating point numbers. You are
-+These represent machine-level double precision floating-point numbers. You are
- at the mercy of the underlying machine architecture (and C or Java
- implementation) for the accepted range and handling of overflow. Python does not
--support single-precision floating point numbers; the savings in processor and
-+support single-precision floating-point numbers; the savings in processor and
- memory usage that are usually the reason for using these are dwarfed by the
- overhead of using objects in Python, so there is no reason to complicate the
--language with two kinds of floating point numbers.
-+language with two kinds of floating-point numbers.
-
-
- :class:`numbers.Complex` (:class:`complex`)
-@@ -281,7 +285,7 @@
- pair: complex; number
-
- These represent complex numbers as a pair of machine-level double precision
--floating point numbers. The same caveats apply as for floating point numbers.
-+floating-point numbers. The same caveats apply as for floating-point numbers.
- The real and imaginary parts of a complex number ``z`` can be retrieved through
- the read-only attributes ``z.real`` and ``z.imag``.
-
-@@ -373,7 +377,7 @@
-
- A bytes object is an immutable array. The items are 8-bit bytes,
- represented by integers in the range 0 <= x < 256. Bytes literals
-- (like ``b'abc'``) and the built-in :func:`bytes()` constructor
-+ (like ``b'abc'``) and the built-in :func:`bytes` constructor
- can be used to create bytes objects. Also, bytes objects can be
- decoded to strings via the :meth:`~bytes.decode` method.
-
-@@ -492,7 +496,7 @@
- Replacing an existing key does not change the order, however removing a key
- and re-inserting it will add it to the end instead of keeping its old place.
-
--Dictionaries are mutable; they can be created by the ``{...}`` notation (see
-+Dictionaries are mutable; they can be created by the ``{}`` notation (see
- section :ref:`dict`).
-
- .. index::
-@@ -727,14 +731,7 @@
- itself, so that calling either ``x.f(1)`` or ``C.f(1)`` is equivalent to
- calling ``f(C,1)`` where ``f`` is the underlying function.
-
--Note that the transformation from :ref:`function object `
--to instance method
--object happens each time the attribute is retrieved from the instance. In
--some cases, a fruitful optimization is to assign the attribute to a local
--variable and call that local variable. Also notice that this
--transformation only happens for user-defined functions; other callable
--objects (and all non-callable objects) are retrieved without
--transformation. It is also important to note that user-defined functions
-+It is important to note that user-defined functions
- which are attributes of a class instance are not converted to bound
- methods; this *only* happens when the function is an attribute of the
- class.
-@@ -1643,6 +1640,8 @@
-
- It is not guaranteed that :meth:`__del__` methods are called for objects
- that still exist when the interpreter exits.
-+ :class:`weakref.finalize` provides a straightforward way to register
-+ a cleanup function to be called when an object is garbage collected.
-
- .. note::
-
-diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
-index 38f00ae2aa0..b38eadfaf30 100644
---- a/Doc/reference/expressions.rst
-+++ b/Doc/reference/expressions.rst
-@@ -33,7 +33,7 @@
-
- * If either argument is a complex number, the other is converted to complex;
-
--* otherwise, if either argument is a floating point number, the other is
-+* otherwise, if either argument is a floating-point number, the other is
- converted to floating point;
-
- * otherwise, both must be integers and no conversion is necessary.
-@@ -83,18 +83,47 @@
- pair: name; mangling
- pair: private; names
-
--**Private name mangling:** When an identifier that textually occurs in a class
--definition begins with two or more underscore characters and does not end in two
--or more underscores, it is considered a :dfn:`private name` of that class.
--Private names are transformed to a longer form before code is generated for
--them. The transformation inserts the class name, with leading underscores
--removed and a single underscore inserted, in front of the name. For example,
--the identifier ``__spam`` occurring in a class named ``Ham`` will be transformed
--to ``_Ham__spam``. This transformation is independent of the syntactical
--context in which the identifier is used. If the transformed name is extremely
--long (longer than 255 characters), implementation defined truncation may happen.
--If the class name consists only of underscores, no transformation is done.
-+Private name mangling
-+^^^^^^^^^^^^^^^^^^^^^
-
-+When an identifier that textually occurs in a class definition begins with two
-+or more underscore characters and does not end in two or more underscores, it
-+is considered a :dfn:`private name` of that class.
-+
-+.. seealso::
-+
-+ The :ref:`class specifications `.
-+
-+More precisely, private names are transformed to a longer form before code is
-+generated for them. If the transformed name is longer than 255 characters,
-+implementation-defined truncation may happen.
-+
-+The transformation is independent of the syntactical context in which the
-+identifier is used but only the following private identifiers are mangled:
-+
-+- Any name used as the name of a variable that is assigned or read or any
-+ name of an attribute being accessed.
-+
-+ The ``__name__`` attribute of nested functions, classes, and type aliases
-+ is however not mangled.
-+
-+- The name of imported modules, e.g., ``__spam`` in ``import __spam``.
-+ If the module is part of a package (i.e., its name contains a dot),
-+ the name is *not* mangled, e.g., the ``__foo`` in ``import __foo.bar``
-+ is not mangled.
-+
-+- The name of an imported member, e.g., ``__f`` in ``from spam import __f``.
-+
-+The transformation rule is defined as follows:
-+
-+- The class name, with leading underscores removed and a single leading
-+ underscore inserted, is inserted in front of the identifier, e.g., the
-+ identifier ``__spam`` occurring in a class named ``Foo``, ``_Foo`` or
-+ ``__Foo`` is transformed to ``_Foo__spam``.
-+
-+- If the class name consists only of underscores, the transformation is the
-+ identity, e.g., the identifier ``__spam`` occurring in a class named ``_``
-+ or ``__`` is left as is.
-
- .. _atom-literals:
-
-@@ -110,8 +139,8 @@
- : | `integer` | `floatnumber` | `imagnumber`
-
- Evaluation of a literal yields an object of the given type (string, bytes,
--integer, floating point number, complex number) with the given value. The value
--may be approximated in the case of floating point and imaginary (complex)
-+integer, floating-point number, complex number) with the given value. The value
-+may be approximated in the case of floating-point and imaginary (complex)
- literals. See section :ref:`literals` for details.
-
- .. index::
-@@ -218,10 +247,12 @@
- :keyword:`!for` or :keyword:`!async for` clause following the leading
- expression, may contain additional :keyword:`!for` or :keyword:`!async for`
- clauses, and may also use :keyword:`await` expressions.
--If a comprehension contains either :keyword:`!async for` clauses or
--:keyword:`!await` expressions or other asynchronous comprehensions it is called
--an :dfn:`asynchronous comprehension`. An asynchronous comprehension may
--suspend the execution of the coroutine function in which it appears.
-+
-+If a comprehension contains :keyword:`!async for` clauses, or if it contains
-+:keyword:`!await` expressions or other asynchronous comprehensions anywhere except
-+the iterable expression in the leftmost :keyword:`!for` clause, it is called an
-+:dfn:`asynchronous comprehension`. An asynchronous comprehension may suspend the
-+execution of the coroutine function in which it appears.
- See also :pep:`530`.
-
- .. versionadded:: 3.6
-@@ -734,7 +765,7 @@
- .. coroutinemethod:: agen.asend(value)
-
- Returns an awaitable which when run resumes the execution of the
-- asynchronous generator. As with the :meth:`~generator.send()` method for a
-+ asynchronous generator. As with the :meth:`~generator.send` method for a
- generator, this "sends" a value into the asynchronous generator function,
- and the *value* argument becomes the result of the current yield expression.
- The awaitable returned by the :meth:`asend` method will return the next
-@@ -1204,7 +1235,8 @@
- Raising a negative number to a fractional power results in a :class:`complex`
- number. (In earlier versions it raised a :exc:`ValueError`.)
-
--This operation can be customized using the special :meth:`~object.__pow__` method.
-+This operation can be customized using the special :meth:`~object.__pow__` and
-+:meth:`~object.__rpow__` methods.
-
- .. _unary:
-
-@@ -1292,6 +1324,9 @@
- The ``@`` (at) operator is intended to be used for matrix multiplication. No
- builtin Python types implement this operator.
-
-+This operation can be customized using the special :meth:`~object.__matmul__` and
-+:meth:`~object.__rmatmul__` methods.
-+
- .. versionadded:: 3.5
-
- .. index::
-@@ -1307,8 +1342,10 @@
- applied to the result. Division by zero raises the :exc:`ZeroDivisionError`
- exception.
-
--This operation can be customized using the special :meth:`~object.__truediv__` and
--:meth:`~object.__floordiv__` methods.
-+The division operation can be customized using the special :meth:`~object.__truediv__`
-+and :meth:`~object.__rtruediv__` methods.
-+The floor division operation can be customized using the special
-+:meth:`~object.__floordiv__` and :meth:`~object.__rfloordiv__` methods.
-
- .. index::
- single: modulo
-@@ -1317,7 +1354,7 @@
- The ``%`` (modulo) operator yields the remainder from the division of the first
- argument by the second. The numeric arguments are first converted to a common
- type. A zero right argument raises the :exc:`ZeroDivisionError` exception. The
--arguments may be floating point numbers, e.g., ``3.14%0.7`` equals ``0.34``
-+arguments may be floating-point numbers, e.g., ``3.14%0.7`` equals ``0.34``
- (since ``3.14`` equals ``4*0.7 + 0.34``.) The modulo operator always yields a
- result with the same sign as its second operand (or zero); the absolute value of
- the result is strictly smaller than the absolute value of the second operand
-@@ -1333,11 +1370,12 @@
- known as interpolation). The syntax for string formatting is described in the
- Python Library Reference, section :ref:`old-string-formatting`.
-
--The *modulo* operation can be customized using the special :meth:`~object.__mod__` method.
-+The *modulo* operation can be customized using the special :meth:`~object.__mod__`
-+and :meth:`~object.__rmod__` methods.
-
- The floor division operator, the modulo operator, and the :func:`divmod`
--function are not defined for complex numbers. Instead, convert to a floating
--point number using the :func:`abs` function if appropriate.
-+function are not defined for complex numbers. Instead, convert to a
-+floating-point number using the :func:`abs` function if appropriate.
-
- .. index::
- single: addition
-@@ -1360,7 +1398,8 @@
- The ``-`` (subtraction) operator yields the difference of its arguments. The
- numeric arguments are first converted to a common type.
-
--This operation can be customized using the special :meth:`~object.__sub__` method.
-+This operation can be customized using the special :meth:`~object.__sub__` and
-+:meth:`~object.__rsub__` methods.
-
-
- .. _shifting:
-@@ -1381,8 +1420,10 @@
- These operators accept integers as arguments. They shift the first argument to
- the left or right by the number of bits given by the second argument.
-
--This operation can be customized using the special :meth:`~object.__lshift__` and
--:meth:`~object.__rshift__` methods.
-+The left shift operation can be customized using the special :meth:`~object.__lshift__`
-+and :meth:`~object.__rlshift__` methods.
-+The right shift operation can be customized using the special :meth:`~object.__rshift__`
-+and :meth:`~object.__rrshift__` methods.
-
- .. index:: pair: exception; ValueError
-
-diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst
-index f8c9724114d..7de995b1270 100644
---- a/Doc/reference/import.rst
-+++ b/Doc/reference/import.rst
-@@ -281,7 +281,7 @@
- searches :data:`sys.meta_path`, which contains a list of meta path finder
- objects. These finders are queried in order to see if they know how to handle
- the named module. Meta path finders must implement a method called
--:meth:`~importlib.abc.MetaPathFinder.find_spec()` which takes three arguments:
-+:meth:`~importlib.abc.MetaPathFinder.find_spec` which takes three arguments:
- a name, an import path, and (optionally) a target module. The meta path
- finder can use any strategy it wants to determine whether it can handle
- the named module or not.
-@@ -292,7 +292,7 @@
- a spec, then a :exc:`ModuleNotFoundError` is raised. Any other exceptions
- raised are simply propagated up, aborting the import process.
-
--The :meth:`~importlib.abc.MetaPathFinder.find_spec()` method of meta path
-+The :meth:`~importlib.abc.MetaPathFinder.find_spec` method of meta path
- finders is called with two or three arguments. The first is the fully
- qualified name of the module being imported, for example ``foo.bar.baz``.
- The second argument is the path entries to use for the module search. For
-diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst
-index 103d6ef05e4..cfae01ba97a 100644
---- a/Doc/reference/lexical_analysis.rst
-+++ b/Doc/reference/lexical_analysis.rst
-@@ -503,11 +503,10 @@
- single: r"; raw string literal
-
- Both string and bytes literals may optionally be prefixed with a letter ``'r'``
--or ``'R'``; such strings are called :dfn:`raw strings` and treat backslashes as
--literal characters. As a result, in string literals, ``'\U'`` and ``'\u'``
--escapes in raw strings are not treated specially. Given that Python 2.x's raw
--unicode literals behave differently than Python 3.x's the ``'ur'`` syntax
--is not supported.
-+or ``'R'``; such constructs are called :dfn:`raw string literals`
-+and :dfn:`raw bytes literals` respectively and treat backslashes as
-+literal characters. As a result, in raw string literals, ``'\U'`` and ``'\u'``
-+escapes are not treated specially.
-
- .. versionadded:: 3.3
- The ``'rb'`` prefix of raw bytes literals has been added as a synonym
-@@ -879,10 +878,10 @@
- ----------------
-
- .. index:: number, numeric literal, integer literal
-- floating point literal, hexadecimal literal
-+ floating-point literal, hexadecimal literal
- octal literal, binary literal, decimal literal, imaginary literal, complex literal
-
--There are three types of numeric literals: integers, floating point numbers, and
-+There are three types of numeric literals: integers, floating-point numbers, and
- imaginary numbers. There are no complex literals (complex numbers can be formed
- by adding a real number and an imaginary number).
-
-@@ -943,10 +942,10 @@
- single: _ (underscore); in numeric literal
- .. _floating:
-
--Floating point literals
-+Floating-point literals
- -----------------------
-
--Floating point literals are described by the following lexical definitions:
-+Floating-point literals are described by the following lexical definitions:
-
- .. productionlist:: python-grammar
- floatnumber: `pointfloat` | `exponentfloat`
-@@ -958,10 +957,10 @@
-
- Note that the integer and exponent parts are always interpreted using radix 10.
- For example, ``077e010`` is legal, and denotes the same number as ``77e10``. The
--allowed range of floating point literals is implementation-dependent. As in
-+allowed range of floating-point literals is implementation-dependent. As in
- integer literals, underscores are supported for digit grouping.
-
--Some examples of floating point literals::
-+Some examples of floating-point literals::
-
- 3.14 10. .001 1e100 3.14e-10 0e0 3.14_15_93
-
-@@ -982,9 +981,9 @@
- imagnumber: (`floatnumber` | `digitpart`) ("j" | "J")
-
- An imaginary literal yields a complex number with a real part of 0.0. Complex
--numbers are represented as a pair of floating point numbers and have the same
-+numbers are represented as a pair of floating-point numbers and have the same
- restrictions on their range. To create a complex number with a nonzero real
--part, add a floating point number to it, e.g., ``(3+4j)``. Some examples of
-+part, add a floating-point number to it, e.g., ``(3+4j)``. Some examples of
- imaginary literals::
-
- 3.14j 10.j 10j .001j 1e100j 3.14e-10j 3.14_15_93j
-@@ -1019,9 +1018,9 @@
- .. code-block:: none
-
- ( ) [ ] { }
-- , : . ; @ = ->
-- += -= *= /= //= %= @=
-- &= |= ^= >>= <<= **=
-+ , : ! . ; @ =
-+ -> += -= *= /= //= %=
-+ @= &= |= ^= >>= <<= **=
-
- The period can also occur in floating-point and imaginary literals. A sequence
- of three periods has a special meaning as an ellipsis literal. The second half
-diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst
-index a253482156d..618664b23f0 100644
---- a/Doc/reference/simple_stmts.rst
-+++ b/Doc/reference/simple_stmts.rst
-@@ -293,7 +293,7 @@
- operation specific to the type of assignment on the two operands, and assigns
- the result to the original target. The target is only evaluated once.
-
--An augmented assignment expression like ``x += 1`` can be rewritten as ``x = x +
-+An augmented assignment statement like ``x += 1`` can be rewritten as ``x = x +
- 1`` to achieve a similar, but not exactly equal effect. In the augmented
- version, ``x`` is only evaluated once. Also, when possible, the actual operation
- is performed *in-place*, meaning that rather than creating a new object and
-@@ -333,7 +333,9 @@
-
- The difference from normal :ref:`assignment` is that only a single target is allowed.
-
--For simple names as assignment targets, if in class or module scope,
-+The assignment target is considered "simple" if it consists of a single
-+name that is not enclosed in parentheses.
-+For simple assignment targets, if in class or module scope,
- the annotations are evaluated and stored in a special class or module
- attribute :attr:`__annotations__`
- that is a dictionary mapping from variable names (mangled if private) to
-@@ -341,7 +343,8 @@
- created at the start of class or module body execution, if annotations
- are found statically.
-
--For expressions as assignment targets, the annotations are evaluated if
-+If the assignment target is not simple (an attribute, subscript node, or
-+parenthesized name), the annotation is evaluated if
- in class or module scope, but not stored.
-
- If a name is annotated in a function scope, then this name is local for
-diff --git a/Doc/requirements-oldest-sphinx.txt b/Doc/requirements-oldest-sphinx.txt
-index 3ae65bc944d..068fe0cb426 100644
---- a/Doc/requirements-oldest-sphinx.txt
-+++ b/Doc/requirements-oldest-sphinx.txt
-@@ -14,16 +14,16 @@
-
- alabaster==0.7.16
- Babel==2.15.0
--certifi==2024.2.2
-+certifi==2024.7.4
- charset-normalizer==3.3.2
- docutils==0.19
- idna==3.7
- imagesize==1.4.1
- Jinja2==3.1.4
- MarkupSafe==2.1.5
--packaging==24.0
-+packaging==24.1
- Pygments==2.18.0
--requests==2.32.2
-+requests==2.32.3
- snowballstemmer==2.2.0
- Sphinx==6.2.1
- sphinxcontrib-applehelp==1.0.8
-@@ -32,4 +32,4 @@
- sphinxcontrib-jsmath==1.0.1
- sphinxcontrib-qthelp==1.0.7
- sphinxcontrib-serializinghtml==1.1.10
--urllib3==2.2.1
-+urllib3==2.2.2
-diff --git a/Doc/requirements.txt b/Doc/requirements.txt
-index b47a9d8a863..bf1028020b7 100644
---- a/Doc/requirements.txt
-+++ b/Doc/requirements.txt
-@@ -6,12 +6,12 @@
- # Sphinx version is pinned so that new versions that introduce new warnings
- # won't suddenly cause build failures. Updating the version is fine as long
- # as no warnings are raised by doing so.
--sphinx~=7.3.0
-+sphinx~=8.0.0
-
- blurb
-
--sphinxext-opengraph==0.7.5
--sphinx-notfound-page==1.0.0
-+sphinxext-opengraph~=0.9.0
-+sphinx-notfound-page~=1.0.0
-
- # The theme used by the documentation is stored separately, so we need
- # to install that as well.
-diff --git a/Doc/tools/check-warnings.py b/Doc/tools/check-warnings.py
-index c50b00636c3..8f92ab298eb 100644
---- a/Doc/tools/check-warnings.py
-+++ b/Doc/tools/check-warnings.py
-@@ -2,6 +2,7 @@
- """
- Check the output of running Sphinx in nit-picky mode (missing references).
- """
-+
- from __future__ import annotations
-
- import argparse
-@@ -14,7 +15,7 @@
- from typing import TextIO
-
- # Fail if NEWS nit found before this line number
--NEWS_NIT_THRESHOLD = 200
-+NEWS_NIT_THRESHOLD = 300
-
- # Exclude these whether they're dirty or clean,
- # because they trigger a rebuild of dirty files.
-@@ -206,7 +207,9 @@
-
-
- def fail_if_regression(
-- warnings: list[str], files_with_expected_nits: set[str], files_with_nits: set[str]
-+ warnings: list[str],
-+ files_with_expected_nits: set[str],
-+ files_with_nits: set[str],
- ) -> int:
- """
- Ensure some files always pass Sphinx nit-picky mode (no missing references).
-@@ -252,17 +255,11 @@
- """
- Ensure no warnings are found in the NEWS file before a given line number.
- """
-- news_nits = (
-- warning
-- for warning in warnings
-- if "/build/NEWS:" in warning
-- )
-+ news_nits = (warning for warning in warnings if "/build/NEWS:" in warning)
-
- # Nits found before the threshold line
- new_news_nits = [
-- nit
-- for nit in news_nits
-- if int(nit.split(":")[1]) <= threshold
-+ nit for nit in news_nits if int(nit.split(":")[1]) <= threshold
- ]
-
- if new_news_nits:
-@@ -311,7 +308,8 @@
- exit_code = 0
-
- wrong_directory_msg = "Must run this script from the repo root"
-- assert Path("Doc").exists() and Path("Doc").is_dir(), wrong_directory_msg
-+ if not Path("Doc").exists() or not Path("Doc").is_dir():
-+ raise RuntimeError(wrong_directory_msg)
-
- with Path("Doc/sphinx-warnings.txt").open(encoding="UTF-8") as f:
- warnings = f.read().splitlines()
-@@ -339,7 +337,9 @@
- )
-
- if args.fail_if_improved:
-- exit_code += fail_if_improved(files_with_expected_nits, files_with_nits)
-+ exit_code += fail_if_improved(
-+ files_with_expected_nits, files_with_nits
-+ )
-
- if args.fail_if_new_news_nit:
- exit_code += fail_if_new_news_nit(warnings, args.fail_if_new_news_nit)
---- /dev/null
-+++ b/Doc/tools/extensions/audit_events.py
-@@ -0,0 +1,264 @@
-+"""Support for documenting audit events."""
-+
-+from __future__ import annotations
-+
-+import re
-+from typing import TYPE_CHECKING
-+
-+from docutils import nodes
-+from sphinx.errors import NoUri
-+from sphinx.locale import _ as sphinx_gettext
-+from sphinx.transforms.post_transforms import SphinxPostTransform
-+from sphinx.util import logging
-+from sphinx.util.docutils import SphinxDirective
-+
-+if TYPE_CHECKING:
-+ from collections.abc import Iterator
-+
-+ from sphinx.application import Sphinx
-+ from sphinx.builders import Builder
-+ from sphinx.environment import BuildEnvironment
-+
-+logger = logging.getLogger(__name__)
-+
-+# This list of sets are allowable synonyms for event argument names.
-+# If two names are in the same set, they are treated as equal for the
-+# purposes of warning. This won't help if the number of arguments is
-+# different!
-+_SYNONYMS = [
-+ frozenset({"file", "path", "fd"}),
-+]
-+
-+
-+class AuditEvents:
-+ def __init__(self) -> None:
-+ self.events: dict[str, list[str]] = {}
-+ self.sources: dict[str, list[tuple[str, str]]] = {}
-+
-+ def __iter__(self) -> Iterator[tuple[str, list[str], tuple[str, str]]]:
-+ for name, args in self.events.items():
-+ for source in self.sources[name]:
-+ yield name, args, source
-+
-+ def add_event(
-+ self, name, args: list[str], source: tuple[str, str]
-+ ) -> None:
-+ if name in self.events:
-+ self._check_args_match(name, args)
-+ else:
-+ self.events[name] = args
-+ self.sources.setdefault(name, []).append(source)
-+
-+ def _check_args_match(self, name: str, args: list[str]) -> None:
-+ current_args = self.events[name]
-+ msg = (
-+ f"Mismatched arguments for audit-event {name}: "
-+ f"{current_args!r} != {args!r}"
-+ )
-+ if current_args == args:
-+ return
-+ if len(current_args) != len(args):
-+ logger.warning(msg)
-+ return
-+ for a1, a2 in zip(current_args, args, strict=False):
-+ if a1 == a2:
-+ continue
-+ if any(a1 in s and a2 in s for s in _SYNONYMS):
-+ continue
-+ logger.warning(msg)
-+ return
-+
-+ def id_for(self, name) -> str:
-+ source_count = len(self.sources.get(name, ()))
-+ name_clean = re.sub(r"\W", "_", name)
-+ return f"audit_event_{name_clean}_{source_count}"
-+
-+ def rows(self) -> Iterator[tuple[str, list[str], list[tuple[str, str]]]]:
-+ for name in sorted(self.events.keys()):
-+ yield name, self.events[name], self.sources[name]
-+
-+
-+def initialise_audit_events(app: Sphinx) -> None:
-+ """Initialise the audit_events attribute on the environment."""
-+ if not hasattr(app.env, "audit_events"):
-+ app.env.audit_events = AuditEvents()
-+
-+
-+def audit_events_purge(
-+ app: Sphinx, env: BuildEnvironment, docname: str
-+) -> None:
-+ """This is to remove traces of removed documents from env.audit_events."""
-+ fresh_audit_events = AuditEvents()
-+ for name, args, (doc, target) in env.audit_events:
-+ if doc != docname:
-+ fresh_audit_events.add_event(name, args, (doc, target))
-+
-+
-+def audit_events_merge(
-+ app: Sphinx,
-+ env: BuildEnvironment,
-+ docnames: list[str],
-+ other: BuildEnvironment,
-+) -> None:
-+ """In Sphinx parallel builds, this merges audit_events from subprocesses."""
-+ for name, args, source in other.audit_events:
-+ env.audit_events.add_event(name, args, source)
-+
-+
-+class AuditEvent(SphinxDirective):
-+ has_content = True
-+ required_arguments = 1
-+ optional_arguments = 2
-+ final_argument_whitespace = True
-+
-+ _label = [
-+ sphinx_gettext(
-+ "Raises an :ref:`auditing event ` "
-+ "{name} with no arguments."
-+ ),
-+ sphinx_gettext(
-+ "Raises an :ref:`auditing event ` "
-+ "{name} with argument {args}."
-+ ),
-+ sphinx_gettext(
-+ "Raises an :ref:`auditing event ` "
-+ "{name} with arguments {args}."
-+ ),
-+ ]
-+
-+ def run(self) -> list[nodes.paragraph]:
-+ name = self.arguments[0]
-+ if len(self.arguments) >= 2 and self.arguments[1]:
-+ args = [
-+ arg
-+ for argument in self.arguments[1].strip("'\"").split(",")
-+ if (arg := argument.strip())
-+ ]
-+ else:
-+ args = []
-+ ids = []
-+ try:
-+ target = self.arguments[2].strip("\"'")
-+ except (IndexError, TypeError):
-+ target = None
-+ if not target:
-+ target = self.env.audit_events.id_for(name)
-+ ids.append(target)
-+ self.env.audit_events.add_event(name, args, (self.env.docname, target))
-+
-+ node = nodes.paragraph("", classes=["audit-hook"], ids=ids)
-+ self.set_source_info(node)
-+ if self.content:
-+ node.rawsource = '\n'.join(self.content) # for gettext
-+ self.state.nested_parse(self.content, self.content_offset, node)
-+ else:
-+ num_args = min(2, len(args))
-+ text = self._label[num_args].format(
-+ name=f"``{name}``",
-+ args=", ".join(f"``{a}``" for a in args),
-+ )
-+ node.rawsource = text # for gettext
-+ parsed, messages = self.state.inline_text(text, self.lineno)
-+ node += parsed
-+ node += messages
-+ return [node]
-+
-+
-+class audit_event_list(nodes.General, nodes.Element): # noqa: N801
-+ pass
-+
-+
-+class AuditEventListDirective(SphinxDirective):
-+ def run(self) -> list[audit_event_list]:
-+ return [audit_event_list()]
-+
-+
-+class AuditEventListTransform(SphinxPostTransform):
-+ default_priority = 500
-+
-+ def run(self) -> None:
-+ if self.document.next_node(audit_event_list) is None:
-+ return
-+
-+ table = self._make_table(self.app.builder, self.env.docname)
-+ for node in self.document.findall(audit_event_list):
-+ node.replace_self(table)
-+
-+ def _make_table(self, builder: Builder, docname: str) -> nodes.table:
-+ table = nodes.table(cols=3)
-+ group = nodes.tgroup(
-+ "",
-+ nodes.colspec(colwidth=30),
-+ nodes.colspec(colwidth=55),
-+ nodes.colspec(colwidth=15),
-+ cols=3,
-+ )
-+ head = nodes.thead()
-+ body = nodes.tbody()
-+
-+ table += group
-+ group += head
-+ group += body
-+
-+ head += nodes.row(
-+ "",
-+ nodes.entry("", nodes.paragraph("", "Audit event")),
-+ nodes.entry("", nodes.paragraph("", "Arguments")),
-+ nodes.entry("", nodes.paragraph("", "References")),
-+ )
-+
-+ for name, args, sources in builder.env.audit_events.rows():
-+ body += self._make_row(builder, docname, name, args, sources)
-+
-+ return table
-+
-+ @staticmethod
-+ def _make_row(
-+ builder: Builder,
-+ docname: str,
-+ name: str,
-+ args: list[str],
-+ sources: list[tuple[str, str]],
-+ ) -> nodes.row:
-+ row = nodes.row()
-+ name_node = nodes.paragraph("", nodes.Text(name))
-+ row += nodes.entry("", name_node)
-+
-+ args_node = nodes.paragraph()
-+ for arg in args:
-+ args_node += nodes.literal(arg, arg)
-+ args_node += nodes.Text(", ")
-+ if len(args_node.children) > 0:
-+ args_node.children.pop() # remove trailing comma
-+ row += nodes.entry("", args_node)
-+
-+ backlinks_node = nodes.paragraph()
-+ backlinks = enumerate(sorted(set(sources)), start=1)
-+ for i, (doc, label) in backlinks:
-+ if isinstance(label, str):
-+ ref = nodes.reference("", f"[{i}]", internal=True)
-+ try:
-+ target = (
-+ f"{builder.get_relative_uri(docname, doc)}#{label}"
-+ )
-+ except NoUri:
-+ continue
-+ else:
-+ ref["refuri"] = target
-+ backlinks_node += ref
-+ row += nodes.entry("", backlinks_node)
-+ return row
-+
-+
-+def setup(app: Sphinx):
-+ app.add_directive("audit-event", AuditEvent)
-+ app.add_directive("audit-event-table", AuditEventListDirective)
-+ app.add_post_transform(AuditEventListTransform)
-+ app.connect("builder-inited", initialise_audit_events)
-+ app.connect("env-purge-doc", audit_events_purge)
-+ app.connect("env-merge-info", audit_events_merge)
-+ return {
-+ "version": "1.0",
-+ "parallel_read_safe": True,
-+ "parallel_write_safe": True,
-+ }
-diff --git a/Doc/tools/extensions/c_annotations.py b/Doc/tools/extensions/c_annotations.py
-index 7916b178f1c..a65cf71e4af 100644
---- a/Doc/tools/extensions/c_annotations.py
-+++ b/Doc/tools/extensions/c_annotations.py
-@@ -1,226 +1,305 @@
--"""
-- c_annotations.py
-- ~~~~~~~~~~~~~~~~
--
-- Supports annotations for C API elements:
-+"""Support annotations for C API elements.
-
-- * reference count annotations for C API functions. Based on
-- refcount.py and anno-api.py in the old Python documentation tools.
-+* Reference count annotations for C API functions.
-+* Stable ABI annotations
-+* Limited API annotations
-
-- * stable API annotations
-+Configuration:
-+* Set ``refcount_file`` to the path to the reference count data file.
-+* Set ``stable_abi_file`` to the path to stable ABI list.
-+"""
-
-- Usage:
-- * Set the `refcount_file` config value to the path to the reference
-- count data file.
-- * Set the `stable_abi_file` config value to the path to stable ABI list.
-+from __future__ import annotations
-
-- :copyright: Copyright 2007-2014 by Georg Brandl.
-- :license: Python license.
--"""
-+import csv
-+import dataclasses
-+from pathlib import Path
-+from typing import TYPE_CHECKING
-
--from os import path
-+import sphinx
- from docutils import nodes
--from docutils.parsers.rst import directives
--from docutils.parsers.rst import Directive
- from docutils.statemachine import StringList
--from sphinx.locale import _ as sphinx_gettext
--import csv
--
- from sphinx import addnodes
--from sphinx.domains.c import CObject
-+from sphinx.locale import _ as sphinx_gettext
-+from sphinx.util.docutils import SphinxDirective
-
-+if TYPE_CHECKING:
-+ from sphinx.application import Sphinx
-+ from sphinx.util.typing import ExtensionMetadata
-
--REST_ROLE_MAP = {
-- 'function': 'func',
-- 'macro': 'macro',
-- 'member': 'member',
-- 'type': 'type',
-- 'var': 'data',
-+ROLE_TO_OBJECT_TYPE = {
-+ "func": "function",
-+ "macro": "macro",
-+ "member": "member",
-+ "type": "type",
-+ "data": "var",
- }
-
-
--class RCEntry:
-- def __init__(self, name):
-- self.name = name
-- self.args = []
-- self.result_type = ''
-- self.result_refs = None
--
--
--class Annotations:
-- def __init__(self, refcount_filename, stable_abi_file):
-- self.refcount_data = {}
-- with open(refcount_filename, encoding='utf8') as fp:
-- for line in fp:
-- line = line.strip()
-- if line[:1] in ("", "#"):
-- # blank lines and comments
-- continue
-- parts = line.split(":", 4)
-- if len(parts) != 5:
-- raise ValueError(f"Wrong field count in {line!r}")
-- function, type, arg, refcount, comment = parts
-- # Get the entry, creating it if needed:
-- try:
-- entry = self.refcount_data[function]
-- except KeyError:
-- entry = self.refcount_data[function] = RCEntry(function)
-- if not refcount or refcount == "null":
-- refcount = None
-- else:
-- refcount = int(refcount)
-- # Update the entry with the new parameter or the result
-- # information.
-- if arg:
-- entry.args.append((arg, type, refcount))
-- else:
-- entry.result_type = type
-- entry.result_refs = refcount
--
-- self.stable_abi_data = {}
-- with open(stable_abi_file, encoding='utf8') as fp:
-- for record in csv.DictReader(fp):
-- name = record['name']
-- self.stable_abi_data[name] = record
--
-- def add_annotations(self, app, doctree):
-- for node in doctree.findall(addnodes.desc_content):
-- par = node.parent
-- if par['domain'] != 'c':
-- continue
-- if not par[0].has_key('ids') or not par[0]['ids']:
-- continue
-- name = par[0]['ids'][0]
-- if name.startswith("c."):
-- name = name[2:]
--
-- objtype = par['objtype']
--
-- # Stable ABI annotation. These have two forms:
-- # Part of the [Stable ABI](link).
-- # Part of the [Stable ABI](link) since version X.Y.
-- # For structs, there's some more info in the message:
-- # Part of the [Limited API](link) (as an opaque struct).
-- # Part of the [Stable ABI](link) (including all members).
-- # Part of the [Limited API](link) (Only some members are part
-- # of the stable ABI.).
-- # ... all of which can have "since version X.Y" appended.
-- record = self.stable_abi_data.get(name)
-- if record:
-- if record['role'] != objtype:
-- raise ValueError(
-- f"Object type mismatch in limited API annotation "
-- f"for {name}: {record['role']!r} != {objtype!r}")
-- stable_added = record['added']
-- message = sphinx_gettext('Part of the')
-- message = message.center(len(message) + 2)
-- emph_node = nodes.emphasis(message, message,
-- classes=['stableabi'])
-- ref_node = addnodes.pending_xref(
-- 'Stable ABI', refdomain="std", reftarget='stable',
-- reftype='ref', refexplicit="False")
-- struct_abi_kind = record['struct_abi_kind']
-- if struct_abi_kind in {'opaque', 'members'}:
-- ref_node += nodes.Text(sphinx_gettext('Limited API'))
-- else:
-- ref_node += nodes.Text(sphinx_gettext('Stable ABI'))
-- emph_node += ref_node
-- if struct_abi_kind == 'opaque':
-- emph_node += nodes.Text(' ' + sphinx_gettext('(as an opaque struct)'))
-- elif struct_abi_kind == 'full-abi':
-- emph_node += nodes.Text(' ' + sphinx_gettext('(including all members)'))
-- if record['ifdef_note']:
-- emph_node += nodes.Text(' ' + record['ifdef_note'])
-- if stable_added == '3.2':
-- # Stable ABI was introduced in 3.2.
-- pass
-- else:
-- emph_node += nodes.Text(' ' + sphinx_gettext('since version %s') % stable_added)
-- emph_node += nodes.Text('.')
-- if struct_abi_kind == 'members':
-- emph_node += nodes.Text(
-- ' ' + sphinx_gettext('(Only some members are part of the stable ABI.)'))
-- node.insert(0, emph_node)
--
-- # Unstable API annotation.
-- if name.startswith('PyUnstable'):
-- warn_node = nodes.admonition(
-- classes=['unstable-c-api', 'warning'])
-- message = sphinx_gettext('This is') + ' '
-- emph_node = nodes.emphasis(message, message)
-- ref_node = addnodes.pending_xref(
-- 'Unstable API', refdomain="std",
-- reftarget='unstable-c-api',
-- reftype='ref', refexplicit="False")
-- ref_node += nodes.Text(sphinx_gettext('Unstable API'))
-- emph_node += ref_node
-- emph_node += nodes.Text(sphinx_gettext('. It may change without warning in minor releases.'))
-- warn_node += emph_node
-- node.insert(0, warn_node)
--
-- # Return value annotation
-- if objtype != 'function':
-- continue
-- entry = self.refcount_data.get(name)
-- if not entry:
-- continue
-- elif not entry.result_type.endswith("Object*"):
-- continue
-- classes = ['refcount']
-- if entry.result_refs is None:
-- rc = sphinx_gettext('Return value: Always NULL.')
-- classes.append('return_null')
-- elif entry.result_refs:
-- rc = sphinx_gettext('Return value: New reference.')
-- classes.append('return_new_ref')
-- else:
-- rc = sphinx_gettext('Return value: Borrowed reference.')
-- classes.append('return_borrowed_ref')
-- node.insert(0, nodes.emphasis(rc, rc, classes=classes))
--
--
--def init_annotations(app):
-- annotations = Annotations(
-- path.join(app.srcdir, app.config.refcount_file),
-- path.join(app.srcdir, app.config.stable_abi_file),
-+@dataclasses.dataclass(slots=True)
-+class RefCountEntry:
-+ # Name of the function.
-+ name: str
-+ # List of (argument name, type, refcount effect) tuples.
-+ # (Currently not used. If it was, a dataclass might work better.)
-+ args: list = dataclasses.field(default_factory=list)
-+ # Return type of the function.
-+ result_type: str = ""
-+ # Reference count effect for the return value.
-+ result_refs: int | None = None
-+
-+
-+@dataclasses.dataclass(frozen=True, slots=True)
-+class StableABIEntry:
-+ # Role of the object.
-+ # Source: Each [item_kind] in stable_abi.toml is mapped to a C Domain role.
-+ role: str
-+ # Name of the object.
-+ # Source: [.*] in stable_abi.toml.
-+ name: str
-+ # Version when the object was added to the stable ABI.
-+ # (Source: [.*.added] in stable_abi.toml.
-+ added: str
-+ # An explananatory blurb for the ifdef.
-+ # Source: ``feature_macro.*.doc`` in stable_abi.toml.
-+ ifdef_note: str
-+ # Defines how much of the struct is exposed. Only relevant for structs.
-+ # Source: [.*.struct_abi_kind] in stable_abi.toml.
-+ struct_abi_kind: str
-+
-+
-+def read_refcount_data(refcount_filename: Path) -> dict[str, RefCountEntry]:
-+ refcount_data = {}
-+ refcounts = refcount_filename.read_text(encoding="utf8")
-+ for line in refcounts.splitlines():
-+ line = line.strip()
-+ if not line or line.startswith("#"):
-+ # blank lines and comments
-+ continue
-+
-+ # Each line is of the form
-+ # function ':' type ':' [param name] ':' [refcount effect] ':' [comment]
-+ parts = line.split(":", 4)
-+ if len(parts) != 5:
-+ raise ValueError(f"Wrong field count in {line!r}")
-+ function, type, arg, refcount, _comment = parts
-+
-+ # Get the entry, creating it if needed:
-+ try:
-+ entry = refcount_data[function]
-+ except KeyError:
-+ entry = refcount_data[function] = RefCountEntry(function)
-+ if not refcount or refcount == "null":
-+ refcount = None
-+ else:
-+ refcount = int(refcount)
-+ # Update the entry with the new parameter
-+ # or the result information.
-+ if arg:
-+ entry.args.append((arg, type, refcount))
-+ else:
-+ entry.result_type = type
-+ entry.result_refs = refcount
-+
-+ return refcount_data
-+
-+
-+def read_stable_abi_data(stable_abi_file: Path) -> dict[str, StableABIEntry]:
-+ stable_abi_data = {}
-+ with open(stable_abi_file, encoding="utf8") as fp:
-+ for record in csv.DictReader(fp):
-+ name = record["name"]
-+ stable_abi_data[name] = StableABIEntry(**record)
-+
-+ return stable_abi_data
-+
-+
-+def add_annotations(app: Sphinx, doctree: nodes.document) -> None:
-+ state = app.env.domaindata["c_annotations"]
-+ refcount_data = state["refcount_data"]
-+ stable_abi_data = state["stable_abi_data"]
-+ for node in doctree.findall(addnodes.desc_content):
-+ par = node.parent
-+ if par["domain"] != "c":
-+ continue
-+ if not par[0].get("ids", None):
-+ continue
-+ name = par[0]["ids"][0]
-+ if name.startswith("c."):
-+ name = name[2:]
-+
-+ objtype = par["objtype"]
-+
-+ # Stable ABI annotation.
-+ if record := stable_abi_data.get(name):
-+ if ROLE_TO_OBJECT_TYPE[record.role] != objtype:
-+ msg = (
-+ f"Object type mismatch in limited API annotation for {name}: "
-+ f"{ROLE_TO_OBJECT_TYPE[record.role]!r} != {objtype!r}"
-+ )
-+ raise ValueError(msg)
-+ annotation = _stable_abi_annotation(record)
-+ node.insert(0, annotation)
-+
-+ # Unstable API annotation.
-+ if name.startswith("PyUnstable"):
-+ annotation = _unstable_api_annotation()
-+ node.insert(0, annotation)
-+
-+ # Return value annotation
-+ if objtype != "function":
-+ continue
-+ if name not in refcount_data:
-+ continue
-+ entry = refcount_data[name]
-+ if not entry.result_type.endswith("Object*"):
-+ continue
-+ annotation = _return_value_annotation(entry.result_refs)
-+ node.insert(0, annotation)
-+
-+
-+def _stable_abi_annotation(record: StableABIEntry) -> nodes.emphasis:
-+ """Create the Stable ABI annotation.
-+
-+ These have two forms:
-+ Part of the `Stable ABI `_.
-+ Part of the `Stable ABI `_ since version X.Y.
-+ For structs, there's some more info in the message:
-+ Part of the `Limited API `_ (as an opaque struct).
-+ Part of the `Stable ABI `_ (including all members).
-+ Part of the `Limited API `_ (Only some members are part
-+ of the stable ABI.).
-+ ... all of which can have "since version X.Y" appended.
-+ """
-+ stable_added = record.added
-+ message = sphinx_gettext("Part of the")
-+ message = message.center(len(message) + 2)
-+ emph_node = nodes.emphasis(message, message, classes=["stableabi"])
-+ ref_node = addnodes.pending_xref(
-+ "Stable ABI",
-+ refdomain="std",
-+ reftarget="stable",
-+ reftype="ref",
-+ refexplicit="False",
-+ )
-+ struct_abi_kind = record.struct_abi_kind
-+ if struct_abi_kind in {"opaque", "members"}:
-+ ref_node += nodes.Text(sphinx_gettext("Limited API"))
-+ else:
-+ ref_node += nodes.Text(sphinx_gettext("Stable ABI"))
-+ emph_node += ref_node
-+ if struct_abi_kind == "opaque":
-+ emph_node += nodes.Text(" " + sphinx_gettext("(as an opaque struct)"))
-+ elif struct_abi_kind == "full-abi":
-+ emph_node += nodes.Text(
-+ " " + sphinx_gettext("(including all members)")
-+ )
-+ if record.ifdef_note:
-+ emph_node += nodes.Text(f" {record.ifdef_note}")
-+ if stable_added == "3.2":
-+ # Stable ABI was introduced in 3.2.
-+ pass
-+ else:
-+ emph_node += nodes.Text(
-+ " " + sphinx_gettext("since version %s") % stable_added
-+ )
-+ emph_node += nodes.Text(".")
-+ if struct_abi_kind == "members":
-+ msg = " " + sphinx_gettext(
-+ "(Only some members are part of the stable ABI.)"
-+ )
-+ emph_node += nodes.Text(msg)
-+ return emph_node
-+
-+
-+def _unstable_api_annotation() -> nodes.admonition:
-+ ref_node = addnodes.pending_xref(
-+ "Unstable API",
-+ nodes.Text(sphinx_gettext("Unstable API")),
-+ refdomain="std",
-+ reftarget="unstable-c-api",
-+ reftype="ref",
-+ refexplicit="False",
-+ )
-+ emph_node = nodes.emphasis(
-+ "This is ",
-+ sphinx_gettext("This is") + " ",
-+ ref_node,
-+ nodes.Text(
-+ sphinx_gettext(
-+ ". It may change without warning in minor releases."
-+ )
-+ ),
-+ )
-+ return nodes.admonition(
-+ "",
-+ emph_node,
-+ classes=["unstable-c-api", "warning"],
- )
-- app.connect('doctree-read', annotations.add_annotations)
-
-- class LimitedAPIList(Directive):
-
-- has_content = False
-- required_arguments = 0
-- optional_arguments = 0
-- final_argument_whitespace = True
-+def _return_value_annotation(result_refs: int | None) -> nodes.emphasis:
-+ classes = ["refcount"]
-+ if result_refs is None:
-+ rc = sphinx_gettext("Return value: Always NULL.")
-+ classes.append("return_null")
-+ elif result_refs:
-+ rc = sphinx_gettext("Return value: New reference.")
-+ classes.append("return_new_ref")
-+ else:
-+ rc = sphinx_gettext("Return value: Borrowed reference.")
-+ classes.append("return_borrowed_ref")
-+ return nodes.emphasis(rc, rc, classes=classes)
-+
-+
-+class LimitedAPIList(SphinxDirective):
-+ has_content = False
-+ required_arguments = 0
-+ optional_arguments = 0
-+ final_argument_whitespace = True
-
-- def run(self):
-- content = []
-- for record in annotations.stable_abi_data.values():
-- role = REST_ROLE_MAP[record['role']]
-- name = record['name']
-- content.append(f'* :c:{role}:`{name}`')
-+ def run(self) -> list[nodes.Node]:
-+ state = self.env.domaindata["c_annotations"]
-+ content = [
-+ f"* :c:{record.role}:`{record.name}`"
-+ for record in state["stable_abi_data"].values()
-+ ]
-+ node = nodes.paragraph()
-+ self.state.nested_parse(StringList(content), 0, node)
-+ return [node]
-
-- pnode = nodes.paragraph()
-- self.state.nested_parse(StringList(content), 0, pnode)
-- return [pnode]
-
-- app.add_directive('limited-api-list', LimitedAPIList)
-+def init_annotations(app: Sphinx) -> None:
-+ # Using domaindata is a bit hack-ish,
-+ # but allows storing state without a global variable or closure.
-+ app.env.domaindata["c_annotations"] = state = {}
-+ state["refcount_data"] = read_refcount_data(
-+ Path(app.srcdir, app.config.refcount_file)
-+ )
-+ state["stable_abi_data"] = read_stable_abi_data(
-+ Path(app.srcdir, app.config.stable_abi_file)
-+ )
-
-
--def setup(app):
-- app.add_config_value('refcount_file', '', True)
-- app.add_config_value('stable_abi_file', '', True)
-- app.connect('builder-inited', init_annotations)
-+def setup(app: Sphinx) -> ExtensionMetadata:
-+ app.add_config_value("refcount_file", "", "env", types={str})
-+ app.add_config_value("stable_abi_file", "", "env", types={str})
-+ app.add_directive("limited-api-list", LimitedAPIList)
-+ app.connect("builder-inited", init_annotations)
-+ app.connect("doctree-read", add_annotations)
-
-- # monkey-patch C object...
-- CObject.option_spec = {
-- 'noindex': directives.flag,
-- 'stableabi': directives.flag,
-- }
-- old_handle_signature = CObject.handle_signature
-+ if sphinx.version_info[:2] < (7, 2):
-+ from docutils.parsers.rst import directives
-+ from sphinx.domains.c import CObject
-
-- def new_handle_signature(self, sig, signode):
-- signode.parent['stableabi'] = 'stableabi' in self.options
-- return old_handle_signature(self, sig, signode)
-- CObject.handle_signature = new_handle_signature
-- return {'version': '1.0', 'parallel_read_safe': True}
-+ # monkey-patch C object...
-+ CObject.option_spec |= {
-+ "no-index-entry": directives.flag,
-+ "no-contents-entry": directives.flag,
-+ }
-+
-+ return {
-+ "version": "1.0",
-+ "parallel_read_safe": True,
-+ "parallel_write_safe": True,
-+ }
-diff --git a/Doc/tools/extensions/glossary_search.py b/Doc/tools/extensions/glossary_search.py
-index 7c93b1e4990..502b6cd95bc 100644
---- a/Doc/tools/extensions/glossary_search.py
-+++ b/Doc/tools/extensions/glossary_search.py
-@@ -1,63 +1,63 @@
--# -*- coding: utf-8 -*-
--"""
-- glossary_search.py
-- ~~~~~~~~~~~~~~~~
-+"""Feature search results for glossary items prominently."""
-
-- Feature search results for glossary items prominently.
-+from __future__ import annotations
-
-- :license: Python license.
--"""
- import json
--import os.path
--from docutils.nodes import definition_list_item
-+from pathlib import Path
-+from typing import TYPE_CHECKING
-+
-+from docutils import nodes
- from sphinx.addnodes import glossary
- from sphinx.util import logging
-
-+if TYPE_CHECKING:
-+ from sphinx.application import Sphinx
-+ from sphinx.util.typing import ExtensionMetadata
-
- logger = logging.getLogger(__name__)
--STATIC_DIR = '_static'
--JSON = 'glossary.json'
-
-
--def process_glossary_nodes(app, doctree, fromdocname):
-+def process_glossary_nodes(
-+ app: Sphinx,
-+ doctree: nodes.document,
-+ _docname: str,
-+) -> None:
- if app.builder.format != 'html' or app.builder.embedded:
- return
-
-- terms = {}
-+ if hasattr(app.env, 'glossary_terms'):
-+ terms = app.env.glossary_terms
-+ else:
-+ terms = app.env.glossary_terms = {}
-
- for node in doctree.findall(glossary):
-- for glossary_item in node.findall(definition_list_item):
-- term = glossary_item[0].astext().lower()
-- definition = glossary_item[1]
-+ for glossary_item in node.findall(nodes.definition_list_item):
-+ term = glossary_item[0].astext()
-+ definition = glossary_item[-1]
-
- rendered = app.builder.render_partial(definition)
-- terms[term] = {
-- 'title': glossary_item[0].astext(),
-- 'body': rendered['html_body']
-+ terms[term.lower()] = {
-+ 'title': term,
-+ 'body': rendered['html_body'],
- }
-
-- if hasattr(app.env, 'glossary_terms'):
-- app.env.glossary_terms.update(terms)
-- else:
-- app.env.glossary_terms = terms
-
--def on_build_finish(app, exc):
-- if not hasattr(app.env, 'glossary_terms'):
-- return
-- if not app.env.glossary_terms:
-+def write_glossary_json(app: Sphinx, _exc: Exception) -> None:
-+ if not getattr(app.env, 'glossary_terms', None):
- return
-
-- logger.info(f'Writing {JSON}', color='green')
--
-- dest_dir = os.path.join(app.outdir, STATIC_DIR)
-- os.makedirs(dest_dir, exist_ok=True)
--
-- with open(os.path.join(dest_dir, JSON), 'w') as f:
-- json.dump(app.env.glossary_terms, f)
-+ logger.info('Writing glossary.json', color='green')
-+ dest = Path(app.outdir, '_static', 'glossary.json')
-+ dest.parent.mkdir(exist_ok=True)
-+ dest.write_text(json.dumps(app.env.glossary_terms), encoding='utf-8')
-
-
--def setup(app):
-+def setup(app: Sphinx) -> ExtensionMetadata:
- app.connect('doctree-resolved', process_glossary_nodes)
-- app.connect('build-finished', on_build_finish)
-+ app.connect('build-finished', write_glossary_json)
-
-- return {'version': '0.1', 'parallel_read_safe': True}
-+ return {
-+ 'version': '1.0',
-+ 'parallel_read_safe': True,
-+ 'parallel_write_safe': True,
-+ }
---- /dev/null
-+++ b/Doc/tools/extensions/lexers/__init__.py
-@@ -0,0 +1,15 @@
-+from .asdl_lexer import ASDLLexer
-+from .peg_lexer import PEGLexer
-+
-+
-+def setup(app):
-+ # Used for highlighting Parser/Python.asdl in library/ast.rst
-+ app.add_lexer("asdl", ASDLLexer)
-+ # Used for highlighting Grammar/python.gram in reference/grammar.rst
-+ app.add_lexer("peg", PEGLexer)
-+
-+ return {
-+ "version": "1.0",
-+ "parallel_read_safe": True,
-+ "parallel_write_safe": True,
-+ }
-diff --git a/Doc/tools/extensions/asdl_highlight.py b/Doc/tools/extensions/lexers/asdl_lexer.py
-similarity index 62%
-rename from Doc/tools/extensions/asdl_highlight.py
-rename to Doc/tools/extensions/lexers/asdl_lexer.py
-index 42863a4b3bc..3a74174a1f7 100644
---- a/Doc/tools/extensions/asdl_highlight.py
-+++ b/Doc/tools/extensions/lexers/asdl_lexer.py
-@@ -1,15 +1,6 @@
--import sys
--from pathlib import Path
-+from pygments.lexer import RegexLexer, bygroups, include
-+from pygments.token import Comment, Keyword, Name, Operator, Punctuation, Text
-
--CPYTHON_ROOT = Path(__file__).resolve().parent.parent.parent.parent
--sys.path.append(str(CPYTHON_ROOT / "Parser"))
--
--from pygments.lexer import RegexLexer, bygroups, include, words
--from pygments.token import (Comment, Keyword, Name, Operator,
-- Punctuation, Text)
--
--from asdl import builtin_types
--from sphinx.highlighting import lexers
-
- class ASDLLexer(RegexLexer):
- name = "ASDL"
-@@ -34,7 +25,10 @@
- r"(\w+)(\*\s|\?\s|\s)(\w+)",
- bygroups(Name.Builtin.Pseudo, Operator, Name),
- ),
-- (words(builtin_types), Name.Builtin),
-+ # Keep in line with ``builtin_types`` from Parser/asdl.py.
-+ # ASDL's 4 builtin types are
-+ # constant, identifier, int, string
-+ ("constant|identifier|int|string", Name.Builtin),
- (r"attributes", Name.Builtin),
- (
- _name + _text_ws + "(=)",
-@@ -46,8 +40,3 @@
- (r".", Text),
- ],
- }
--
--
--def setup(app):
-- lexers["asdl"] = ASDLLexer()
-- return {'version': '1.0', 'parallel_read_safe': True}
-diff --git a/Doc/tools/extensions/peg_highlight.py b/Doc/tools/extensions/lexers/peg_lexer.py
-similarity index 94%
-rename from Doc/tools/extensions/peg_highlight.py
-rename to Doc/tools/extensions/lexers/peg_lexer.py
-index 5ab5530d269..06f9f8eb312 100644
---- a/Doc/tools/extensions/peg_highlight.py
-+++ b/Doc/tools/extensions/lexers/peg_lexer.py
-@@ -1,8 +1,6 @@
- from pygments.lexer import RegexLexer, bygroups, include
- from pygments.token import Comment, Keyword, Name, Operator, Punctuation, Text
-
--from sphinx.highlighting import lexers
--
-
- class PEGLexer(RegexLexer):
- """Pygments Lexer for PEG grammar (.gram) files
-@@ -81,8 +79,3 @@
- (r".", Text),
- ],
- }
--
--
--def setup(app):
-- lexers["peg"] = PEGLexer()
-- return {"version": "1.0", "parallel_read_safe": True}
-diff --git a/Doc/tools/extensions/patchlevel.py b/Doc/tools/extensions/patchlevel.py
-index 617f28c2527..f2df6db47a2 100644
---- a/Doc/tools/extensions/patchlevel.py
-+++ b/Doc/tools/extensions/patchlevel.py
-@@ -1,68 +1,77 @@
--# -*- coding: utf-8 -*-
--"""
-- patchlevel.py
-- ~~~~~~~~~~~~~
-+"""Extract version information from Include/patchlevel.h."""
-
-- Extract version info from Include/patchlevel.h.
-- Adapted from Doc/tools/getversioninfo.
-+import re
-+import sys
-+from pathlib import Path
-+from typing import Literal, NamedTuple
-
-- :copyright: 2007-2008 by Georg Brandl.
-- :license: Python license.
--"""
-+CPYTHON_ROOT = Path(
-+ __file__, # cpython/Doc/tools/extensions/patchlevel.py
-+ "..", # cpython/Doc/tools/extensions
-+ "..", # cpython/Doc/tools
-+ "..", # cpython/Doc
-+ "..", # cpython
-+).resolve()
-+PATCHLEVEL_H = CPYTHON_ROOT / "Include" / "patchlevel.h"
-
--from __future__ import print_function
-+RELEASE_LEVELS = {
-+ "PY_RELEASE_LEVEL_ALPHA": "alpha",
-+ "PY_RELEASE_LEVEL_BETA": "beta",
-+ "PY_RELEASE_LEVEL_GAMMA": "candidate",
-+ "PY_RELEASE_LEVEL_FINAL": "final",
-+}
-
--import os
--import re
--import sys
-
--def get_header_version_info(srcdir):
-- patchlevel_h = os.path.join(srcdir, '..', 'Include', 'patchlevel.h')
-+class version_info(NamedTuple): # noqa: N801
-+ major: int #: Major release number
-+ minor: int #: Minor release number
-+ micro: int #: Patch release number
-+ releaselevel: Literal["alpha", "beta", "candidate", "final"]
-+ serial: int #: Serial release number
-
-- # This won't pick out all #defines, but it will pick up the ones we
-- # care about.
-- rx = re.compile(r'\s*#define\s+([a-zA-Z][a-zA-Z_0-9]*)\s+([a-zA-Z_0-9]+)')
-
-- d = {}
-- with open(patchlevel_h) as f:
-- for line in f:
-- m = rx.match(line)
-- if m is not None:
-- name, value = m.group(1, 2)
-- d[name] = value
-+def get_header_version_info() -> version_info:
-+ # Capture PY_ prefixed #defines.
-+ pat = re.compile(r"\s*#define\s+(PY_\w*)\s+(\w+)", re.ASCII)
-
-- release = version = '%s.%s' % (d['PY_MAJOR_VERSION'], d['PY_MINOR_VERSION'])
-- micro = int(d['PY_MICRO_VERSION'])
-- release += '.' + str(micro)
-+ defines = {}
-+ patchlevel_h = PATCHLEVEL_H.read_text(encoding="utf-8")
-+ for line in patchlevel_h.splitlines():
-+ if (m := pat.match(line)) is not None:
-+ name, value = m.groups()
-+ defines[name] = value
-
-- level = d['PY_RELEASE_LEVEL']
-- suffixes = {
-- 'PY_RELEASE_LEVEL_ALPHA': 'a',
-- 'PY_RELEASE_LEVEL_BETA': 'b',
-- 'PY_RELEASE_LEVEL_GAMMA': 'rc',
-- }
-- if level != 'PY_RELEASE_LEVEL_FINAL':
-- release += suffixes[level] + str(int(d['PY_RELEASE_SERIAL']))
-- return version, release
-+ return version_info(
-+ major=int(defines["PY_MAJOR_VERSION"]),
-+ minor=int(defines["PY_MINOR_VERSION"]),
-+ micro=int(defines["PY_MICRO_VERSION"]),
-+ releaselevel=RELEASE_LEVELS[defines["PY_RELEASE_LEVEL"]],
-+ serial=int(defines["PY_RELEASE_SERIAL"]),
-+ )
-
-
--def get_sys_version_info():
-- major, minor, micro, level, serial = sys.version_info
-- release = version = '%s.%s' % (major, minor)
-- release += '.%s' % micro
-- if level != 'final':
-- release += '%s%s' % (level[0], serial)
-+def format_version_info(info: version_info) -> tuple[str, str]:
-+ version = f"{info.major}.{info.minor}"
-+ release = f"{info.major}.{info.minor}.{info.micro}"
-+ if info.releaselevel != "final":
-+ suffix = {"alpha": "a", "beta": "b", "candidate": "rc"}
-+ release += f"{suffix[info.releaselevel]}{info.serial}"
- return version, release
-
-
- def get_version_info():
- try:
-- return get_header_version_info('.')
-- except (IOError, OSError):
-- version, release = get_sys_version_info()
-- print('Can\'t get version info from Include/patchlevel.h, ' \
-- 'using version of this interpreter (%s).' % release, file=sys.stderr)
-+ info = get_header_version_info()
-+ return format_version_info(info)
-+ except OSError:
-+ version, release = format_version_info(sys.version_info)
-+ print(
-+ f"Failed to get version info from Include/patchlevel.h, "
-+ f"using version of this interpreter ({release}).",
-+ file=sys.stderr,
-+ )
- return version, release
-
--if __name__ == '__main__':
-- print(get_header_version_info('.')[1])
-+
-+if __name__ == "__main__":
-+ print(format_version_info(get_header_version_info())[1])
diff --git a/Doc/tools/extensions/pyspecific.py b/Doc/tools/extensions/pyspecific.py
-index caf145997fa..7cd9155634b 100644
+index 96a4f24fad3..7cd9155634b 100644
--- a/Doc/tools/extensions/pyspecific.py
+++ b/Doc/tools/extensions/pyspecific.py
-@@ -15,14 +15,14 @@
- from time import asctime
- from pprint import pformat
-
--from docutils import nodes, utils
-+from docutils import nodes
- from docutils.io import StringOutput
--from docutils.parsers.rst import Directive
--from docutils.utils import new_document
-+from docutils.parsers.rst import directives
-+from docutils.utils import new_document, unescape
- from sphinx import addnodes
- from sphinx.builders import Builder
--from sphinx.domains.python import PyFunction, PyMethod
--from sphinx.errors import NoUri
-+from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes
-+from sphinx.domains.python import PyFunction, PyMethod, PyModule
- from sphinx.locale import _ as sphinx_gettext
- from sphinx.util import logging
- from sphinx.util.docutils import SphinxDirective
-@@ -48,11 +48,14 @@
-
- std.token_re = re.compile(r'`((~?[\w-]*:)?\w+)`')
-
-+# backport :no-index:
-+PyModule.option_spec['no-index'] = directives.flag
-+
-
- # Support for marking up and linking to bugs.python.org issues
-
- def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
-- issue = utils.unescape(text)
-+ issue = unescape(text)
- # sanity check: there are no bpo issues within these two values
- if 47261 < int(issue) < 400000:
- msg = inliner.reporter.error(f'The BPO ID {text!r} seems too high -- '
-@@ -67,7 +70,7 @@
- # Support for marking up and linking to GitHub issues
-
- def gh_issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
-- issue = utils.unescape(text)
-+ issue = unescape(text)
- # sanity check: all GitHub issues have ID >= 32426
- # even though some of them are also valid BPO IDs
- if int(issue) < 32426:
-@@ -82,7 +85,7 @@
-
- # Support for marking up implementation details
-
--class ImplementationDetail(Directive):
-+class ImplementationDetail(SphinxDirective):
-
- has_content = True
- final_argument_whitespace = True
-@@ -118,7 +121,7 @@
+@@ -121,7 +121,7 @@
known_platforms = frozenset({
"AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD",
"Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris", "Unix", "VxWorks",
@@ -11814,7 +887,7 @@ index caf145997fa..7cd9155634b 100644
# libc
"BSD libc", "glibc", "musl",
# POSIX platforms with pthreads
-@@ -149,7 +152,7 @@
+@@ -152,7 +152,7 @@
Example::
@@ -11823,1050 +896,10 @@ index caf145997fa..7cd9155634b 100644
Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not
parsed into separate tokens.
-@@ -179,143 +182,6 @@
- return platforms
-
-
--# Support for documenting audit event
--
--def audit_events_purge(app, env, docname):
-- """This is to remove from env.all_audit_events old traces of removed
-- documents.
-- """
-- if not hasattr(env, 'all_audit_events'):
-- return
-- fresh_all_audit_events = {}
-- for name, event in env.all_audit_events.items():
-- event["source"] = [(d, t) for d, t in event["source"] if d != docname]
-- if event["source"]:
-- # Only keep audit_events that have at least one source.
-- fresh_all_audit_events[name] = event
-- env.all_audit_events = fresh_all_audit_events
--
--
--def audit_events_merge(app, env, docnames, other):
-- """In Sphinx parallel builds, this merges env.all_audit_events from
-- subprocesses.
--
-- all_audit_events is a dict of names, with values like:
-- {'source': [(docname, target), ...], 'args': args}
-- """
-- if not hasattr(other, 'all_audit_events'):
-- return
-- if not hasattr(env, 'all_audit_events'):
-- env.all_audit_events = {}
-- for name, value in other.all_audit_events.items():
-- if name in env.all_audit_events:
-- env.all_audit_events[name]["source"].extend(value["source"])
-- else:
-- env.all_audit_events[name] = value
--
--
--class AuditEvent(Directive):
--
-- has_content = True
-- required_arguments = 1
-- optional_arguments = 2
-- final_argument_whitespace = True
--
-- _label = [
-- sphinx_gettext("Raises an :ref:`auditing event ` {name} with no arguments."),
-- sphinx_gettext("Raises an :ref:`auditing event ` {name} with argument {args}."),
-- sphinx_gettext("Raises an :ref:`auditing event ` {name} with arguments {args}."),
-- ]
--
-- @property
-- def logger(self):
-- cls = type(self)
-- return logging.getLogger(cls.__module__ + "." + cls.__name__)
--
-- def run(self):
-- name = self.arguments[0]
-- if len(self.arguments) >= 2 and self.arguments[1]:
-- args = (a.strip() for a in self.arguments[1].strip("'\"").split(","))
-- args = [a for a in args if a]
-- else:
-- args = []
--
-- label = self._label[min(2, len(args))]
-- text = label.format(name="``{}``".format(name),
-- args=", ".join("``{}``".format(a) for a in args if a))
--
-- env = self.state.document.settings.env
-- if not hasattr(env, 'all_audit_events'):
-- env.all_audit_events = {}
--
-- new_info = {
-- 'source': [],
-- 'args': args
-- }
-- info = env.all_audit_events.setdefault(name, new_info)
-- if info is not new_info:
-- if not self._do_args_match(info['args'], new_info['args']):
-- self.logger.warning(
-- "Mismatched arguments for audit-event {}: {!r} != {!r}"
-- .format(name, info['args'], new_info['args'])
-- )
--
-- ids = []
-- try:
-- target = self.arguments[2].strip("\"'")
-- except (IndexError, TypeError):
-- target = None
-- if not target:
-- target = "audit_event_{}_{}".format(
-- re.sub(r'\W', '_', name),
-- len(info['source']),
-- )
-- ids.append(target)
--
-- info['source'].append((env.docname, target))
--
-- pnode = nodes.paragraph(text, classes=["audit-hook"], ids=ids)
-- pnode.line = self.lineno
-- if self.content:
-- self.state.nested_parse(self.content, self.content_offset, pnode)
-- else:
-- n, m = self.state.inline_text(text, self.lineno)
-- pnode.extend(n + m)
--
-- return [pnode]
--
-- # This list of sets are allowable synonyms for event argument names.
-- # If two names are in the same set, they are treated as equal for the
-- # purposes of warning. This won't help if number of arguments is
-- # different!
-- _SYNONYMS = [
-- {"file", "path", "fd"},
-- ]
--
-- def _do_args_match(self, args1, args2):
-- if args1 == args2:
-- return True
-- if len(args1) != len(args2):
-- return False
-- for a1, a2 in zip(args1, args2):
-- if a1 == a2:
-- continue
-- if any(a1 in s and a2 in s for s in self._SYNONYMS):
-- continue
-- return False
-- return True
--
--
--class audit_event_list(nodes.General, nodes.Element):
-- pass
--
--
--class AuditEventListDirective(Directive):
--
-- def run(self):
-- return [audit_event_list('')]
--
--
- # Support for documenting decorators
-
- class PyDecoratorMixin(object):
-@@ -395,58 +261,34 @@
-
- # Support for documenting version of removal in deprecations
-
--class DeprecatedRemoved(Directive):
-- has_content = True
-+class DeprecatedRemoved(VersionChange):
- required_arguments = 2
-- optional_arguments = 1
-- final_argument_whitespace = True
-- option_spec = {}
-
-- _deprecated_label = sphinx_gettext('Deprecated since version {deprecated}, will be removed in version {removed}')
-- _removed_label = sphinx_gettext('Deprecated since version {deprecated}, removed in version {removed}')
-+ _deprecated_label = sphinx_gettext('Deprecated since version %s, will be removed in version %s')
-+ _removed_label = sphinx_gettext('Deprecated since version %s, removed in version %s')
-
- def run(self):
-- node = addnodes.versionmodified()
-- node.document = self.state.document
-- node['type'] = 'deprecated-removed'
-- version = (self.arguments[0], self.arguments[1])
-- node['version'] = version
-- env = self.state.document.settings.env
-- current_version = tuple(int(e) for e in env.config.version.split('.'))
-- removed_version = tuple(int(e) for e in self.arguments[1].split('.'))
-+ # Replace the first two arguments (deprecated version and removed version)
-+ # with a single tuple of both versions.
-+ version_deprecated = self.arguments[0]
-+ version_removed = self.arguments.pop(1)
-+ self.arguments[0] = version_deprecated, version_removed
-+
-+ # Set the label based on if we have reached the removal version
-+ current_version = tuple(map(int, self.config.version.split('.')))
-+ removed_version = tuple(map(int, version_removed.split('.')))
- if current_version < removed_version:
-- label = self._deprecated_label
-- else:
-- label = self._removed_label
--
-- text = label.format(deprecated=self.arguments[0], removed=self.arguments[1])
-- if len(self.arguments) == 3:
-- inodes, messages = self.state.inline_text(self.arguments[2],
-- self.lineno+1)
-- para = nodes.paragraph(self.arguments[2], '', *inodes, translatable=False)
-- node.append(para)
-+ versionlabels[self.name] = self._deprecated_label
-+ versionlabel_classes[self.name] = 'deprecated'
- else:
-- messages = []
-- if self.content:
-- self.state.nested_parse(self.content, self.content_offset, node)
-- if len(node):
-- if isinstance(node[0], nodes.paragraph) and node[0].rawsource:
-- content = nodes.inline(node[0].rawsource, translatable=True)
-- content.source = node[0].source
-- content.line = node[0].line
-- content += node[0].children
-- node[0].replace_self(nodes.paragraph('', '', content, translatable=False))
-- node[0].insert(0, nodes.inline('', '%s: ' % text,
-- classes=['versionmodified']))
-- else:
-- para = nodes.paragraph('', '',
-- nodes.inline('', '%s.' % text,
-- classes=['versionmodified']),
-- translatable=False)
-- node.append(para)
-- env = self.state.document.settings.env
-- env.get_domain('changeset').note_changeset(node)
-- return [node] + messages
-+ versionlabels[self.name] = self._removed_label
-+ versionlabel_classes[self.name] = 'removed'
-+ try:
-+ return super().run()
-+ finally:
-+ # reset versionlabels and versionlabel_classes
-+ versionlabels[self.name] = ''
-+ versionlabel_classes[self.name] = ''
-
-
- # Support for including Misc/NEWS
-@@ -456,7 +298,7 @@
- whatsnew_re = re.compile(r"(?im)^what's new in (.*?)\??$")
-
-
--class MiscNews(Directive):
-+class MiscNews(SphinxDirective):
- has_content = False
- required_arguments = 1
- optional_arguments = 0
-@@ -471,7 +313,7 @@
- if not source_dir:
- source_dir = path.dirname(path.abspath(source))
- fpath = path.join(source_dir, fname)
-- self.state.document.settings.record_dependencies.add(fpath)
-+ self.env.note_dependency(path.abspath(fpath))
- try:
- with io.open(fpath, encoding='utf-8') as fp:
- content = fp.read()
-@@ -603,70 +445,6 @@
- return sig
-
-
--def process_audit_events(app, doctree, fromdocname):
-- for node in doctree.findall(audit_event_list):
-- break
-- else:
-- return
--
-- env = app.builder.env
--
-- table = nodes.table(cols=3)
-- group = nodes.tgroup(
-- '',
-- nodes.colspec(colwidth=30),
-- nodes.colspec(colwidth=55),
-- nodes.colspec(colwidth=15),
-- cols=3,
-- )
-- head = nodes.thead()
-- body = nodes.tbody()
--
-- table += group
-- group += head
-- group += body
--
-- row = nodes.row()
-- row += nodes.entry('', nodes.paragraph('', nodes.Text('Audit event')))
-- row += nodes.entry('', nodes.paragraph('', nodes.Text('Arguments')))
-- row += nodes.entry('', nodes.paragraph('', nodes.Text('References')))
-- head += row
--
-- for name in sorted(getattr(env, "all_audit_events", ())):
-- audit_event = env.all_audit_events[name]
--
-- row = nodes.row()
-- node = nodes.paragraph('', nodes.Text(name))
-- row += nodes.entry('', node)
--
-- node = nodes.paragraph()
-- for i, a in enumerate(audit_event['args']):
-- if i:
-- node += nodes.Text(", ")
-- node += nodes.literal(a, nodes.Text(a))
-- row += nodes.entry('', node)
--
-- node = nodes.paragraph()
-- backlinks = enumerate(sorted(set(audit_event['source'])), start=1)
-- for i, (doc, label) in backlinks:
-- if isinstance(label, str):
-- ref = nodes.reference("", nodes.Text("[{}]".format(i)), internal=True)
-- try:
-- ref['refuri'] = "{}#{}".format(
-- app.builder.get_relative_uri(fromdocname, doc),
-- label,
-- )
-- except NoUri:
-- continue
-- node += ref
-- row += nodes.entry('', node)
--
-- body += row
--
-- for node in doctree.findall(audit_event_list):
-- node.replace_self(table)
--
--
- def patch_pairindextypes(app, _env) -> None:
- """Remove all entries from ``pairindextypes`` before writing POT files.
-
-@@ -696,8 +474,6 @@
- app.add_role('gh', gh_issue_role)
- app.add_directive('impl-detail', ImplementationDetail)
- app.add_directive('availability', Availability)
-- app.add_directive('audit-event', AuditEvent)
-- app.add_directive('audit-event-table', AuditEventListDirective)
- app.add_directive('deprecated-removed', DeprecatedRemoved)
- app.add_builder(PydocTopicsBuilder)
- app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
-@@ -713,7 +489,4 @@
- app.add_directive_to_domain('py', 'abstractmethod', PyAbstractMethod)
- app.add_directive('miscnews', MiscNews)
- app.connect('env-check-consistency', patch_pairindextypes)
-- app.connect('doctree-resolved', process_audit_events)
-- app.connect('env-merge-info', audit_events_merge)
-- app.connect('env-purge-doc', audit_events_purge)
- return {'version': '1.0', 'parallel_read_safe': True}
---- /dev/null
-+++ b/Doc/tools/static/glossary_search.js
-@@ -0,0 +1,47 @@
-+"use strict";
-+
-+const GLOSSARY_PAGE = "glossary.html";
-+
-+const glossary_search = async () => {
-+ const response = await fetch("_static/glossary.json");
-+ if (!response.ok) {
-+ throw new Error("Failed to fetch glossary.json");
-+ }
-+ const glossary = await response.json();
-+
-+ const params = new URLSearchParams(document.location.search).get("q");
-+ if (!params) {
-+ return;
-+ }
-+
-+ const searchParam = params.toLowerCase();
-+ const glossaryItem = glossary[searchParam];
-+ if (!glossaryItem) {
-+ return;
-+ }
-+
-+ // set up the title text with a link to the glossary page
-+ const glossaryTitle = document.getElementById("glossary-title");
-+ glossaryTitle.textContent = "Glossary: " + glossaryItem.title;
-+ const linkTarget = searchParam.replace(/ /g, "-");
-+ glossaryTitle.href = GLOSSARY_PAGE + "#term-" + linkTarget;
-+
-+ // rewrite any anchor links (to other glossary terms)
-+ // to have a full reference to the glossary page
-+ const glossaryBody = document.getElementById("glossary-body");
-+ glossaryBody.innerHTML = glossaryItem.body;
-+ const anchorLinks = glossaryBody.querySelectorAll('a[href^="#"]');
-+ anchorLinks.forEach(function (link) {
-+ const currentUrl = link.getAttribute("href");
-+ link.href = GLOSSARY_PAGE + currentUrl;
-+ });
-+
-+ const glossaryResult = document.getElementById("glossary-result");
-+ glossaryResult.style.display = "";
-+};
-+
-+if (document.readyState !== "loading") {
-+ glossary_search().catch(console.error);
-+} else {
-+ document.addEventListener("DOMContentLoaded", glossary_search);
-+}
---- /dev/null
-+++ b/Doc/tools/static/rtd_switcher.js
-@@ -0,0 +1,55 @@
-+ function onSwitch(event) {
-+ const option = event.target.selectedIndex;
-+ const item = event.target.options[option];
-+ window.location.href = item.dataset.url;
-+ }
-+
-+ document.addEventListener("readthedocs-addons-data-ready", function(event) {
-+ const config = event.detail.data()
-+ const versionSelect = `
-+
-+ `;
-+
-+ // Prepend the current language to the options on the selector
-+ let languages = config.projects.translations.concat(config.projects.current);
-+ languages = languages.sort((a, b) => a.language.name.localeCompare(b.language.name));
-+
-+ const languageSelect = `
-+
-+ `;
-+
-+ // Query all the placeholders because there are different ones for Desktop/Mobile
-+ const versionPlaceholders = document.querySelectorAll(".version_switcher_placeholder");
-+ for (placeholder of versionPlaceholders) {
-+ placeholder.innerHTML = versionSelect;
-+ let selectElement = placeholder.querySelector("select");
-+ selectElement.addEventListener("change", onSwitch);
-+ }
-+
-+ const languagePlaceholders = document.querySelectorAll(".language_switcher_placeholder");
-+ for (placeholder of languagePlaceholders) {
-+ placeholder.innerHTML = languageSelect;
-+ let selectElement = placeholder.querySelector("select");
-+ selectElement.addEventListener("change", onSwitch);
-+ }
-+ });
-diff --git a/Doc/tools/templates/download.html b/Doc/tools/templates/download.html
-index b5353d6fb77..9f99eea6f3c 100644
---- a/Doc/tools/templates/download.html
-+++ b/Doc/tools/templates/download.html
-@@ -1,5 +1,5 @@
- {% extends "layout.html" %}
--{% set title = 'Download' %}
-+{% set title = _('Download') %}
- {% if daily is defined %}
- {% set dlbase = pathto('archives', 1) %}
- {% else %}
-@@ -11,54 +11,68 @@
- {% endif %}
-
- {% block body %}
--
Download Python {{ release }} Documentation
-+
{% trans %}Download Python {{ release }} Documentation{% endtrans %}
-
--{% if last_updated %}
Last updated on: {{ last_updated }}.
{% endif %}
-+{% if last_updated %}
{% trans %}Last updated on: {{ last_updated }}.{% endtrans %}
{% endif %}
-
--
To download an archive containing all the documents for this version of
--Python in one of various formats, follow one of links in this table.
-+
{% trans %}To download an archive containing all the documents for this version of
-+Python in one of various formats, follow one of links in this table.{% endtrans %}
These archives contain all the content in the documentation.
-+
{% trans %}These archives contain all the content in the documentation.{% endtrans %}
-
-
--
Unpacking
-+
{% trans %}Unpacking{% endtrans %}
-
--
Unix users should download the .tar.bz2 archives; these are bzipped tar
-+
{% trans %}Unix users should download the .tar.bz2 archives; these are bzipped tar
- archives and can be handled in the usual way using tar and the bzip2
- program. The Info-ZIP unzip program can be
- used to handle the ZIP archives if desired. The .tar.bz2 archives provide the
--best compression and fastest download times.
-+best compression and fastest download times.{% endtrans %}
-
--
Windows users can use the ZIP archives since those are customary on that
--platform. These are created on Unix using the Info-ZIP zip program.
-+
{% trans %}Windows users can use the ZIP archives since those are customary on that
-+platform. These are created on Unix using the Info-ZIP zip program.{% endtrans %}
-
-
--
Problems
-+
{% trans %}Problems{% endtrans %}
-
--
If you have comments or suggestions for the Python documentation, please send
--email to docs@python.org.
-+
{% trans %}If you have comments or suggestions for the Python documentation, please send
-+email to docs@python.org.{% endtrans %}