diff options
141 files changed, 2917 insertions, 1415 deletions
diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 4683848ab5e..be63fcb48bb 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -13,7 +13,10 @@ on: - "Lib/test/libregrtest/**" - "Lib/tomllib/**" - "Misc/mypy/**" + - "Tools/build/compute-changes.py" - "Tools/build/generate_sbom.py" + - "Tools/build/verify_ensurepip_wheels.py" + - "Tools/build/update_file.py" - "Tools/cases_generator/**" - "Tools/clinic/**" - "Tools/jit/**" diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 1cab3ce3061..8eabc0406b1 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -16,19 +16,6 @@ Importing Modules This is a wrapper around :c:func:`PyImport_Import()` which takes a :c:expr:`const char *` as an argument instead of a :c:expr:`PyObject *`. -.. c:function:: PyObject* PyImport_ImportModuleNoBlock(const char *name) - - This function is a deprecated alias of :c:func:`PyImport_ImportModule`. - - .. versionchanged:: 3.3 - This function used to fail immediately when the import lock was held - by another thread. In Python 3.3 though, the locking scheme switched - to per-module locks for most purposes, so this function's special - behaviour isn't needed anymore. - - .. deprecated-removed:: 3.13 3.15 - Use :c:func:`PyImport_ImportModule` instead. - .. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index c8c60eb9f48..2bad0bab224 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -826,14 +826,17 @@ frequently used builds will be described in the remainder of this section. Compiling the interpreter with the :c:macro:`!Py_DEBUG` macro defined produces what is generally meant by :ref:`a debug build of Python <debug-build>`. -:c:macro:`!Py_DEBUG` is enabled in the Unix build by adding -:option:`--with-pydebug` to the :file:`./configure` command. -It is also implied by the presence of the -not-Python-specific :c:macro:`!_DEBUG` macro. When :c:macro:`!Py_DEBUG` is enabled -in the Unix build, compiler optimization is disabled. + +On Unix, :c:macro:`!Py_DEBUG` can be enabled by adding :option:`--with-pydebug` +to the :file:`./configure` command. This will also disable compiler optimization. + +On Windows, selecting a debug build (e.g., by passing the :option:`-d` option to +:file:`PCbuild/build.bat`) automatically enables :c:macro:`!Py_DEBUG`. +Additionally, the presence of the not-Python-specific :c:macro:`!_DEBUG` macro, +when defined by the compiler, will also implicitly enable :c:macro:`!Py_DEBUG`. In addition to the reference count debugging described below, extra checks are -performed, see :ref:`Python Debug Build <debug-build>`. +performed. See :ref:`Python Debug Build <debug-build>` for more details. Defining :c:macro:`Py_TRACE_REFS` enables reference tracing (see the :option:`configure --with-trace-refs option <--with-trace-refs>`). diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat index ca99b9e6d37..14990bee6e4 100644 --- a/Doc/data/refcounts.dat +++ b/Doc/data/refcounts.dat @@ -1093,9 +1093,6 @@ PyImport_ImportModuleLevelObject:PyObject*:locals:0:??? PyImport_ImportModuleLevelObject:PyObject*:fromlist:0:??? PyImport_ImportModuleLevelObject:int:level:: -PyImport_ImportModuleNoBlock:PyObject*::+1: -PyImport_ImportModuleNoBlock:const char*:name:: - PyImport_ReloadModule:PyObject*::+1: PyImport_ReloadModule:PyObject*:m:0: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 3d68487d07b..a8658d8b80e 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -323,7 +323,6 @@ 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 diff --git a/Doc/deprecations/c-api-pending-removal-in-3.15.rst b/Doc/deprecations/c-api-pending-removal-in-3.15.rst index a5cc8f1d5b3..a391566c82c 100644 --- a/Doc/deprecations/c-api-pending-removal-in-3.15.rst +++ b/Doc/deprecations/c-api-pending-removal-in-3.15.rst @@ -2,7 +2,7 @@ Pending removal in Python 3.15 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * The bundled copy of ``libmpdecimal``. -* The :c:func:`PyImport_ImportModuleNoBlock`: +* The :c:func:`!PyImport_ImportModuleNoBlock`: Use :c:func:`PyImport_ImportModule` instead. * :c:func:`PyWeakref_GetObject` and :c:func:`PyWeakref_GET_OBJECT`: Use :c:func:`PyWeakref_GetRef` instead. The `pythoncapi-compat project diff --git a/Doc/deprecations/pending-removal-in-3.14.rst b/Doc/deprecations/pending-removal-in-3.14.rst index 6159fa48848..9aac10840a6 100644 --- a/Doc/deprecations/pending-removal-in-3.14.rst +++ b/Doc/deprecations/pending-removal-in-3.14.rst @@ -78,7 +78,7 @@ Pending removal in Python 3.14 :meth:`~pathlib.PurePath.relative_to`: passing additional arguments is deprecated. -* :mod:`pkgutil`: :func:`!pkgutil.find_loader` and :func:!pkgutil.get_loader` +* :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`.) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index 7efae9e628b..3c8d9ab111e 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -6,8 +6,9 @@ .. versionadded:: 3.2 -**Source code:** :source:`Lib/concurrent/futures/thread.py` -and :source:`Lib/concurrent/futures/process.py` +**Source code:** :source:`Lib/concurrent/futures/thread.py`, +:source:`Lib/concurrent/futures/process.py`, +and :source:`Lib/concurrent/futures/interpreter.py` -------------- diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst index 3a933dff057..3e75621be6d 100644 --- a/Doc/library/functools.rst +++ b/Doc/library/functools.rst @@ -403,8 +403,7 @@ The :mod:`functools` module defines the following functions: >>> remove_first_dear(message) 'Hello, dear world!' - :data:`!Placeholder` has no special treatment when used in a keyword - argument to :func:`!partial`. + :data:`!Placeholder` cannot be passed to :func:`!partial` as a keyword argument. .. versionchanged:: 3.14 Added support for :data:`Placeholder` in positional arguments. diff --git a/Doc/library/heapq-binary-tree.svg b/Doc/library/heapq-binary-tree.svg new file mode 100644 index 00000000000..074a9a44275 --- /dev/null +++ b/Doc/library/heapq-binary-tree.svg @@ -0,0 +1,211 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="89.9 70 450.78 193.82"> +<defs> +<g> +<g id="glyph-0-0"> +<path d="M 4.578125 -3.1875 C 4.578125 -3.984375 4.53125 -4.78125 4.1875 -5.515625 C 3.734375 -6.484375 2.90625 -6.640625 2.5 -6.640625 C 1.890625 -6.640625 1.171875 -6.375 0.75 -5.453125 C 0.4375 -4.765625 0.390625 -3.984375 0.390625 -3.1875 C 0.390625 -2.4375 0.421875 -1.546875 0.84375 -0.78125 C 1.265625 0.015625 2 0.21875 2.484375 0.21875 C 3.015625 0.21875 3.78125 0.015625 4.21875 -0.9375 C 4.53125 -1.625 4.578125 -2.40625 4.578125 -3.1875 Z M 2.484375 0 C 2.09375 0 1.5 -0.25 1.328125 -1.203125 C 1.21875 -1.796875 1.21875 -2.71875 1.21875 -3.3125 C 1.21875 -3.953125 1.21875 -4.609375 1.296875 -5.140625 C 1.484375 -6.328125 2.234375 -6.421875 2.484375 -6.421875 C 2.8125 -6.421875 3.46875 -6.234375 3.65625 -5.25 C 3.765625 -4.6875 3.765625 -3.9375 3.765625 -3.3125 C 3.765625 -2.5625 3.765625 -1.890625 3.65625 -1.25 C 3.5 -0.296875 2.9375 0 2.484375 0 Z M 2.484375 0 "/> +</g> +<g id="glyph-0-1"> +<path d="M 2.9375 -6.375 C 2.9375 -6.625 2.9375 -6.640625 2.703125 -6.640625 C 2.078125 -6 1.203125 -6 0.890625 -6 L 0.890625 -5.6875 C 1.09375 -5.6875 1.671875 -5.6875 2.1875 -5.953125 L 2.1875 -0.78125 C 2.1875 -0.421875 2.15625 -0.3125 1.265625 -0.3125 L 0.953125 -0.3125 L 0.953125 0 C 1.296875 -0.03125 2.15625 -0.03125 2.5625 -0.03125 C 2.953125 -0.03125 3.828125 -0.03125 4.171875 0 L 4.171875 -0.3125 L 3.859375 -0.3125 C 2.953125 -0.3125 2.9375 -0.421875 2.9375 -0.78125 Z M 2.9375 -6.375 "/> +</g> +<g id="glyph-0-2"> +<path d="M 2.890625 -3.515625 C 3.703125 -3.78125 4.28125 -4.46875 4.28125 -5.265625 C 4.28125 -6.078125 3.40625 -6.640625 2.453125 -6.640625 C 1.453125 -6.640625 0.6875 -6.046875 0.6875 -5.28125 C 0.6875 -4.953125 0.90625 -4.765625 1.203125 -4.765625 C 1.5 -4.765625 1.703125 -4.984375 1.703125 -5.28125 C 1.703125 -5.765625 1.234375 -5.765625 1.09375 -5.765625 C 1.390625 -6.265625 2.046875 -6.390625 2.40625 -6.390625 C 2.828125 -6.390625 3.375 -6.171875 3.375 -5.28125 C 3.375 -5.15625 3.34375 -4.578125 3.09375 -4.140625 C 2.796875 -3.65625 2.453125 -3.625 2.203125 -3.625 C 2.125 -3.609375 1.890625 -3.59375 1.8125 -3.59375 C 1.734375 -3.578125 1.671875 -3.5625 1.671875 -3.46875 C 1.671875 -3.359375 1.734375 -3.359375 1.90625 -3.359375 L 2.34375 -3.359375 C 3.15625 -3.359375 3.53125 -2.6875 3.53125 -1.703125 C 3.53125 -0.34375 2.84375 -0.0625 2.40625 -0.0625 C 1.96875 -0.0625 1.21875 -0.234375 0.875 -0.8125 C 1.21875 -0.765625 1.53125 -0.984375 1.53125 -1.359375 C 1.53125 -1.71875 1.265625 -1.921875 0.984375 -1.921875 C 0.734375 -1.921875 0.421875 -1.78125 0.421875 -1.34375 C 0.421875 -0.4375 1.34375 0.21875 2.4375 0.21875 C 3.65625 0.21875 4.5625 -0.6875 4.5625 -1.703125 C 4.5625 -2.515625 3.921875 -3.296875 2.890625 -3.515625 Z M 2.890625 -3.515625 "/> +</g> +<g id="glyph-0-3"> +<path d="M 4.75 -6.078125 C 4.828125 -6.1875 4.828125 -6.203125 4.828125 -6.421875 L 2.40625 -6.421875 C 1.203125 -6.421875 1.171875 -6.546875 1.140625 -6.734375 L 0.890625 -6.734375 L 0.5625 -4.6875 L 0.8125 -4.6875 C 0.84375 -4.84375 0.921875 -5.46875 1.0625 -5.59375 C 1.125 -5.65625 1.90625 -5.65625 2.03125 -5.65625 L 4.09375 -5.65625 C 3.984375 -5.5 3.203125 -4.40625 2.984375 -4.078125 C 2.078125 -2.734375 1.75 -1.34375 1.75 -0.328125 C 1.75 -0.234375 1.75 0.21875 2.21875 0.21875 C 2.671875 0.21875 2.671875 -0.234375 2.671875 -0.328125 L 2.671875 -0.84375 C 2.671875 -1.390625 2.703125 -1.9375 2.78125 -2.46875 C 2.828125 -2.703125 2.953125 -3.5625 3.40625 -4.171875 Z M 4.75 -6.078125 "/> +</g> +<g id="glyph-0-4"> +<path d="M 4.46875 -2 C 4.46875 -3.1875 3.65625 -4.1875 2.578125 -4.1875 C 2.109375 -4.1875 1.671875 -4.03125 1.3125 -3.671875 L 1.3125 -5.625 C 1.515625 -5.5625 1.84375 -5.5 2.15625 -5.5 C 3.390625 -5.5 4.09375 -6.40625 4.09375 -6.53125 C 4.09375 -6.59375 4.0625 -6.640625 3.984375 -6.640625 C 3.984375 -6.640625 3.953125 -6.640625 3.90625 -6.609375 C 3.703125 -6.515625 3.21875 -6.3125 2.546875 -6.3125 C 2.15625 -6.3125 1.6875 -6.390625 1.21875 -6.59375 C 1.140625 -6.625 1.125 -6.625 1.109375 -6.625 C 1 -6.625 1 -6.546875 1 -6.390625 L 1 -3.4375 C 1 -3.265625 1 -3.1875 1.140625 -3.1875 C 1.21875 -3.1875 1.234375 -3.203125 1.28125 -3.265625 C 1.390625 -3.421875 1.75 -3.96875 2.5625 -3.96875 C 3.078125 -3.96875 3.328125 -3.515625 3.40625 -3.328125 C 3.5625 -2.953125 3.59375 -2.578125 3.59375 -2.078125 C 3.59375 -1.71875 3.59375 -1.125 3.34375 -0.703125 C 3.109375 -0.3125 2.734375 -0.0625 2.28125 -0.0625 C 1.5625 -0.0625 0.984375 -0.59375 0.8125 -1.171875 C 0.84375 -1.171875 0.875 -1.15625 0.984375 -1.15625 C 1.3125 -1.15625 1.484375 -1.40625 1.484375 -1.640625 C 1.484375 -1.890625 1.3125 -2.140625 0.984375 -2.140625 C 0.84375 -2.140625 0.5 -2.0625 0.5 -1.609375 C 0.5 -0.75 1.1875 0.21875 2.296875 0.21875 C 3.453125 0.21875 4.46875 -0.734375 4.46875 -2 Z M 4.46875 -2 "/> +</g> +<g id="glyph-0-5"> +<path d="M 1.3125 -3.265625 L 1.3125 -3.515625 C 1.3125 -6.03125 2.546875 -6.390625 3.0625 -6.390625 C 3.296875 -6.390625 3.71875 -6.328125 3.9375 -5.984375 C 3.78125 -5.984375 3.390625 -5.984375 3.390625 -5.546875 C 3.390625 -5.234375 3.625 -5.078125 3.84375 -5.078125 C 4 -5.078125 4.3125 -5.171875 4.3125 -5.5625 C 4.3125 -6.15625 3.875 -6.640625 3.046875 -6.640625 C 1.765625 -6.640625 0.421875 -5.359375 0.421875 -3.15625 C 0.421875 -0.484375 1.578125 0.21875 2.5 0.21875 C 3.609375 0.21875 4.5625 -0.71875 4.5625 -2.03125 C 4.5625 -3.296875 3.671875 -4.25 2.5625 -4.25 C 1.890625 -4.25 1.515625 -3.75 1.3125 -3.265625 Z M 2.5 -0.0625 C 1.875 -0.0625 1.578125 -0.65625 1.515625 -0.8125 C 1.328125 -1.28125 1.328125 -2.078125 1.328125 -2.25 C 1.328125 -3.03125 1.65625 -4.03125 2.546875 -4.03125 C 2.71875 -4.03125 3.171875 -4.03125 3.484375 -3.40625 C 3.65625 -3.046875 3.65625 -2.53125 3.65625 -2.046875 C 3.65625 -1.5625 3.65625 -1.0625 3.484375 -0.703125 C 3.1875 -0.109375 2.734375 -0.0625 2.5 -0.0625 Z M 2.5 -0.0625 "/> +</g> +<g id="glyph-0-6"> +<path d="M 1.625 -4.5625 C 1.171875 -4.859375 1.125 -5.1875 1.125 -5.359375 C 1.125 -5.96875 1.78125 -6.390625 2.484375 -6.390625 C 3.203125 -6.390625 3.84375 -5.875 3.84375 -5.15625 C 3.84375 -4.578125 3.453125 -4.109375 2.859375 -3.765625 Z M 3.078125 -3.609375 C 3.796875 -3.984375 4.28125 -4.5 4.28125 -5.15625 C 4.28125 -6.078125 3.40625 -6.640625 2.5 -6.640625 C 1.5 -6.640625 0.6875 -5.90625 0.6875 -4.96875 C 0.6875 -4.796875 0.703125 -4.34375 1.125 -3.875 C 1.234375 -3.765625 1.609375 -3.515625 1.859375 -3.34375 C 1.28125 -3.046875 0.421875 -2.5 0.421875 -1.5 C 0.421875 -0.453125 1.4375 0.21875 2.484375 0.21875 C 3.609375 0.21875 4.5625 -0.609375 4.5625 -1.671875 C 4.5625 -2.03125 4.453125 -2.484375 4.0625 -2.90625 C 3.875 -3.109375 3.71875 -3.203125 3.078125 -3.609375 Z M 2.078125 -3.1875 L 3.3125 -2.40625 C 3.59375 -2.21875 4.0625 -1.921875 4.0625 -1.3125 C 4.0625 -0.578125 3.3125 -0.0625 2.5 -0.0625 C 1.640625 -0.0625 0.921875 -0.671875 0.921875 -1.5 C 0.921875 -2.078125 1.234375 -2.71875 2.078125 -3.1875 Z M 2.078125 -3.1875 "/> +</g> +<g id="glyph-0-7"> +<path d="M 2.9375 -1.640625 L 2.9375 -0.78125 C 2.9375 -0.421875 2.90625 -0.3125 2.171875 -0.3125 L 1.96875 -0.3125 L 1.96875 0 C 2.375 -0.03125 2.890625 -0.03125 3.3125 -0.03125 C 3.734375 -0.03125 4.25 -0.03125 4.671875 0 L 4.671875 -0.3125 L 4.453125 -0.3125 C 3.71875 -0.3125 3.703125 -0.421875 3.703125 -0.78125 L 3.703125 -1.640625 L 4.6875 -1.640625 L 4.6875 -1.953125 L 3.703125 -1.953125 L 3.703125 -6.484375 C 3.703125 -6.6875 3.703125 -6.75 3.53125 -6.75 C 3.453125 -6.75 3.421875 -6.75 3.34375 -6.625 L 0.28125 -1.953125 L 0.28125 -1.640625 Z M 2.984375 -1.953125 L 0.5625 -1.953125 L 2.984375 -5.671875 Z M 2.984375 -1.953125 "/> +</g> +<g id="glyph-0-8"> +<path d="M 3.65625 -3.171875 L 3.65625 -2.84375 C 3.65625 -0.515625 2.625 -0.0625 2.046875 -0.0625 C 1.875 -0.0625 1.328125 -0.078125 1.0625 -0.421875 C 1.5 -0.421875 1.578125 -0.703125 1.578125 -0.875 C 1.578125 -1.1875 1.34375 -1.328125 1.125 -1.328125 C 0.96875 -1.328125 0.671875 -1.25 0.671875 -0.859375 C 0.671875 -0.1875 1.203125 0.21875 2.046875 0.21875 C 3.34375 0.21875 4.5625 -1.140625 4.5625 -3.28125 C 4.5625 -5.96875 3.40625 -6.640625 2.515625 -6.640625 C 1.96875 -6.640625 1.484375 -6.453125 1.0625 -6.015625 C 0.640625 -5.5625 0.421875 -5.140625 0.421875 -4.390625 C 0.421875 -3.15625 1.296875 -2.171875 2.40625 -2.171875 C 3.015625 -2.171875 3.421875 -2.59375 3.65625 -3.171875 Z M 2.421875 -2.40625 C 2.265625 -2.40625 1.796875 -2.40625 1.5 -3.03125 C 1.3125 -3.40625 1.3125 -3.890625 1.3125 -4.390625 C 1.3125 -4.921875 1.3125 -5.390625 1.53125 -5.765625 C 1.796875 -6.265625 2.171875 -6.390625 2.515625 -6.390625 C 2.984375 -6.390625 3.3125 -6.046875 3.484375 -5.609375 C 3.59375 -5.28125 3.640625 -4.65625 3.640625 -4.203125 C 3.640625 -3.375 3.296875 -2.40625 2.421875 -2.40625 Z M 2.421875 -2.40625 "/> +</g> +<g id="glyph-0-9"> +<path d="M 1.265625 -0.765625 L 2.328125 -1.796875 C 3.875 -3.171875 4.46875 -3.703125 4.46875 -4.703125 C 4.46875 -5.84375 3.578125 -6.640625 2.359375 -6.640625 C 1.234375 -6.640625 0.5 -5.71875 0.5 -4.828125 C 0.5 -4.28125 1 -4.28125 1.03125 -4.28125 C 1.203125 -4.28125 1.546875 -4.390625 1.546875 -4.8125 C 1.546875 -5.0625 1.359375 -5.328125 1.015625 -5.328125 C 0.9375 -5.328125 0.921875 -5.328125 0.890625 -5.3125 C 1.109375 -5.96875 1.65625 -6.328125 2.234375 -6.328125 C 3.140625 -6.328125 3.5625 -5.515625 3.5625 -4.703125 C 3.5625 -3.90625 3.078125 -3.125 2.515625 -2.5 L 0.609375 -0.375 C 0.5 -0.265625 0.5 -0.234375 0.5 0 L 4.203125 0 L 4.46875 -1.734375 L 4.234375 -1.734375 C 4.171875 -1.4375 4.109375 -1 4 -0.84375 C 3.9375 -0.765625 3.28125 -0.765625 3.0625 -0.765625 Z M 1.265625 -0.765625 "/> +</g> +</g> +</defs> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 8.754781 -0.000125 C 8.754781 4.835813 4.832906 8.753781 0.000875 8.753781 C -4.835062 8.753781 -8.753031 4.835813 -8.753031 -0.000125 C -8.753031 -4.836062 -4.835062 -8.754031 0.000875 -8.754031 C 4.832906 -8.754031 8.754781 -4.836062 8.754781 -0.000125 Z M 8.754781 -0.000125 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-0" x="312.806" y="84.163"/> +</g> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -104.635844 -42.519656 C -104.635844 -37.687625 -108.553812 -33.76575 -113.385844 -33.76575 C -118.221781 -33.76575 -122.13975 -37.687625 -122.13975 -42.519656 C -122.13975 -47.355594 -118.221781 -51.273562 -113.385844 -51.273562 C -108.553812 -51.273562 -104.635844 -47.355594 -104.635844 -42.519656 Z M -104.635844 -42.519656 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="199.42" y="126.682"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -8.381937 -3.144656 L -105.006937 -39.375125 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -161.32725 -85.039187 C -161.32725 -80.207156 -165.245219 -76.289187 -170.081156 -76.289187 C -174.917094 -76.289187 -178.835062 -80.207156 -178.835062 -85.039187 C -178.835062 -89.875125 -174.917094 -93.793094 -170.081156 -93.793094 C -165.245219 -93.793094 -161.32725 -89.875125 -161.32725 -85.039187 Z M -161.32725 -85.039187 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-2" x="142.727" y="169.202"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -120.549906 -47.89075 L -162.921 -79.668094 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -189.674906 -127.558719 C -189.674906 -122.726687 -193.592875 -118.808719 -198.428812 -118.808719 C -203.260844 -118.808719 -207.182719 -122.726687 -207.182719 -127.558719 C -207.182719 -132.394656 -203.260844 -136.312625 -198.428812 -136.312625 C -193.592875 -136.312625 -189.674906 -132.394656 -189.674906 -127.558719 Z M -189.674906 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-3" x="114.38" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -175.046 -92.488406 L -193.463969 -120.113406 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -202.026469 -170.082156 C -202.026469 -164.242312 -206.760844 -159.507937 -212.600687 -159.507937 C -218.440531 -159.507937 -223.174906 -164.242312 -223.174906 -170.082156 C -223.174906 -175.922 -218.440531 -180.652469 -212.600687 -180.652469 C -206.760844 -180.652469 -202.026469 -175.922 -202.026469 -170.082156 Z M -202.026469 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="97.717" y="254.241"/> +<use xlink:href="#glyph-0-4" x="102.6983" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -201.256937 -136.054812 L -209.194437 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -173.678812 -170.082156 C -173.678812 -164.242312 -178.413187 -159.507937 -184.253031 -159.507937 C -190.092875 -159.507937 -194.82725 -164.242312 -194.82725 -170.082156 C -194.82725 -175.922 -190.092875 -180.652469 -184.253031 -180.652469 C -178.413187 -180.652469 -173.678812 -175.922 -173.678812 -170.082156 Z M -173.678812 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="126.063" y="254.241"/> +<use xlink:href="#glyph-0-5" x="131.0443" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -195.596781 -136.054812 L -187.659281 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -132.979594 -127.558719 C -132.979594 -122.726687 -136.901469 -118.808719 -141.7335 -118.808719 C -146.569437 -118.808719 -150.487406 -122.726687 -150.487406 -127.558719 C -150.487406 -132.394656 -146.569437 -136.312625 -141.7335 -136.312625 C -136.901469 -136.312625 -132.979594 -132.394656 -132.979594 -127.558719 Z M -132.979594 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-6" x="171.073" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -165.116312 -92.488406 L -146.698344 -120.113406 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -145.335062 -170.082156 C -145.335062 -164.242312 -150.069437 -159.507937 -155.909281 -159.507937 C -161.745219 -159.507937 -166.479594 -164.242312 -166.479594 -170.082156 C -166.479594 -175.922 -161.745219 -180.652469 -155.909281 -180.652469 C -150.069437 -180.652469 -145.335062 -175.922 -145.335062 -170.082156 Z M -145.335062 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="154.409" y="254.241"/> +<use xlink:href="#glyph-0-3" x="159.3903" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -144.565531 -136.054812 L -152.499125 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -116.987406 -170.082156 C -116.987406 -164.242312 -121.721781 -159.507937 -127.561625 -159.507937 C -133.401469 -159.507937 -138.135844 -164.242312 -138.135844 -170.082156 C -138.135844 -175.922 -133.401469 -180.652469 -127.561625 -180.652469 C -121.721781 -180.652469 -116.987406 -175.922 -116.987406 -170.082156 Z M -116.987406 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="182.756" y="254.241"/> +<use xlink:href="#glyph-0-6" x="187.7373" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -138.901469 -136.054812 L -130.967875 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -47.940531 -85.039187 C -47.940531 -80.207156 -51.8585 -76.289187 -56.694437 -76.289187 C -61.526469 -76.289187 -65.448344 -80.207156 -65.448344 -85.039187 C -65.448344 -89.875125 -61.526469 -93.793094 -56.694437 -93.793094 C -51.8585 -93.793094 -47.940531 -89.875125 -47.940531 -85.039187 Z M -47.940531 -85.039187 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-7" x="256.113" y="169.202"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -106.225687 -47.89075 L -63.854594 -79.668094 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -76.288187 -127.558719 C -76.288187 -122.726687 -80.206156 -118.808719 -85.042094 -118.808719 C -89.874125 -118.808719 -93.792094 -122.726687 -93.792094 -127.558719 C -93.792094 -132.394656 -89.874125 -136.312625 -85.042094 -136.312625 C -80.206156 -136.312625 -76.288187 -132.394656 -76.288187 -127.558719 Z M -76.288187 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-8" x="227.766" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -61.659281 -92.488406 L -80.073344 -120.113406 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -88.63975 -170.082156 C -88.63975 -164.242312 -93.374125 -159.507937 -99.213969 -159.507937 C -105.053812 -159.507937 -109.788187 -164.242312 -109.788187 -170.082156 C -109.788187 -175.922 -105.053812 -180.652469 -99.213969 -180.652469 C -93.374125 -180.652469 -88.63975 -175.922 -88.63975 -170.082156 Z M -88.63975 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="211.102" y="254.241"/> +<use xlink:href="#glyph-0-8" x="216.0833" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -87.870219 -136.054812 L -95.807719 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -60.292094 -170.082156 C -60.292094 -164.242312 -65.026469 -159.507937 -70.866312 -159.507937 C -76.706156 -159.507937 -81.440531 -164.242312 -81.440531 -170.082156 C -81.440531 -175.922 -76.706156 -180.652469 -70.866312 -180.652469 C -65.026469 -180.652469 -60.292094 -175.922 -60.292094 -170.082156 Z M -60.292094 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="239.449" y="254.241"/> +<use xlink:href="#glyph-0-0" x="244.4303" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -82.210062 -136.054812 L -74.272562 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -17.772562 -127.558719 C -17.772562 -121.722781 -22.506937 -116.988406 -28.346781 -116.988406 C -34.186625 -116.988406 -38.921 -121.722781 -38.921 -127.558719 C -38.921 -133.398562 -34.186625 -138.132937 -28.346781 -138.132937 C -22.506937 -138.132937 -17.772562 -133.398562 -17.772562 -127.558719 Z M -17.772562 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="281.968" y="211.722"/> +<use xlink:href="#glyph-0-0" x="286.9493" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -51.729594 -92.488406 L -34.323344 -118.597781 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -31.948344 -170.082156 C -31.948344 -164.242312 -36.678812 -159.507937 -42.518656 -159.507937 C -48.3585 -159.507937 -53.092875 -164.242312 -53.092875 -170.082156 C -53.092875 -175.922 -48.3585 -180.652469 -42.518656 -180.652469 C -36.678812 -180.652469 -31.948344 -175.922 -31.948344 -170.082156 Z M -31.948344 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="267.795" y="254.241"/> +<use xlink:href="#glyph-0-1" x="272.7763" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -31.753031 -137.781375 L -39.112406 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M -3.600687 -170.082156 C -3.600687 -164.242312 -8.335062 -159.507937 -14.174906 -159.507937 C -20.01475 -159.507937 -24.745219 -164.242312 -24.745219 -170.082156 C -24.745219 -175.922 -20.01475 -180.652469 -14.174906 -180.652469 C -8.335062 -180.652469 -3.600687 -175.922 -3.600687 -170.082156 Z M -3.600687 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="296.142" y="254.241"/> +<use xlink:href="#glyph-0-9" x="301.1233" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M -24.940531 -137.781375 L -17.581156 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 122.1415 -42.519656 C 122.1415 -37.687625 118.223531 -33.76575 113.387594 -33.76575 C 108.551656 -33.76575 104.633688 -37.687625 104.633688 -42.519656 C 104.633688 -47.355594 108.551656 -51.273562 113.387594 -51.273562 C 118.223531 -51.273562 122.1415 -47.355594 122.1415 -42.519656 Z M 122.1415 -42.519656 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="426.191" y="126.682"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 8.383688 -3.144656 L 105.004781 -39.375125 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 65.446188 -85.039187 C 65.446188 -80.207156 61.528219 -76.289187 56.692281 -76.289187 C 51.86025 -76.289187 47.942281 -80.207156 47.942281 -85.039187 C 47.942281 -89.875125 51.86025 -93.793094 56.692281 -93.793094 C 61.528219 -93.793094 65.446188 -89.875125 65.446188 -85.039187 Z M 65.446188 -85.039187 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-4" x="369.498" y="169.202"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 106.227438 -47.89075 L 63.856344 -79.668094 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 38.918844 -127.558719 C 38.918844 -121.722781 34.188375 -116.988406 28.348531 -116.988406 C 22.508688 -116.988406 17.774313 -121.722781 17.774313 -127.558719 C 17.774313 -133.398562 22.508688 -138.132937 28.348531 -138.132937 C 34.188375 -138.132937 38.918844 -133.398562 38.918844 -127.558719 Z M 38.918844 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="338.661" y="211.722"/> +<use xlink:href="#glyph-0-1" x="343.6423" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 51.727438 -92.488406 L 34.321188 -118.597781 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 24.746969 -170.082156 C 24.746969 -164.242312 20.012594 -159.507937 14.17275 -159.507937 C 8.332906 -159.507937 3.598531 -164.242312 3.598531 -170.082156 C 3.598531 -175.922 8.332906 -180.652469 14.17275 -180.652469 C 20.012594 -180.652469 24.746969 -175.922 24.746969 -170.082156 Z M 24.746969 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="324.488" y="254.241"/> +<use xlink:href="#glyph-0-2" x="329.4693" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 24.942281 -137.781375 L 17.579 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 53.094625 -170.082156 C 53.094625 -164.242312 48.36025 -159.507937 42.520406 -159.507937 C 36.680563 -159.507937 31.946188 -164.242312 31.946188 -170.082156 C 31.946188 -175.922 36.680563 -180.652469 42.520406 -180.652469 C 48.36025 -180.652469 53.094625 -175.922 53.094625 -170.082156 Z M 53.094625 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="352.835" y="254.241"/> +<use xlink:href="#glyph-0-7" x="357.8163" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 31.754781 -137.781375 L 39.114156 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 95.614156 -127.558719 C 95.614156 -121.722781 90.879781 -116.988406 85.039938 -116.988406 C 79.200094 -116.988406 74.465719 -121.722781 74.465719 -127.558719 C 74.465719 -133.398562 79.200094 -138.132937 85.039938 -138.132937 C 90.879781 -138.132937 95.614156 -133.398562 95.614156 -127.558719 Z M 95.614156 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="395.354" y="211.722"/> +<use xlink:href="#glyph-0-9" x="400.3353" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 61.661031 -92.488406 L 79.063375 -118.597781 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 81.442281 -170.082156 C 81.442281 -164.242312 76.707906 -159.507937 70.868063 -159.507937 C 65.028219 -159.507937 60.293844 -164.242312 60.293844 -170.082156 C 60.293844 -175.922 65.028219 -180.652469 70.868063 -180.652469 C 76.707906 -180.652469 81.442281 -175.922 81.442281 -170.082156 Z M 81.442281 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="381.181" y="254.241"/> +<use xlink:href="#glyph-0-4" x="386.1623" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 81.633688 -137.781375 L 74.274313 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 109.786031 -170.082156 C 109.786031 -164.242312 105.051656 -159.507937 99.215719 -159.507937 C 93.375875 -159.507937 88.6415 -164.242312 88.6415 -170.082156 C 88.6415 -175.922 93.375875 -180.652469 99.215719 -180.652469 C 105.051656 -180.652469 109.786031 -175.922 109.786031 -170.082156 Z M 109.786031 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="409.527" y="254.241"/> +<use xlink:href="#glyph-0-5" x="414.5083" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 88.446188 -137.781375 L 95.805563 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 178.832906 -85.039187 C 178.832906 -80.207156 174.914938 -76.289187 170.079 -76.289187 C 165.246969 -76.289187 161.329 -80.207156 161.329 -85.039187 C 161.329 -89.875125 165.246969 -93.793094 170.079 -93.793094 C 174.914938 -93.793094 178.832906 -89.875125 178.832906 -85.039187 Z M 178.832906 -85.039187 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-5" x="482.884" y="169.202"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 120.54775 -47.89075 L 162.918844 -79.668094 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 152.309469 -127.558719 C 152.309469 -121.722781 147.575094 -116.988406 141.73525 -116.988406 C 135.895406 -116.988406 131.161031 -121.722781 131.161031 -127.558719 C 131.161031 -133.398562 135.895406 -138.132937 141.73525 -138.132937 C 147.575094 -138.132937 152.309469 -133.398562 152.309469 -127.558719 Z M 152.309469 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="452.047" y="211.722"/> +<use xlink:href="#glyph-0-2" x="457.0283" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 165.114156 -92.488406 L 147.707906 -118.597781 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 138.133688 -170.082156 C 138.133688 -164.242312 133.399313 -159.507937 127.559469 -159.507937 C 121.719625 -159.507937 116.989156 -164.242312 116.989156 -170.082156 C 116.989156 -175.922 121.719625 -180.652469 127.559469 -180.652469 C 133.399313 -180.652469 138.133688 -175.922 138.133688 -170.082156 Z M 138.133688 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="437.874" y="254.241"/> +<use xlink:href="#glyph-0-3" x="442.8553" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 138.329 -137.781375 L 130.965719 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 166.481344 -170.082156 C 166.481344 -164.242312 161.746969 -159.507937 155.907125 -159.507937 C 150.067281 -159.507937 145.332906 -164.242312 145.332906 -170.082156 C 145.332906 -175.922 150.067281 -180.652469 155.907125 -180.652469 C 161.746969 -180.652469 166.481344 -175.922 166.481344 -170.082156 Z M 166.481344 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="466.22" y="254.241"/> +<use xlink:href="#glyph-0-6" x="471.2013" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 145.1415 -137.781375 L 152.500875 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 209.000875 -127.558719 C 209.000875 -121.722781 204.2665 -116.988406 198.426656 -116.988406 C 192.586813 -116.988406 187.852438 -121.722781 187.852438 -127.558719 C 187.852438 -133.398562 192.586813 -138.132937 198.426656 -138.132937 C 204.2665 -138.132937 209.000875 -133.398562 209.000875 -127.558719 Z M 209.000875 -127.558719 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-1" x="508.74" y="211.722"/> +<use xlink:href="#glyph-0-7" x="513.7213" y="211.722"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 175.04775 -92.488406 L 192.454 -118.597781 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 194.829 -170.082156 C 194.829 -164.242312 190.094625 -159.507937 184.254781 -159.507937 C 178.414938 -159.507937 173.680563 -164.242312 173.680563 -170.082156 C 173.680563 -175.922 178.414938 -180.652469 184.254781 -180.652469 C 190.094625 -180.652469 194.829 -175.922 194.829 -170.082156 Z M 194.829 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-9" x="494.567" y="254.241"/> +<use xlink:href="#glyph-0-8" x="499.5483" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 195.020406 -137.781375 L 187.661031 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<path fill-rule="nonzero" fill="rgb(79.998779%, 79.998779%, 100%)" fill-opacity="1" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 100%)" stroke-opacity="1" stroke-miterlimit="10" d="M 223.176656 -170.082156 C 223.176656 -164.242312 218.442281 -159.507937 212.602438 -159.507937 C 206.762594 -159.507937 202.028219 -164.242312 202.028219 -170.082156 C 202.028219 -175.922 206.762594 -180.652469 212.602438 -180.652469 C 218.442281 -180.652469 223.176656 -175.922 223.176656 -170.082156 Z M 223.176656 -170.082156 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +<g fill="rgb(0%, 0%, 0%)" fill-opacity="1"> +<use xlink:href="#glyph-0-2" x="522.913" y="254.241"/> +<use xlink:href="#glyph-0-0" x="527.8943" y="254.241"/> +</g> +<path fill="none" stroke-width="0.3985" stroke-linecap="butt" stroke-linejoin="miter" stroke="rgb(0%, 0%, 0%)" stroke-opacity="1" stroke-miterlimit="10" d="M 201.832906 -137.781375 L 209.196188 -159.8595 " transform="matrix(1, 0, 0, -1, 315.296, 80.953)"/> +</svg>
\ No newline at end of file diff --git a/Doc/library/heapq.rst b/Doc/library/heapq.rst index 922ba0c8aa4..183ac9a27d5 100644 --- a/Doc/library/heapq.rst +++ b/Doc/library/heapq.rst @@ -312,17 +312,11 @@ elements are considered to be infinite. The interesting property of a heap is that ``a[0]`` is always its smallest element. The strange invariant above is meant to be an efficient memory representation -for a tournament. The numbers below are *k*, not ``a[k]``:: +for a tournament. The numbers below are *k*, not ``a[k]``: - 0 - - 1 2 - - 3 4 5 6 - - 7 8 9 10 11 12 13 14 - - 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 +.. figure:: heapq-binary-tree.svg + :align: center + :alt: Example (min-heap) binary tree. In the tree above, each cell *k* is topping ``2*k+1`` and ``2*k+2``. In a usual binary tournament we see in sports, each cell is the winner over the two cells diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index c615650b622..2d0f9a740c6 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -259,10 +259,10 @@ Reference Module functions ^^^^^^^^^^^^^^^^ -.. function:: connect(database, timeout=5.0, detect_types=0, \ +.. function:: connect(database, *, timeout=5.0, detect_types=0, \ isolation_level="DEFERRED", check_same_thread=True, \ factory=sqlite3.Connection, cached_statements=128, \ - uri=False, *, \ + uri=False, \ autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL) Open a connection to an SQLite database. @@ -355,11 +355,8 @@ Module functions .. versionchanged:: 3.12 Added the *autocommit* parameter. - .. versionchanged:: 3.13 - Positional use of the parameters *timeout*, *detect_types*, - *isolation_level*, *check_same_thread*, *factory*, *cached_statements*, - and *uri* is deprecated. - They will become keyword-only parameters in Python 3.15. + .. versionchanged:: 3.15 + All parameters except *database* are now keyword-only. .. function:: complete_statement(statement) @@ -693,7 +690,7 @@ Connection objects :meth:`~Cursor.executescript` on it with the given *sql_script*. Return the new cursor object. - .. method:: create_function(name, narg, func, *, deterministic=False) + .. method:: create_function(name, narg, func, /, *, deterministic=False) Create or remove a user-defined SQL function. @@ -719,6 +716,9 @@ Connection objects .. versionchanged:: 3.8 Added the *deterministic* parameter. + .. versionchanged:: 3.15 + The first three parameters are now positional-only. + Example: .. doctest:: @@ -733,13 +733,8 @@ Connection objects ('acbd18db4cc2f85cedef654fccc4a4d8',) >>> con.close() - .. versionchanged:: 3.13 - - Passing *name*, *narg*, and *func* as keyword arguments is deprecated. - These parameters will become positional-only in Python 3.15. - - .. method:: create_aggregate(name, n_arg, aggregate_class) + .. method:: create_aggregate(name, n_arg, aggregate_class, /) Create or remove a user-defined SQL aggregate function. @@ -763,6 +758,9 @@ Connection objects Set to ``None`` to remove an existing SQL aggregate function. :type aggregate_class: :term:`class` | None + .. versionchanged:: 3.15 + All three parameters are now positional-only. + Example: .. testcode:: @@ -792,11 +790,6 @@ Connection objects 3 - .. versionchanged:: 3.13 - - Passing *name*, *n_arg*, and *aggregate_class* as keyword arguments is deprecated. - These parameters will become positional-only in Python 3.15. - .. method:: create_window_function(name, num_params, aggregate_class, /) @@ -937,7 +930,7 @@ Connection objects Aborted queries will raise an :exc:`OperationalError`. - .. method:: set_authorizer(authorizer_callback) + .. method:: set_authorizer(authorizer_callback, /) Register :term:`callable` *authorizer_callback* to be invoked for each attempt to access a column of a table in the database. @@ -962,12 +955,11 @@ Connection objects .. versionchanged:: 3.11 Added support for disabling the authorizer using ``None``. - .. versionchanged:: 3.13 - Passing *authorizer_callback* as a keyword argument is deprecated. - The parameter will become positional-only in Python 3.15. + .. versionchanged:: 3.15 + The only parameter is now positional-only. - .. method:: set_progress_handler(progress_handler, n) + .. method:: set_progress_handler(progress_handler, /, n) Register :term:`callable` *progress_handler* to be invoked for every *n* instructions of the SQLite virtual machine. This is useful if you want to @@ -981,12 +973,11 @@ Connection objects currently executing query and cause it to raise a :exc:`DatabaseError` exception. - .. versionchanged:: 3.13 - Passing *progress_handler* as a keyword argument is deprecated. - The parameter will become positional-only in Python 3.15. + .. versionchanged:: 3.15 + The first parameter is now positional-only. - .. method:: set_trace_callback(trace_callback) + .. method:: set_trace_callback(trace_callback, /) Register :term:`callable` *trace_callback* to be invoked for each SQL statement that is actually executed by the SQLite backend. @@ -1009,9 +1000,8 @@ Connection objects .. versionadded:: 3.3 - .. versionchanged:: 3.13 - Passing *trace_callback* as a keyword argument is deprecated. - The parameter will become positional-only in Python 3.15. + .. versionchanged:: 3.15 + The first parameter is now positional-only. .. method:: enable_load_extension(enabled, /) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 39aaa5da078..61d39a6671c 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4823,7 +4823,13 @@ can be used interchangeably to index the same dictionary entry. being added is already present, the value from the keyword argument replaces the value from the positional argument. - To illustrate, the following examples all return a dictionary equal to + Providing keyword arguments as in the first example only works for keys that + are valid Python identifiers. Otherwise, any valid keys can be used. + + Dictionaries compare equal if and only if they have the same ``(key, + value)`` pairs (regardless of ordering). Order comparisons ('<', '<=', '>=', '>') raise + :exc:`TypeError`. To illustrate dictionary creation and equality, + the following examples all return a dictionary equal to ``{"one": 1, "two": 2, "three": 3}``:: >>> a = dict(one=1, two=2, three=3) @@ -4838,6 +4844,27 @@ can be used interchangeably to index the same dictionary entry. Providing keyword arguments as in the first example only works for keys that are valid Python identifiers. Otherwise, any valid keys can be used. + Dictionaries preserve insertion order. Note that updating a key does not + affect the order. Keys added after deletion are inserted at the end. :: + + >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} + >>> d + {'one': 1, 'two': 2, 'three': 3, 'four': 4} + >>> list(d) + ['one', 'two', 'three', 'four'] + >>> list(d.values()) + [1, 2, 3, 4] + >>> d["one"] = 42 + >>> d + {'one': 42, 'two': 2, 'three': 3, 'four': 4} + >>> del d["two"] + >>> d["two"] = None + >>> d + {'one': 42, 'three': 3, 'four': 4, 'two': None} + + .. versionchanged:: 3.7 + Dictionary order is guaranteed to be insertion order. This behavior was + an implementation detail of CPython from 3.6. These are the operations that dictionaries support (and therefore, custom mapping types should support too): @@ -5008,32 +5035,6 @@ can be used interchangeably to index the same dictionary entry. .. versionadded:: 3.9 - Dictionaries compare equal if and only if they have the same ``(key, - value)`` pairs (regardless of ordering). Order comparisons ('<', '<=', '>=', '>') raise - :exc:`TypeError`. - - Dictionaries preserve insertion order. Note that updating a key does not - affect the order. Keys added after deletion are inserted at the end. :: - - >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} - >>> d - {'one': 1, 'two': 2, 'three': 3, 'four': 4} - >>> list(d) - ['one', 'two', 'three', 'four'] - >>> list(d.values()) - [1, 2, 3, 4] - >>> d["one"] = 42 - >>> d - {'one': 42, 'two': 2, 'three': 3, 'four': 4} - >>> del d["two"] - >>> d["two"] = None - >>> d - {'one': 42, 'three': 3, 'four': 4, 'two': None} - - .. versionchanged:: 3.7 - Dictionary order is guaranteed to be insertion order. This behavior was - an implementation detail of CPython from 3.6. - Dictionaries and dictionary views are reversible. :: >>> d = {"one": 1, "two": 2, "three": 3, "four": 4} diff --git a/Doc/reference/lexical_analysis.rst b/Doc/reference/lexical_analysis.rst index ff801a7d4fc..001e2547fe8 100644 --- a/Doc/reference/lexical_analysis.rst +++ b/Doc/reference/lexical_analysis.rst @@ -35,11 +35,11 @@ Logical lines .. index:: logical line, physical line, line joining, NEWLINE token -The end of a logical line is represented by the token NEWLINE. Statements -cannot cross logical line boundaries except where NEWLINE is allowed by the -syntax (e.g., between statements in compound statements). A logical line is -constructed from one or more *physical lines* by following the explicit or -implicit *line joining* rules. +The end of a logical line is represented by the token :data:`~token.NEWLINE`. +Statements cannot cross logical line boundaries except where :data:`!NEWLINE` +is allowed by the syntax (e.g., between statements in compound statements). +A logical line is constructed from one or more *physical lines* by following +the explicit or implicit *line joining* rules. .. _physical-lines: @@ -99,7 +99,7 @@ which is recognized by Bram Moolenaar's VIM. If no encoding declaration is found, the default encoding is UTF-8. If the implicit or explicit encoding of a file is UTF-8, an initial UTF-8 byte-order -mark (b'\xef\xbb\xbf') is ignored rather than being a syntax error. +mark (``b'\xef\xbb\xbf'``) is ignored rather than being a syntax error. If an encoding is declared, the encoding name must be recognized by Python (see :ref:`standard-encodings`). The @@ -160,11 +160,12 @@ Blank lines .. index:: single: blank line A logical line that contains only spaces, tabs, formfeeds and possibly a -comment, is ignored (i.e., no NEWLINE token is generated). During interactive -input of statements, handling of a blank line may differ depending on the -implementation of the read-eval-print loop. In the standard interactive -interpreter, an entirely blank logical line (i.e. one containing not even -whitespace or a comment) terminates a multi-line statement. +comment, is ignored (i.e., no :data:`~token.NEWLINE` token is generated). +During interactive input of statements, handling of a blank line may differ +depending on the implementation of the read-eval-print loop. +In the standard interactive interpreter, an entirely blank logical line (that +is, one containing not even whitespace or a comment) terminates a multi-line +statement. .. _indentation: @@ -202,19 +203,20 @@ the space count to zero). .. index:: INDENT token, DEDENT token -The indentation levels of consecutive lines are used to generate INDENT and -DEDENT tokens, using a stack, as follows. +The indentation levels of consecutive lines are used to generate +:data:`~token.INDENT` and :data:`~token.DEDENT` tokens, using a stack, +as follows. Before the first line of the file is read, a single zero is pushed on the stack; this will never be popped off again. The numbers pushed on the stack will always be strictly increasing from bottom to top. At the beginning of each logical line, the line's indentation level is compared to the top of the stack. If it is equal, nothing happens. If it is larger, it is pushed on the stack, and -one INDENT token is generated. If it is smaller, it *must* be one of the +one :data:`!INDENT` token is generated. If it is smaller, it *must* be one of the numbers occurring on the stack; all numbers on the stack that are larger are -popped off, and for each number popped off a DEDENT token is generated. At the -end of the file, a DEDENT token is generated for each number remaining on the -stack that is larger than zero. +popped off, and for each number popped off a :data:`!DEDENT` token is generated. +At the end of the file, a :data:`!DEDENT` token is generated for each number +remaining on the stack that is larger than zero. Here is an example of a correctly (though confusingly) indented piece of Python code:: @@ -254,8 +256,18 @@ Whitespace between tokens Except at the beginning of a logical line or in string literals, the whitespace characters space, tab and formfeed can be used interchangeably to separate tokens. Whitespace is needed between two tokens only if their concatenation -could otherwise be interpreted as a different token (e.g., ab is one token, but -a b is two tokens). +could otherwise be interpreted as a different token. For example, ``ab`` is one +token, but ``a b`` is two tokens. However, ``+a`` and ``+ a`` both produce +two tokens, ``+`` and ``a``, as ``+a`` is not a valid token. + + +.. _endmarker-token: + +End marker +---------- + +At the end of non-interactive input, the lexical analyzer generates an +:data:`~token.ENDMARKER` token. .. _other-tokens: @@ -263,11 +275,15 @@ a b is two tokens). Other tokens ============ -Besides NEWLINE, INDENT and DEDENT, the following categories of tokens exist: -*identifiers*, *keywords*, *literals*, *operators*, and *delimiters*. Whitespace -characters (other than line terminators, discussed earlier) are not tokens, but -serve to delimit tokens. Where ambiguity exists, a token comprises the longest -possible string that forms a legal token, when read from left to right. +Besides :data:`~token.NEWLINE`, :data:`~token.INDENT` and :data:`~token.DEDENT`, +the following categories of tokens exist: +*identifiers* and *keywords* (:data:`~token.NAME`), *literals* (such as +:data:`~token.NUMBER` and :data:`~token.STRING`), and other symbols +(*operators* and *delimiters*, :data:`~token.OP`). +Whitespace characters (other than logical line terminators, discussed earlier) +are not tokens, but serve to delimit tokens. +Where ambiguity exists, a token comprises the longest possible string that +forms a legal token, when read from left to right. .. _identifiers: diff --git a/Doc/tutorial/introduction.rst b/Doc/tutorial/introduction.rst index bec5da8fd75..cdb35da7bc9 100644 --- a/Doc/tutorial/introduction.rst +++ b/Doc/tutorial/introduction.rst @@ -147,6 +147,8 @@ Python can manipulate text (represented by type :class:`str`, so-called "``Yay! :)``". They can be enclosed in single quotes (``'...'``) or double quotes (``"..."``) with the same result [#]_. +.. code-block:: pycon + >>> 'spam eggs' # single quotes 'spam eggs' >>> "Paris rabbit got your back :)! Yay!" # double quotes diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst index 74d6db5d7d1..c084392ca66 100644 --- a/Doc/using/windows.rst +++ b/Doc/using/windows.rst @@ -95,6 +95,9 @@ as ``python3.14.exe``) to be available. The directory will be administrator. Click Start and search for "Edit environment variables for your account" for the system settings page to add the path. +Each Python runtime you install will have its own directory for scripts. These +also need to be added to :envvar:`PATH` if you want to use them. + The Python install manager will be automatically updated to new releases. This does not affect any installs of Python runtimes. Uninstalling the Python install manager does not uninstall any Python runtimes. @@ -713,6 +716,16 @@ default). your ``pythonw.exe`` and ``pyw.exe`` aliases are consistent with your others. " + "``pip`` gives me a ""command not found"" error when I type it in my + terminal.","Have you activated a virtual environment? Run the + ``.venv\Scripts\activate`` script in your terminal to activate. + " + "","The package may be available but missing the generated executable. + We recommend using the ``python -m pip`` command instead, or alternatively + the ``python -m pip install --force pip`` command will recreate the + executables and show you the path to add to :envvar:`PATH`. These scripts are + separated for each runtime, and so you may need to add multiple paths. + " .. _windows-embeddable: diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst index 9dbc07a34e2..0803eba99e6 100644 --- a/Doc/whatsnew/2.6.rst +++ b/Doc/whatsnew/2.6.rst @@ -3043,7 +3043,7 @@ Changes to Python's build process and to the C API include: * Importing modules simultaneously in two different threads no longer deadlocks; it will now raise an :exc:`ImportError`. A new API - function, :c:func:`PyImport_ImportModuleNoBlock`, will look for a + function, :c:func:`!PyImport_ImportModuleNoBlock`, will look for a module in ``sys.modules`` first, then try to import it after acquiring an import lock. If the import lock is held by another thread, an :exc:`ImportError` is raised. diff --git a/Doc/whatsnew/3.0.rst b/Doc/whatsnew/3.0.rst index 6e1fda22ed2..d858586138e 100644 --- a/Doc/whatsnew/3.0.rst +++ b/Doc/whatsnew/3.0.rst @@ -870,7 +870,7 @@ to the C API. * :c:func:`!PyNumber_Coerce`, :c:func:`!PyNumber_CoerceEx`, :c:func:`!PyMember_Get`, and :c:func:`!PyMember_Set` C APIs are removed. -* New C API :c:func:`PyImport_ImportModuleNoBlock`, works like +* New C API :c:func:`!PyImport_ImportModuleNoBlock`, works like :c:func:`PyImport_ImportModule` but won't block on the import lock (returning an error instead). diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index e20e49325c0..ff33224e272 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -2499,7 +2499,7 @@ Deprecated C APIs which return a :term:`borrowed reference`. (Soft deprecated as part of :pep:`667`.) -* Deprecate the :c:func:`PyImport_ImportModuleNoBlock` function, +* Deprecate the :c:func:`!PyImport_ImportModuleNoBlock` function, which is just an alias to :c:func:`PyImport_ImportModule` since Python 3.3. (Contributed by Victor Stinner in :gh:`105396`.) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 5e9922069aa..7131eeb697e 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -143,7 +143,16 @@ New features Porting to Python 3.15 ---------------------- -* TODO +* :class:`sqlite3.Connection` APIs has been cleaned up. + + * All parameters of :func:`sqlite3.connect` except *database* are now keyword-only. + * The first three parameters of methods :meth:`~sqlite3.Connection.create_function` + and :meth:`~sqlite3.Connection.create_aggregate` are now positional-only. + * The first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, + :meth:`~sqlite3.Connection.set_progress_handler` and + :meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. + + (Contributed by Serhiy Storchaka in :gh:`133595`.) Deprecated C APIs ----------------- @@ -155,3 +164,5 @@ Deprecated C APIs Removed C APIs -------------- +* :c:func:`!PyImport_ImportModuleNoBlock`: deprecated alias + of :c:func:`PyImport_ImportModule`. diff --git a/Doc/whatsnew/3.3.rst b/Doc/whatsnew/3.3.rst index 7a8eb47cbdb..89fd6868645 100644 --- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -829,7 +829,7 @@ Previous versions of CPython have always relied on a global import lock. This led to unexpected annoyances, such as deadlocks when importing a module would trigger code execution in a different thread as a side-effect. Clumsy workarounds were sometimes employed, such as the -:c:func:`PyImport_ImportModuleNoBlock` C API function. +:c:func:`!PyImport_ImportModuleNoBlock` C API function. In Python 3.3, importing a module takes a per-module lock. This correctly serializes importation of a given module from multiple threads (preventing diff --git a/Grammar/Tokens b/Grammar/Tokens index e40a4437afb..0547e6ed08f 100644 --- a/Grammar/Tokens +++ b/Grammar/Tokens @@ -1,3 +1,8 @@ +# When adding new tokens, remember to update the PEG generator in +# Tools/peg_generator/pegen/parser_generator.py +# This will ensure that older versions of Python can generate a Python parser +# using "python -m pegen python <GRAMMAR FILE>". + ENDMARKER NAME NUMBER diff --git a/Include/import.h b/Include/import.h index 24b23b91191..d91ebe96ca8 100644 --- a/Include/import.h +++ b/Include/import.h @@ -51,9 +51,6 @@ PyAPI_FUNC(PyObject *) PyImport_AddModuleRef( PyAPI_FUNC(PyObject *) PyImport_ImportModule( const char *name /* UTF-8 encoded string */ ); -Py_DEPRECATED(3.13) PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock( - const char *name /* UTF-8 encoded string */ - ); PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel( const char *name, /* UTF-8 encoded string */ PyObject *globals, diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index b135e30b7ad..37a747aa4e3 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -614,6 +614,47 @@ PyAPI_FUNC(int) _PyCode_SetUnboundVarCounts( PyObject *globalsns, PyObject *builtinsns); + +/* "Stateless" code is a function or code object which does not rely on + * external state or internal state. It may rely on arguments and + * builtins, but not globals or a closure. Thus it does not rely + * on __globals__ or __closure__, and a stateless function + * is equivalent to its code object. + * + * Stateless code also does not keep any persistent state + * of its own, so it can't have any executors, monitoring, + * instrumentation, or "extras" (i.e. co_extra). + * + * Stateless code may create nested functions, including closures. + * However, nested functions must themselves be stateless, except they + * *can* close on the enclosing locals. + * + * Stateless code may return any value, including nested functions and closures. + * + * Stateless code that takes no arguments and doesn't return anything + * may be treated like a script. + * + * We consider stateless code to be "portable" if it does not return + * any object that holds a reference to any of the code's locals. Thus + * generators and coroutines are not portable. Likewise a function + * that returns a closure is not portable. The concept of + * portability is useful in cases where the code is run + * in a different execution context than where + * the return value will be used. */ + +PyAPI_FUNC(int) _PyCode_CheckNoInternalState(PyCodeObject *, const char **); +PyAPI_FUNC(int) _PyCode_CheckNoExternalState( + PyCodeObject *, + _PyCode_var_counts_t *, + const char **); +PyAPI_FUNC(int) _PyCode_VerifyStateless( + PyThreadState *, + PyCodeObject *, + PyObject *globalnames, + PyObject *globalsns, + PyObject *builtinsns); + +PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **); PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *); diff --git a/Include/internal/pycore_crossinterp.h b/Include/internal/pycore_crossinterp.h index 9de61ef5412..9c9b2c2f9c5 100644 --- a/Include/internal/pycore_crossinterp.h +++ b/Include/internal/pycore_crossinterp.h @@ -191,6 +191,14 @@ PyAPI_FUNC(int) _PyCode_GetXIData( PyThreadState *, PyObject *, _PyXIData_t *); +PyAPI_FUNC(int) _PyCode_GetScriptXIData( + PyThreadState *, + PyObject *, + _PyXIData_t *); +PyAPI_FUNC(int) _PyCode_GetPureScriptXIData( + PyThreadState *, + PyObject *, + _PyXIData_t *); /* using cross-interpreter data */ diff --git a/Include/internal/pycore_function.h b/Include/internal/pycore_function.h index 209252b2ddc..a30d52d49bd 100644 --- a/Include/internal/pycore_function.h +++ b/Include/internal/pycore_function.h @@ -35,6 +35,13 @@ PyFunctionObject *_PyFunction_LookupByVersion(uint32_t version, PyObject **p_cod extern PyObject *_Py_set_function_type_params( PyThreadState* unused, PyObject *func, PyObject *type_params); + +/* See pycore_code.h for explanation about what "stateless" means. */ + +PyAPI_FUNC(int) +_PyFunction_VerifyStateless(PyThreadState *, PyObject *); + + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 9bde4faaf5a..54931e8504e 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -792,7 +792,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(add_done_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_child)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(after_in_parent)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(aggregate_class)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(alias)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(align)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(all)); @@ -809,7 +808,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ast)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(athrow)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(attribute)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(authorizer_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(autocommit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(backtick)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(base)); @@ -1108,7 +1106,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(msg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mutex)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(mycmp)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_arg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_fields)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_sequence_fields)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(n_unnamed_fields)); @@ -1116,7 +1113,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(name_from)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(namespace_separator)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(namespaces)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(narg)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ndigits)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(nested)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(new_file_name)); @@ -1174,7 +1170,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(print_file_and_line)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(priority)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress_handler)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(progress_routine)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(proto)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(protocol)); @@ -1280,7 +1275,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); - _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trailers)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(translate)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 3a83fd6b604..a665195c899 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -283,7 +283,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(add_done_callback) STRUCT_FOR_ID(after_in_child) STRUCT_FOR_ID(after_in_parent) - STRUCT_FOR_ID(aggregate_class) STRUCT_FOR_ID(alias) STRUCT_FOR_ID(align) STRUCT_FOR_ID(all) @@ -300,7 +299,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(ast) STRUCT_FOR_ID(athrow) STRUCT_FOR_ID(attribute) - STRUCT_FOR_ID(authorizer_callback) STRUCT_FOR_ID(autocommit) STRUCT_FOR_ID(backtick) STRUCT_FOR_ID(base) @@ -599,7 +597,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(msg) STRUCT_FOR_ID(mutex) STRUCT_FOR_ID(mycmp) - STRUCT_FOR_ID(n_arg) STRUCT_FOR_ID(n_fields) STRUCT_FOR_ID(n_sequence_fields) STRUCT_FOR_ID(n_unnamed_fields) @@ -607,7 +604,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(name_from) STRUCT_FOR_ID(namespace_separator) STRUCT_FOR_ID(namespaces) - STRUCT_FOR_ID(narg) STRUCT_FOR_ID(ndigits) STRUCT_FOR_ID(nested) STRUCT_FOR_ID(new_file_name) @@ -665,7 +661,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(print_file_and_line) STRUCT_FOR_ID(priority) STRUCT_FOR_ID(progress) - STRUCT_FOR_ID(progress_handler) STRUCT_FOR_ID(progress_routine) STRUCT_FOR_ID(proto) STRUCT_FOR_ID(protocol) @@ -771,7 +766,6 @@ struct _Py_global_strings { STRUCT_FOR_ID(timetuple) STRUCT_FOR_ID(timeunit) STRUCT_FOR_ID(top) - STRUCT_FOR_ID(trace_callback) STRUCT_FOR_ID(traceback) STRUCT_FOR_ID(trailers) STRUCT_FOR_ID(translate) diff --git a/Include/internal/pycore_importdl.h b/Include/internal/pycore_importdl.h index 525a16f6b97..3ba9229cc21 100644 --- a/Include/internal/pycore_importdl.h +++ b/Include/internal/pycore_importdl.h @@ -107,7 +107,7 @@ extern int _PyImport_RunModInitFunc( #include <windows.h> typedef FARPROC dl_funcptr; -#ifdef _DEBUG +#ifdef Py_DEBUG # define PYD_DEBUG_SUFFIX "_d" #else # define PYD_DEBUG_SUFFIX "" diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index ed6c4353167..3196d1b8208 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -158,6 +158,11 @@ PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *); // Export for '_testclinic' shared extension (Argument Clinic code) PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *); +PyAPI_FUNC(int) _PyLong_UInt8_Converter(PyObject *, void *); +PyAPI_FUNC(int) _PyLong_UInt16_Converter(PyObject *, void *); +PyAPI_FUNC(int) _PyLong_UInt32_Converter(PyObject *, void *); +PyAPI_FUNC(int) _PyLong_UInt64_Converter(PyObject *, void *); + /* Long value tag bits: * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. * 2: Set to 1 for the small ints diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 0e34074f160..e55e26783a6 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -113,7 +113,7 @@ int _PyOpcode_num_popped(int opcode, int oparg) { case CALL_INTRINSIC_2: return 2; case CALL_ISINSTANCE: - return 2 + oparg; + return 4; case CALL_KW: return 3 + oparg; case CALL_KW_BOUND_METHOD: @@ -1115,7 +1115,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_ISINSTANCE] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, + [CALL_ISINSTANCE] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_KW] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_KW_BOUND_METHOD] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_KW_NON_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1363,7 +1363,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_BUILTIN_O] = { .nuops = 2, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } }, - [CALL_ISINSTANCE] = { .nuops = 1, .uops = { { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, + [CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, [CALL_KW_BOUND_METHOD] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION_KW, 2, 1 }, { _EXPAND_METHOD_KW, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_KW_NON_PY] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_KW, OPARG_SIMPLE, 3 }, { _CALL_KW_NON_PY, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_KW_PY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h index 62af06dc01c..79a1a242556 100644 --- a/Include/internal/pycore_opcode_utils.h +++ b/Include/internal/pycore_opcode_utils.h @@ -56,6 +56,8 @@ extern "C" { #define IS_RETURN_OPCODE(opcode) \ (opcode == RETURN_VALUE) +#define IS_RAISE_OPCODE(opcode) \ + (opcode == RAISE_VARARGS || opcode == RERAISE) /* Flags used in the oparg for MAKE_FUNCTION */ diff --git a/Include/internal/pycore_pythonrun.h b/Include/internal/pycore_pythonrun.h index 0bfc5704dc4..7daed1326af 100644 --- a/Include/internal/pycore_pythonrun.h +++ b/Include/internal/pycore_pythonrun.h @@ -25,6 +25,7 @@ extern int _PyRun_InteractiveLoopObject( PyObject *filename, PyCompilerFlags *flags); +extern int _PyObject_SupportedAsScript(PyObject *); extern const char* _Py_SourceAsString( PyObject *cmd, const char *funcname, diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 4a34ffa559e..01289f6118d 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -790,7 +790,6 @@ extern "C" { INIT_ID(add_done_callback), \ INIT_ID(after_in_child), \ INIT_ID(after_in_parent), \ - INIT_ID(aggregate_class), \ INIT_ID(alias), \ INIT_ID(align), \ INIT_ID(all), \ @@ -807,7 +806,6 @@ extern "C" { INIT_ID(ast), \ INIT_ID(athrow), \ INIT_ID(attribute), \ - INIT_ID(authorizer_callback), \ INIT_ID(autocommit), \ INIT_ID(backtick), \ INIT_ID(base), \ @@ -1106,7 +1104,6 @@ extern "C" { INIT_ID(msg), \ INIT_ID(mutex), \ INIT_ID(mycmp), \ - INIT_ID(n_arg), \ INIT_ID(n_fields), \ INIT_ID(n_sequence_fields), \ INIT_ID(n_unnamed_fields), \ @@ -1114,7 +1111,6 @@ extern "C" { INIT_ID(name_from), \ INIT_ID(namespace_separator), \ INIT_ID(namespaces), \ - INIT_ID(narg), \ INIT_ID(ndigits), \ INIT_ID(nested), \ INIT_ID(new_file_name), \ @@ -1172,7 +1168,6 @@ extern "C" { INIT_ID(print_file_and_line), \ INIT_ID(priority), \ INIT_ID(progress), \ - INIT_ID(progress_handler), \ INIT_ID(progress_routine), \ INIT_ID(proto), \ INIT_ID(protocol), \ @@ -1278,7 +1273,6 @@ extern "C" { INIT_ID(timetuple), \ INIT_ID(timeunit), \ INIT_ID(top), \ - INIT_ID(trace_callback), \ INIT_ID(traceback), \ INIT_ID(trailers), \ INIT_ID(translate), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index fefacef77c8..8ec1ac1e56d 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -920,10 +920,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(aggregate_class); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(alias); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -988,10 +984,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(authorizer_callback); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(autocommit); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2184,10 +2176,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(n_arg); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(n_fields); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2216,10 +2204,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(narg); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(ndigits); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2448,10 +2432,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(progress_handler); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(progress_routine); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2872,10 +2852,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); - string = &_Py_ID(trace_callback); - _PyUnicode_InternStatic(interp, &string); - assert(_PyUnicode_CheckConsistency(string, 1)); - assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(traceback); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index d3d2b716e2c..71a288a3a39 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -43,125 +43,127 @@ extern "C" { #define _CALL_BUILTIN_O 323 #define _CALL_INTRINSIC_1 CALL_INTRINSIC_1 #define _CALL_INTRINSIC_2 CALL_INTRINSIC_2 -#define _CALL_ISINSTANCE CALL_ISINSTANCE -#define _CALL_KW_NON_PY 324 -#define _CALL_LEN 325 +#define _CALL_ISINSTANCE 324 +#define _CALL_KW_NON_PY 325 +#define _CALL_LEN 326 #define _CALL_LIST_APPEND CALL_LIST_APPEND -#define _CALL_METHOD_DESCRIPTOR_FAST 326 -#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 327 -#define _CALL_METHOD_DESCRIPTOR_NOARGS 328 -#define _CALL_METHOD_DESCRIPTOR_O 329 -#define _CALL_NON_PY_GENERAL 330 -#define _CALL_STR_1 331 -#define _CALL_TUPLE_1 332 -#define _CALL_TYPE_1 333 -#define _CHECK_AND_ALLOCATE_OBJECT 334 -#define _CHECK_ATTR_CLASS 335 -#define _CHECK_ATTR_METHOD_LAZY_DICT 336 -#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 337 +#define _CALL_METHOD_DESCRIPTOR_FAST 327 +#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 328 +#define _CALL_METHOD_DESCRIPTOR_NOARGS 329 +#define _CALL_METHOD_DESCRIPTOR_O 330 +#define _CALL_NON_PY_GENERAL 331 +#define _CALL_STR_1 332 +#define _CALL_TUPLE_1 333 +#define _CALL_TYPE_1 334 +#define _CHECK_AND_ALLOCATE_OBJECT 335 +#define _CHECK_ATTR_CLASS 336 +#define _CHECK_ATTR_METHOD_LAZY_DICT 337 +#define _CHECK_CALL_BOUND_METHOD_EXACT_ARGS 338 #define _CHECK_EG_MATCH CHECK_EG_MATCH #define _CHECK_EXC_MATCH CHECK_EXC_MATCH -#define _CHECK_FUNCTION 338 -#define _CHECK_FUNCTION_EXACT_ARGS 339 -#define _CHECK_FUNCTION_VERSION 340 -#define _CHECK_FUNCTION_VERSION_INLINE 341 -#define _CHECK_FUNCTION_VERSION_KW 342 -#define _CHECK_IS_NOT_PY_CALLABLE 343 -#define _CHECK_IS_NOT_PY_CALLABLE_KW 344 -#define _CHECK_MANAGED_OBJECT_HAS_VALUES 345 -#define _CHECK_METHOD_VERSION 346 -#define _CHECK_METHOD_VERSION_KW 347 -#define _CHECK_PEP_523 348 -#define _CHECK_PERIODIC 349 -#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 350 -#define _CHECK_RECURSION_REMAINING 351 -#define _CHECK_STACK_SPACE 352 -#define _CHECK_STACK_SPACE_OPERAND 353 -#define _CHECK_VALIDITY 354 -#define _COMPARE_OP 355 -#define _COMPARE_OP_FLOAT 356 -#define _COMPARE_OP_INT 357 -#define _COMPARE_OP_STR 358 -#define _CONTAINS_OP 359 -#define _CONTAINS_OP_DICT 360 -#define _CONTAINS_OP_SET 361 +#define _CHECK_FUNCTION 339 +#define _CHECK_FUNCTION_EXACT_ARGS 340 +#define _CHECK_FUNCTION_VERSION 341 +#define _CHECK_FUNCTION_VERSION_INLINE 342 +#define _CHECK_FUNCTION_VERSION_KW 343 +#define _CHECK_IS_NOT_PY_CALLABLE 344 +#define _CHECK_IS_NOT_PY_CALLABLE_KW 345 +#define _CHECK_MANAGED_OBJECT_HAS_VALUES 346 +#define _CHECK_METHOD_VERSION 347 +#define _CHECK_METHOD_VERSION_KW 348 +#define _CHECK_PEP_523 349 +#define _CHECK_PERIODIC 350 +#define _CHECK_PERIODIC_IF_NOT_YIELD_FROM 351 +#define _CHECK_RECURSION_REMAINING 352 +#define _CHECK_STACK_SPACE 353 +#define _CHECK_STACK_SPACE_OPERAND 354 +#define _CHECK_VALIDITY 355 +#define _COMPARE_OP 356 +#define _COMPARE_OP_FLOAT 357 +#define _COMPARE_OP_INT 358 +#define _COMPARE_OP_STR 359 +#define _CONTAINS_OP 360 +#define _CONTAINS_OP_DICT 361 +#define _CONTAINS_OP_SET 362 #define _CONVERT_VALUE CONVERT_VALUE #define _COPY COPY #define _COPY_FREE_VARS COPY_FREE_VARS -#define _CREATE_INIT_FRAME 362 +#define _CREATE_INIT_FRAME 363 #define _DELETE_ATTR DELETE_ATTR #define _DELETE_DEREF DELETE_DEREF #define _DELETE_FAST DELETE_FAST #define _DELETE_GLOBAL DELETE_GLOBAL #define _DELETE_NAME DELETE_NAME #define _DELETE_SUBSCR DELETE_SUBSCR -#define _DEOPT 363 +#define _DEOPT 364 #define _DICT_MERGE DICT_MERGE #define _DICT_UPDATE DICT_UPDATE -#define _DO_CALL 364 -#define _DO_CALL_FUNCTION_EX 365 -#define _DO_CALL_KW 366 +#define _DO_CALL 365 +#define _DO_CALL_FUNCTION_EX 366 +#define _DO_CALL_KW 367 #define _END_FOR END_FOR #define _END_SEND END_SEND -#define _ERROR_POP_N 367 +#define _ERROR_POP_N 368 #define _EXIT_INIT_CHECK EXIT_INIT_CHECK -#define _EXPAND_METHOD 368 -#define _EXPAND_METHOD_KW 369 -#define _FATAL_ERROR 370 +#define _EXPAND_METHOD 369 +#define _EXPAND_METHOD_KW 370 +#define _FATAL_ERROR 371 #define _FORMAT_SIMPLE FORMAT_SIMPLE #define _FORMAT_WITH_SPEC FORMAT_WITH_SPEC -#define _FOR_ITER 371 -#define _FOR_ITER_GEN_FRAME 372 -#define _FOR_ITER_TIER_TWO 373 +#define _FOR_ITER 372 +#define _FOR_ITER_GEN_FRAME 373 +#define _FOR_ITER_TIER_TWO 374 #define _GET_AITER GET_AITER #define _GET_ANEXT GET_ANEXT #define _GET_AWAITABLE GET_AWAITABLE #define _GET_ITER GET_ITER #define _GET_LEN GET_LEN #define _GET_YIELD_FROM_ITER GET_YIELD_FROM_ITER -#define _GUARD_BINARY_OP_EXTEND 374 -#define _GUARD_CALLABLE_LEN 375 -#define _GUARD_CALLABLE_STR_1 376 -#define _GUARD_CALLABLE_TUPLE_1 377 -#define _GUARD_CALLABLE_TYPE_1 378 -#define _GUARD_DORV_NO_DICT 379 -#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 380 -#define _GUARD_GLOBALS_VERSION 381 -#define _GUARD_IS_FALSE_POP 382 -#define _GUARD_IS_NONE_POP 383 -#define _GUARD_IS_NOT_NONE_POP 384 -#define _GUARD_IS_TRUE_POP 385 -#define _GUARD_KEYS_VERSION 386 -#define _GUARD_NOS_DICT 387 -#define _GUARD_NOS_FLOAT 388 -#define _GUARD_NOS_INT 389 -#define _GUARD_NOS_LIST 390 -#define _GUARD_NOS_NULL 391 -#define _GUARD_NOS_TUPLE 392 -#define _GUARD_NOS_UNICODE 393 -#define _GUARD_NOT_EXHAUSTED_LIST 394 -#define _GUARD_NOT_EXHAUSTED_RANGE 395 -#define _GUARD_NOT_EXHAUSTED_TUPLE 396 -#define _GUARD_TOS_ANY_SET 397 -#define _GUARD_TOS_DICT 398 -#define _GUARD_TOS_FLOAT 399 -#define _GUARD_TOS_INT 400 -#define _GUARD_TOS_LIST 401 -#define _GUARD_TOS_SLICE 402 -#define _GUARD_TOS_TUPLE 403 -#define _GUARD_TOS_UNICODE 404 -#define _GUARD_TYPE_VERSION 405 -#define _GUARD_TYPE_VERSION_AND_LOCK 406 +#define _GUARD_BINARY_OP_EXTEND 375 +#define _GUARD_CALLABLE_ISINSTANCE 376 +#define _GUARD_CALLABLE_LEN 377 +#define _GUARD_CALLABLE_STR_1 378 +#define _GUARD_CALLABLE_TUPLE_1 379 +#define _GUARD_CALLABLE_TYPE_1 380 +#define _GUARD_DORV_NO_DICT 381 +#define _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT 382 +#define _GUARD_GLOBALS_VERSION 383 +#define _GUARD_IS_FALSE_POP 384 +#define _GUARD_IS_NONE_POP 385 +#define _GUARD_IS_NOT_NONE_POP 386 +#define _GUARD_IS_TRUE_POP 387 +#define _GUARD_KEYS_VERSION 388 +#define _GUARD_NOS_DICT 389 +#define _GUARD_NOS_FLOAT 390 +#define _GUARD_NOS_INT 391 +#define _GUARD_NOS_LIST 392 +#define _GUARD_NOS_NULL 393 +#define _GUARD_NOS_TUPLE 394 +#define _GUARD_NOS_UNICODE 395 +#define _GUARD_NOT_EXHAUSTED_LIST 396 +#define _GUARD_NOT_EXHAUSTED_RANGE 397 +#define _GUARD_NOT_EXHAUSTED_TUPLE 398 +#define _GUARD_THIRD_NULL 399 +#define _GUARD_TOS_ANY_SET 400 +#define _GUARD_TOS_DICT 401 +#define _GUARD_TOS_FLOAT 402 +#define _GUARD_TOS_INT 403 +#define _GUARD_TOS_LIST 404 +#define _GUARD_TOS_SLICE 405 +#define _GUARD_TOS_TUPLE 406 +#define _GUARD_TOS_UNICODE 407 +#define _GUARD_TYPE_VERSION 408 +#define _GUARD_TYPE_VERSION_AND_LOCK 409 #define _IMPORT_FROM IMPORT_FROM #define _IMPORT_NAME IMPORT_NAME -#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 407 -#define _INIT_CALL_PY_EXACT_ARGS 408 -#define _INIT_CALL_PY_EXACT_ARGS_0 409 -#define _INIT_CALL_PY_EXACT_ARGS_1 410 -#define _INIT_CALL_PY_EXACT_ARGS_2 411 -#define _INIT_CALL_PY_EXACT_ARGS_3 412 -#define _INIT_CALL_PY_EXACT_ARGS_4 413 -#define _INSERT_NULL 414 +#define _INIT_CALL_BOUND_METHOD_EXACT_ARGS 410 +#define _INIT_CALL_PY_EXACT_ARGS 411 +#define _INIT_CALL_PY_EXACT_ARGS_0 412 +#define _INIT_CALL_PY_EXACT_ARGS_1 413 +#define _INIT_CALL_PY_EXACT_ARGS_2 414 +#define _INIT_CALL_PY_EXACT_ARGS_3 415 +#define _INIT_CALL_PY_EXACT_ARGS_4 416 +#define _INSERT_NULL 417 #define _INSTRUMENTED_FOR_ITER INSTRUMENTED_FOR_ITER #define _INSTRUMENTED_INSTRUCTION INSTRUMENTED_INSTRUCTION #define _INSTRUMENTED_JUMP_FORWARD INSTRUMENTED_JUMP_FORWARD @@ -171,163 +173,163 @@ extern "C" { #define _INSTRUMENTED_POP_JUMP_IF_NONE INSTRUMENTED_POP_JUMP_IF_NONE #define _INSTRUMENTED_POP_JUMP_IF_NOT_NONE INSTRUMENTED_POP_JUMP_IF_NOT_NONE #define _INSTRUMENTED_POP_JUMP_IF_TRUE INSTRUMENTED_POP_JUMP_IF_TRUE -#define _IS_NONE 415 +#define _IS_NONE 418 #define _IS_OP IS_OP -#define _ITER_CHECK_LIST 416 -#define _ITER_CHECK_RANGE 417 -#define _ITER_CHECK_TUPLE 418 -#define _ITER_JUMP_LIST 419 -#define _ITER_JUMP_RANGE 420 -#define _ITER_JUMP_TUPLE 421 -#define _ITER_NEXT_LIST 422 -#define _ITER_NEXT_LIST_TIER_TWO 423 -#define _ITER_NEXT_RANGE 424 -#define _ITER_NEXT_TUPLE 425 -#define _JUMP_TO_TOP 426 +#define _ITER_CHECK_LIST 419 +#define _ITER_CHECK_RANGE 420 +#define _ITER_CHECK_TUPLE 421 +#define _ITER_JUMP_LIST 422 +#define _ITER_JUMP_RANGE 423 +#define _ITER_JUMP_TUPLE 424 +#define _ITER_NEXT_LIST 425 +#define _ITER_NEXT_LIST_TIER_TWO 426 +#define _ITER_NEXT_RANGE 427 +#define _ITER_NEXT_TUPLE 428 +#define _JUMP_TO_TOP 429 #define _LIST_APPEND LIST_APPEND #define _LIST_EXTEND LIST_EXTEND -#define _LOAD_ATTR 427 -#define _LOAD_ATTR_CLASS 428 +#define _LOAD_ATTR 430 +#define _LOAD_ATTR_CLASS 431 #define _LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN -#define _LOAD_ATTR_INSTANCE_VALUE 429 -#define _LOAD_ATTR_METHOD_LAZY_DICT 430 -#define _LOAD_ATTR_METHOD_NO_DICT 431 -#define _LOAD_ATTR_METHOD_WITH_VALUES 432 -#define _LOAD_ATTR_MODULE 433 -#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 434 -#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 435 -#define _LOAD_ATTR_PROPERTY_FRAME 436 -#define _LOAD_ATTR_SLOT 437 -#define _LOAD_ATTR_WITH_HINT 438 +#define _LOAD_ATTR_INSTANCE_VALUE 432 +#define _LOAD_ATTR_METHOD_LAZY_DICT 433 +#define _LOAD_ATTR_METHOD_NO_DICT 434 +#define _LOAD_ATTR_METHOD_WITH_VALUES 435 +#define _LOAD_ATTR_MODULE 436 +#define _LOAD_ATTR_NONDESCRIPTOR_NO_DICT 437 +#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES 438 +#define _LOAD_ATTR_PROPERTY_FRAME 439 +#define _LOAD_ATTR_SLOT 440 +#define _LOAD_ATTR_WITH_HINT 441 #define _LOAD_BUILD_CLASS LOAD_BUILD_CLASS -#define _LOAD_BYTECODE 439 +#define _LOAD_BYTECODE 442 #define _LOAD_COMMON_CONSTANT LOAD_COMMON_CONSTANT #define _LOAD_CONST LOAD_CONST #define _LOAD_CONST_IMMORTAL LOAD_CONST_IMMORTAL -#define _LOAD_CONST_INLINE 440 -#define _LOAD_CONST_INLINE_BORROW 441 +#define _LOAD_CONST_INLINE 443 +#define _LOAD_CONST_INLINE_BORROW 444 #define _LOAD_CONST_MORTAL LOAD_CONST_MORTAL #define _LOAD_DEREF LOAD_DEREF -#define _LOAD_FAST 442 -#define _LOAD_FAST_0 443 -#define _LOAD_FAST_1 444 -#define _LOAD_FAST_2 445 -#define _LOAD_FAST_3 446 -#define _LOAD_FAST_4 447 -#define _LOAD_FAST_5 448 -#define _LOAD_FAST_6 449 -#define _LOAD_FAST_7 450 +#define _LOAD_FAST 445 +#define _LOAD_FAST_0 446 +#define _LOAD_FAST_1 447 +#define _LOAD_FAST_2 448 +#define _LOAD_FAST_3 449 +#define _LOAD_FAST_4 450 +#define _LOAD_FAST_5 451 +#define _LOAD_FAST_6 452 +#define _LOAD_FAST_7 453 #define _LOAD_FAST_AND_CLEAR LOAD_FAST_AND_CLEAR -#define _LOAD_FAST_BORROW 451 -#define _LOAD_FAST_BORROW_0 452 -#define _LOAD_FAST_BORROW_1 453 -#define _LOAD_FAST_BORROW_2 454 -#define _LOAD_FAST_BORROW_3 455 -#define _LOAD_FAST_BORROW_4 456 -#define _LOAD_FAST_BORROW_5 457 -#define _LOAD_FAST_BORROW_6 458 -#define _LOAD_FAST_BORROW_7 459 +#define _LOAD_FAST_BORROW 454 +#define _LOAD_FAST_BORROW_0 455 +#define _LOAD_FAST_BORROW_1 456 +#define _LOAD_FAST_BORROW_2 457 +#define _LOAD_FAST_BORROW_3 458 +#define _LOAD_FAST_BORROW_4 459 +#define _LOAD_FAST_BORROW_5 460 +#define _LOAD_FAST_BORROW_6 461 +#define _LOAD_FAST_BORROW_7 462 #define _LOAD_FAST_BORROW_LOAD_FAST_BORROW LOAD_FAST_BORROW_LOAD_FAST_BORROW #define _LOAD_FAST_CHECK LOAD_FAST_CHECK #define _LOAD_FAST_LOAD_FAST LOAD_FAST_LOAD_FAST #define _LOAD_FROM_DICT_OR_DEREF LOAD_FROM_DICT_OR_DEREF #define _LOAD_FROM_DICT_OR_GLOBALS LOAD_FROM_DICT_OR_GLOBALS -#define _LOAD_GLOBAL 460 -#define _LOAD_GLOBAL_BUILTINS 461 -#define _LOAD_GLOBAL_MODULE 462 +#define _LOAD_GLOBAL 463 +#define _LOAD_GLOBAL_BUILTINS 464 +#define _LOAD_GLOBAL_MODULE 465 #define _LOAD_LOCALS LOAD_LOCALS #define _LOAD_NAME LOAD_NAME -#define _LOAD_SMALL_INT 463 -#define _LOAD_SMALL_INT_0 464 -#define _LOAD_SMALL_INT_1 465 -#define _LOAD_SMALL_INT_2 466 -#define _LOAD_SMALL_INT_3 467 -#define _LOAD_SPECIAL 468 +#define _LOAD_SMALL_INT 466 +#define _LOAD_SMALL_INT_0 467 +#define _LOAD_SMALL_INT_1 468 +#define _LOAD_SMALL_INT_2 469 +#define _LOAD_SMALL_INT_3 470 +#define _LOAD_SPECIAL 471 #define _LOAD_SUPER_ATTR_ATTR LOAD_SUPER_ATTR_ATTR #define _LOAD_SUPER_ATTR_METHOD LOAD_SUPER_ATTR_METHOD -#define _MAKE_CALLARGS_A_TUPLE 469 +#define _MAKE_CALLARGS_A_TUPLE 472 #define _MAKE_CELL MAKE_CELL #define _MAKE_FUNCTION MAKE_FUNCTION -#define _MAKE_WARM 470 +#define _MAKE_WARM 473 #define _MAP_ADD MAP_ADD #define _MATCH_CLASS MATCH_CLASS #define _MATCH_KEYS MATCH_KEYS #define _MATCH_MAPPING MATCH_MAPPING #define _MATCH_SEQUENCE MATCH_SEQUENCE -#define _MAYBE_EXPAND_METHOD 471 -#define _MAYBE_EXPAND_METHOD_KW 472 -#define _MONITOR_CALL 473 -#define _MONITOR_CALL_KW 474 -#define _MONITOR_JUMP_BACKWARD 475 -#define _MONITOR_RESUME 476 +#define _MAYBE_EXPAND_METHOD 474 +#define _MAYBE_EXPAND_METHOD_KW 475 +#define _MONITOR_CALL 476 +#define _MONITOR_CALL_KW 477 +#define _MONITOR_JUMP_BACKWARD 478 +#define _MONITOR_RESUME 479 #define _NOP NOP #define _POP_EXCEPT POP_EXCEPT -#define _POP_JUMP_IF_FALSE 477 -#define _POP_JUMP_IF_TRUE 478 +#define _POP_JUMP_IF_FALSE 480 +#define _POP_JUMP_IF_TRUE 481 #define _POP_TOP POP_TOP -#define _POP_TOP_LOAD_CONST_INLINE 479 -#define _POP_TOP_LOAD_CONST_INLINE_BORROW 480 -#define _POP_TWO_LOAD_CONST_INLINE_BORROW 481 +#define _POP_TOP_LOAD_CONST_INLINE 482 +#define _POP_TOP_LOAD_CONST_INLINE_BORROW 483 +#define _POP_TWO_LOAD_CONST_INLINE_BORROW 484 #define _PUSH_EXC_INFO PUSH_EXC_INFO -#define _PUSH_FRAME 482 +#define _PUSH_FRAME 485 #define _PUSH_NULL PUSH_NULL -#define _PUSH_NULL_CONDITIONAL 483 -#define _PY_FRAME_GENERAL 484 -#define _PY_FRAME_KW 485 -#define _QUICKEN_RESUME 486 -#define _REPLACE_WITH_TRUE 487 +#define _PUSH_NULL_CONDITIONAL 486 +#define _PY_FRAME_GENERAL 487 +#define _PY_FRAME_KW 488 +#define _QUICKEN_RESUME 489 +#define _REPLACE_WITH_TRUE 490 #define _RESUME_CHECK RESUME_CHECK #define _RETURN_GENERATOR RETURN_GENERATOR #define _RETURN_VALUE RETURN_VALUE -#define _SAVE_RETURN_OFFSET 488 -#define _SEND 489 -#define _SEND_GEN_FRAME 490 +#define _SAVE_RETURN_OFFSET 491 +#define _SEND 492 +#define _SEND_GEN_FRAME 493 #define _SETUP_ANNOTATIONS SETUP_ANNOTATIONS #define _SET_ADD SET_ADD #define _SET_FUNCTION_ATTRIBUTE SET_FUNCTION_ATTRIBUTE #define _SET_UPDATE SET_UPDATE -#define _START_EXECUTOR 491 -#define _STORE_ATTR 492 -#define _STORE_ATTR_INSTANCE_VALUE 493 -#define _STORE_ATTR_SLOT 494 -#define _STORE_ATTR_WITH_HINT 495 +#define _START_EXECUTOR 494 +#define _STORE_ATTR 495 +#define _STORE_ATTR_INSTANCE_VALUE 496 +#define _STORE_ATTR_SLOT 497 +#define _STORE_ATTR_WITH_HINT 498 #define _STORE_DEREF STORE_DEREF -#define _STORE_FAST 496 -#define _STORE_FAST_0 497 -#define _STORE_FAST_1 498 -#define _STORE_FAST_2 499 -#define _STORE_FAST_3 500 -#define _STORE_FAST_4 501 -#define _STORE_FAST_5 502 -#define _STORE_FAST_6 503 -#define _STORE_FAST_7 504 +#define _STORE_FAST 499 +#define _STORE_FAST_0 500 +#define _STORE_FAST_1 501 +#define _STORE_FAST_2 502 +#define _STORE_FAST_3 503 +#define _STORE_FAST_4 504 +#define _STORE_FAST_5 505 +#define _STORE_FAST_6 506 +#define _STORE_FAST_7 507 #define _STORE_FAST_LOAD_FAST STORE_FAST_LOAD_FAST #define _STORE_FAST_STORE_FAST STORE_FAST_STORE_FAST #define _STORE_GLOBAL STORE_GLOBAL #define _STORE_NAME STORE_NAME -#define _STORE_SLICE 505 -#define _STORE_SUBSCR 506 -#define _STORE_SUBSCR_DICT 507 -#define _STORE_SUBSCR_LIST_INT 508 +#define _STORE_SLICE 508 +#define _STORE_SUBSCR 509 +#define _STORE_SUBSCR_DICT 510 +#define _STORE_SUBSCR_LIST_INT 511 #define _SWAP SWAP -#define _TIER2_RESUME_CHECK 509 -#define _TO_BOOL 510 +#define _TIER2_RESUME_CHECK 512 +#define _TO_BOOL 513 #define _TO_BOOL_BOOL TO_BOOL_BOOL #define _TO_BOOL_INT TO_BOOL_INT -#define _TO_BOOL_LIST 511 +#define _TO_BOOL_LIST 514 #define _TO_BOOL_NONE TO_BOOL_NONE -#define _TO_BOOL_STR 512 +#define _TO_BOOL_STR 515 #define _UNARY_INVERT UNARY_INVERT #define _UNARY_NEGATIVE UNARY_NEGATIVE #define _UNARY_NOT UNARY_NOT #define _UNPACK_EX UNPACK_EX -#define _UNPACK_SEQUENCE 513 -#define _UNPACK_SEQUENCE_LIST 514 -#define _UNPACK_SEQUENCE_TUPLE 515 -#define _UNPACK_SEQUENCE_TWO_TUPLE 516 +#define _UNPACK_SEQUENCE 516 +#define _UNPACK_SEQUENCE_LIST 517 +#define _UNPACK_SEQUENCE_TUPLE 518 +#define _UNPACK_SEQUENCE_TWO_TUPLE 519 #define _WITH_EXCEPT_START WITH_EXCEPT_START #define _YIELD_VALUE YIELD_VALUE -#define MAX_UOP_ID 516 +#define MAX_UOP_ID 519 #ifdef __cplusplus } diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 912b1e56692..88a2e538447 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -247,6 +247,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_INIT_CALL_PY_EXACT_ARGS] = HAS_ARG_FLAG | HAS_PURE_FLAG, [_PUSH_FRAME] = 0, [_GUARD_NOS_NULL] = HAS_DEOPT_FLAG, + [_GUARD_THIRD_NULL] = HAS_DEOPT_FLAG, [_GUARD_CALLABLE_TYPE_1] = HAS_DEOPT_FLAG, [_CALL_TYPE_1] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_STR_1] = HAS_DEOPT_FLAG, @@ -262,7 +263,8 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CALL_BUILTIN_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_LEN] = HAS_DEOPT_FLAG, [_CALL_LEN] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, - [_CALL_ISINSTANCE] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, + [_GUARD_CALLABLE_ISINSTANCE] = HAS_DEOPT_FLAG, + [_CALL_ISINSTANCE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -425,6 +427,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GET_LEN] = "_GET_LEN", [_GET_YIELD_FROM_ITER] = "_GET_YIELD_FROM_ITER", [_GUARD_BINARY_OP_EXTEND] = "_GUARD_BINARY_OP_EXTEND", + [_GUARD_CALLABLE_ISINSTANCE] = "_GUARD_CALLABLE_ISINSTANCE", [_GUARD_CALLABLE_LEN] = "_GUARD_CALLABLE_LEN", [_GUARD_CALLABLE_STR_1] = "_GUARD_CALLABLE_STR_1", [_GUARD_CALLABLE_TUPLE_1] = "_GUARD_CALLABLE_TUPLE_1", @@ -447,6 +450,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { [_GUARD_NOT_EXHAUSTED_LIST] = "_GUARD_NOT_EXHAUSTED_LIST", [_GUARD_NOT_EXHAUSTED_RANGE] = "_GUARD_NOT_EXHAUSTED_RANGE", [_GUARD_NOT_EXHAUSTED_TUPLE] = "_GUARD_NOT_EXHAUSTED_TUPLE", + [_GUARD_THIRD_NULL] = "_GUARD_THIRD_NULL", [_GUARD_TOS_ANY_SET] = "_GUARD_TOS_ANY_SET", [_GUARD_TOS_DICT] = "_GUARD_TOS_DICT", [_GUARD_TOS_FLOAT] = "_GUARD_TOS_FLOAT", @@ -1068,6 +1072,8 @@ int _PyUop_num_popped(int opcode, int oparg) return 1; case _GUARD_NOS_NULL: return 0; + case _GUARD_THIRD_NULL: + return 0; case _GUARD_CALLABLE_TYPE_1: return 0; case _CALL_TYPE_1: @@ -1098,8 +1104,10 @@ int _PyUop_num_popped(int opcode, int oparg) return 0; case _CALL_LEN: return 3; + case _GUARD_CALLABLE_ISINSTANCE: + return 0; case _CALL_ISINSTANCE: - return 2 + oparg; + return 4; case _CALL_LIST_APPEND: return 3; case _CALL_METHOD_DESCRIPTOR_O: diff --git a/Lib/_ast_unparse.py b/Lib/_ast_unparse.py index 0b669edb2ff..c25066eb107 100644 --- a/Lib/_ast_unparse.py +++ b/Lib/_ast_unparse.py @@ -627,6 +627,9 @@ class Unparser(NodeVisitor): self._ftstring_helper(fstring_parts) def _tstring_helper(self, node): + if not node.values: + self._write_ftstring([], "t") + return last_idx = 0 for i, value in enumerate(node.values): # This can happen if we have an implicit concat of a t-string @@ -679,9 +682,12 @@ class Unparser(NodeVisitor): unparser.set_precedence(_Precedence.TEST.next(), inner) return unparser.visit(inner) - def _write_interpolation(self, node): + def _write_interpolation(self, node, is_interpolation=False): with self.delimit("{", "}"): - expr = self._unparse_interpolation_value(node.value) + if is_interpolation: + expr = node.str + else: + expr = self._unparse_interpolation_value(node.value) if expr.startswith("{"): # Separate pair of opening brackets as "{ {" self.write(" ") @@ -696,7 +702,7 @@ class Unparser(NodeVisitor): self._write_interpolation(node) def visit_Interpolation(self, node): - self._write_interpolation(node) + self._write_interpolation(node, is_interpolation=True) def visit_Name(self, node): self.write(node.id) diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py index 38cf6b5a08e..752049ac05a 100644 --- a/Lib/_pyrepl/utils.py +++ b/Lib/_pyrepl/utils.py @@ -102,6 +102,8 @@ def gen_colors(buffer: str) -> Iterator[ColorSpan]: for color in gen_colors_from_token_stream(gen, line_lengths): yield color last_emitted = color + except SyntaxError: + return except tokenize.TokenError as te: yield from recover_unterminated_string( te, line_lengths, last_emitted, buffer diff --git a/Lib/annotationlib.py b/Lib/annotationlib.py index c0b1d4395d1..32b85534589 100644 --- a/Lib/annotationlib.py +++ b/Lib/annotationlib.py @@ -305,6 +305,9 @@ class ForwardRef: return f"ForwardRef({self.__forward_arg__!r}{''.join(extra)})" +_Template = type(t"") + + class _Stringifier: # Must match the slots on ForwardRef, so we can turn an instance of one into an # instance of the other in place. @@ -341,6 +344,8 @@ class _Stringifier: if isinstance(other.__ast_node__, str): return ast.Name(id=other.__ast_node__), other.__extra_names__ return other.__ast_node__, other.__extra_names__ + elif type(other) is _Template: + return _template_to_ast(other), None elif ( # In STRING format we don't bother with the create_unique_name() dance; # it's better to emit the repr() of the object instead of an opaque name. @@ -560,6 +565,32 @@ class _Stringifier: del _make_unary_op +def _template_to_ast(template): + values = [] + for part in template: + match part: + case str(): + values.append(ast.Constant(value=part)) + # Interpolation, but we don't want to import the string module + case _: + interp = ast.Interpolation( + str=part.expression, + value=ast.parse(part.expression), + conversion=( + ord(part.conversion) + if part.conversion is not None + else -1 + ), + format_spec=( + ast.Constant(value=part.format_spec) + if part.format_spec != "" + else None + ), + ) + values.append(interp) + return ast.TemplateStr(values=values) + + class _StringifierDict(dict): def __init__(self, namespace, *, globals=None, owner=None, is_class=False, format): super().__init__(namespace) @@ -784,6 +815,8 @@ def _stringify_single(anno): # We have to handle str specially to support PEP 563 stringified annotations. elif isinstance(anno, str): return anno + elif isinstance(anno, _Template): + return ast.unparse(_template_to_ast(anno)) else: return repr(anno) @@ -976,6 +1009,9 @@ def type_repr(value): if value.__module__ == "builtins": return value.__qualname__ return f"{value.__module__}.{value.__qualname__}" + elif isinstance(value, _Template): + tree = _template_to_ast(value) + return ast.unparse(tree) if value is ...: return "..." return repr(value) diff --git a/Lib/functools.py b/Lib/functools.py index 714070c6ac9..7f0eac3f650 100644 --- a/Lib/functools.py +++ b/Lib/functools.py @@ -323,6 +323,9 @@ def _partial_new(cls, func, /, *args, **keywords): "or a descriptor") if args and args[-1] is Placeholder: raise TypeError("trailing Placeholders are not allowed") + for value in keywords.values(): + if value is Placeholder: + raise TypeError("Placeholder cannot be passed as a keyword argument") if isinstance(func, base_cls): pto_phcount = func._phcount tot_args = func.args diff --git a/Lib/logging/__init__.py b/Lib/logging/__init__.py index aa9b79d8cab..283a1055182 100644 --- a/Lib/logging/__init__.py +++ b/Lib/logging/__init__.py @@ -1474,6 +1474,8 @@ class Logger(Filterer): level, and "input.csv", "input.xls" and "input.gnu" for the sub-levels. There is no arbitrary limit to the depth of nesting. """ + _tls = threading.local() + def __init__(self, name, level=NOTSET): """ Initialize the logger with a name and an optional level. @@ -1670,14 +1672,19 @@ class Logger(Filterer): This method is used for unpickled records received from a socket, as well as those created locally. Logger-level filtering is applied. """ - if self.disabled: - return - maybe_record = self.filter(record) - if not maybe_record: + if self._is_disabled(): return - if isinstance(maybe_record, LogRecord): - record = maybe_record - self.callHandlers(record) + + self._tls.in_progress = True + try: + maybe_record = self.filter(record) + if not maybe_record: + return + if isinstance(maybe_record, LogRecord): + record = maybe_record + self.callHandlers(record) + finally: + self._tls.in_progress = False def addHandler(self, hdlr): """ @@ -1765,7 +1772,7 @@ class Logger(Filterer): """ Is this logger enabled for level 'level'? """ - if self.disabled: + if self._is_disabled(): return False try: @@ -1815,6 +1822,11 @@ class Logger(Filterer): if isinstance(item, Logger) and item.parent is self and _hierlevel(item) == 1 + _hierlevel(item.parent)) + def _is_disabled(self): + # We need to use getattr as it will only be set the first time a log + # message is recorded on any given thread + return self.disabled or getattr(self._tls, 'in_progress', False) + def __repr__(self): level = getLevelName(self.getEffectiveLevel()) return '<%s %s (%s)>' % (self.__class__.__name__, self.name, level) diff --git a/Lib/test/.ruff.toml b/Lib/test/.ruff.toml index a1eac32a83a..7aa8a4785d6 100644 --- a/Lib/test/.ruff.toml +++ b/Lib/test/.ruff.toml @@ -9,8 +9,9 @@ extend-exclude = [ "encoded_modules/module_iso_8859_1.py", "encoded_modules/module_koi8_r.py", # SyntaxError because of t-strings - "test_tstring.py", + "test_annotationlib.py", "test_string/test_templatelib.py", + "test_tstring.py", # New grammar constructions may not yet be recognized by Ruff, # and tests re-use the same names as only the grammar is being checked. "test_grammar.py", diff --git a/Lib/test/_code_definitions.py b/Lib/test/_code_definitions.py index c3daa0dccf5..733a15b25f6 100644 --- a/Lib/test/_code_definitions.py +++ b/Lib/test/_code_definitions.py @@ -1,4 +1,32 @@ +def simple_script(): + assert True + + +def complex_script(): + obj = 'a string' + pickle = __import__('pickle') + def spam_minimal(): + pass + spam_minimal() + data = pickle.dumps(obj) + res = pickle.loads(data) + assert res == obj, (res, obj) + + +def script_with_globals(): + obj1, obj2 = spam(42) + assert obj1 == 42 + assert obj2 is None + + +def script_with_explicit_empty_return(): + return None + + +def script_with_return(): + return True + def spam_minimal(): # no arg defaults or kwarg defaults @@ -141,6 +169,11 @@ ham_C_closure, *_ = eggs_closure_C(2) TOP_FUNCTIONS = [ # shallow + simple_script, + complex_script, + script_with_globals, + script_with_explicit_empty_return, + script_with_return, spam_minimal, spam_with_builtins, spam_with_globals_and_builtins, @@ -178,6 +211,52 @@ FUNCTIONS = [ *NESTED_FUNCTIONS, ] +STATELESS_FUNCTIONS = [ + simple_script, + complex_script, + script_with_explicit_empty_return, + script_with_return, + spam, + spam_minimal, + spam_with_builtins, + spam_args_attrs_and_builtins, + spam_returns_arg, + spam_annotated, + spam_with_inner_not_closure, + spam_with_inner_closure, + spam_N, + spam_C, + spam_NN, + spam_NC, + spam_CN, + spam_CC, + eggs_nested, + eggs_nested_N, + ham_nested, + ham_C_nested +] +STATELESS_CODE = [ + *STATELESS_FUNCTIONS, + script_with_globals, + spam_with_globals_and_builtins, + spam_full, +] + +PURE_SCRIPT_FUNCTIONS = [ + simple_script, + complex_script, + script_with_explicit_empty_return, + spam_minimal, + spam_with_builtins, + spam_with_inner_not_closure, + spam_with_inner_closure, +] +SCRIPT_FUNCTIONS = [ + *PURE_SCRIPT_FUNCTIONS, + script_with_globals, + spam_with_globals_and_builtins, +] + # generators diff --git a/Lib/test/_test_gc_fast_cycles.py b/Lib/test/_test_gc_fast_cycles.py new file mode 100644 index 00000000000..4e2c7d72a02 --- /dev/null +++ b/Lib/test/_test_gc_fast_cycles.py @@ -0,0 +1,48 @@ +# Run by test_gc. +from test import support +import _testinternalcapi +import gc +import unittest + +class IncrementalGCTests(unittest.TestCase): + + # Use small increments to emulate longer running process in a shorter time + @support.gc_threshold(200, 10) + def test_incremental_gc_handles_fast_cycle_creation(self): + + class LinkedList: + + #Use slots to reduce number of implicit objects + __slots__ = "next", "prev", "surprise" + + def __init__(self, next=None, prev=None): + self.next = next + if next is not None: + next.prev = self + self.prev = prev + if prev is not None: + prev.next = self + + def make_ll(depth): + head = LinkedList() + for i in range(depth): + head = LinkedList(head, head.prev) + return head + + head = make_ll(1000) + + assert(gc.isenabled()) + olds = [] + initial_heap_size = _testinternalcapi.get_tracked_heap_size() + for i in range(20_000): + newhead = make_ll(20) + newhead.surprise = head + olds.append(newhead) + if len(olds) == 20: + new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size + self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations") + del olds[:] + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index bdc7ef62943..dcba6369541 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -2272,7 +2272,11 @@ class AbstractPicklingErrorTests: def test_nested_lookup_error(self): # Nested name does not exist - obj = REX('AbstractPickleTests.spam') + global TestGlobal + class TestGlobal: + class A: + pass + obj = REX('TestGlobal.A.B.C') obj.__module__ = __name__ for proto in protocols: with self.subTest(proto=proto): @@ -2280,9 +2284,9 @@ class AbstractPicklingErrorTests: self.dumps(obj, proto) self.assertEqual(str(cm.exception), f"Can't pickle {obj!r}: " - f"it's not found as {__name__}.AbstractPickleTests.spam") + f"it's not found as {__name__}.TestGlobal.A.B.C") self.assertEqual(str(cm.exception.__context__), - "type object 'AbstractPickleTests' has no attribute 'spam'") + "type object 'A' has no attribute 'B'") obj.__module__ = None for proto in protocols: @@ -2290,21 +2294,25 @@ class AbstractPicklingErrorTests: with self.assertRaises(pickle.PicklingError) as cm: self.dumps(obj, proto) self.assertEqual(str(cm.exception), - f"Can't pickle {obj!r}: it's not found as __main__.AbstractPickleTests.spam") + f"Can't pickle {obj!r}: " + f"it's not found as __main__.TestGlobal.A.B.C") self.assertEqual(str(cm.exception.__context__), - "module '__main__' has no attribute 'AbstractPickleTests'") + "module '__main__' has no attribute 'TestGlobal'") def test_wrong_object_lookup_error(self): # Name is bound to different object - obj = REX('AbstractPickleTests') + global TestGlobal + class TestGlobal: + pass + obj = REX('TestGlobal') obj.__module__ = __name__ - AbstractPickleTests.ham = [] for proto in protocols: with self.subTest(proto=proto): with self.assertRaises(pickle.PicklingError) as cm: self.dumps(obj, proto) self.assertEqual(str(cm.exception), - f"Can't pickle {obj!r}: it's not the same object as {__name__}.AbstractPickleTests") + f"Can't pickle {obj!r}: " + f"it's not the same object as {__name__}.TestGlobal") self.assertIsNone(cm.exception.__context__) obj.__module__ = None @@ -2313,9 +2321,10 @@ class AbstractPicklingErrorTests: with self.assertRaises(pickle.PicklingError) as cm: self.dumps(obj, proto) self.assertEqual(str(cm.exception), - f"Can't pickle {obj!r}: it's not found as __main__.AbstractPickleTests") + f"Can't pickle {obj!r}: " + f"it's not found as __main__.TestGlobal") self.assertEqual(str(cm.exception.__context__), - "module '__main__' has no attribute 'AbstractPickleTests'") + "module '__main__' has no attribute 'TestGlobal'") def test_local_lookup_error(self): # Test that whichmodule() errors out cleanly when looking up diff --git a/Lib/test/test_annotationlib.py b/Lib/test/test_annotationlib.py index c3c245ddaf8..4af97c82de9 100644 --- a/Lib/test/test_annotationlib.py +++ b/Lib/test/test_annotationlib.py @@ -7,6 +7,7 @@ import collections import functools import itertools import pickle +from string.templatelib import Interpolation, Template import typing import unittest from annotationlib import ( @@ -273,6 +274,43 @@ class TestStringFormat(unittest.TestCase): }, ) + def test_template_str(self): + def f( + x: t"{a}", + y: list[t"{a}"], + z: t"{a:b} {c!r} {d!s:t}", + a: t"a{b}c{d}e{f}g", + b: t"{a:{1}}", + c: t"{a | b * c}", + ): pass + + annos = get_annotations(f, format=Format.STRING) + self.assertEqual(annos, { + "x": "t'{a}'", + "y": "list[t'{a}']", + "z": "t'{a:b} {c!r} {d!s:t}'", + "a": "t'a{b}c{d}e{f}g'", + # interpolations in the format spec are eagerly evaluated so we can't recover the source + "b": "t'{a:1}'", + "c": "t'{a | b * c}'", + }) + + def g( + x: t"{a}", + ): ... + + annos = get_annotations(g, format=Format.FORWARDREF) + templ = annos["x"] + # Template and Interpolation don't have __eq__ so we have to compare manually + self.assertIsInstance(templ, Template) + self.assertEqual(templ.strings, ("", "")) + self.assertEqual(len(templ.interpolations), 1) + interp = templ.interpolations[0] + self.assertEqual(interp.value, support.EqualToForwardRef("a", owner=g)) + self.assertEqual(interp.expression, "a") + self.assertIsNone(interp.conversion) + self.assertEqual(interp.format_spec, "") + def test_getitem(self): def f(x: undef1[str, undef2]): pass diff --git a/Lib/test/test_asyncio/test_ssl.py b/Lib/test/test_asyncio/test_ssl.py index 986ecc2c5a9..3a7185cd897 100644 --- a/Lib/test/test_asyncio/test_ssl.py +++ b/Lib/test/test_asyncio/test_ssl.py @@ -195,9 +195,10 @@ class TestSSL(test_utils.TestCase): except (BrokenPipeError, ConnectionError): pass - def test_create_server_ssl_1(self): + @support.bigmemtest(size=25, memuse=90*2**20, dry_run=False) + def test_create_server_ssl_1(self, size): CNT = 0 # number of clients that were successful - TOTAL_CNT = 25 # total number of clients that test will create + TOTAL_CNT = size # total number of clients that test will create TIMEOUT = support.LONG_TIMEOUT # timeout for this test A_DATA = b'A' * 1024 * BUF_MULTIPLIER @@ -1038,9 +1039,10 @@ class TestSSL(test_utils.TestCase): self.loop.run_until_complete(run_main()) - def test_create_server_ssl_over_ssl(self): + @support.bigmemtest(size=25, memuse=90*2**20, dry_run=False) + def test_create_server_ssl_over_ssl(self, size): CNT = 0 # number of clients that were successful - TOTAL_CNT = 25 # total number of clients that test will create + TOTAL_CNT = size # total number of clients that test will create TIMEOUT = support.LONG_TIMEOUT # timeout for this test A_DATA = b'A' * 1024 * BUF_MULTIPLIER diff --git a/Lib/test/test_capi/test_import.py b/Lib/test/test_capi/test_import.py index 25136624ca4..57e0316fda8 100644 --- a/Lib/test/test_capi/test_import.py +++ b/Lib/test/test_capi/test_import.py @@ -134,7 +134,7 @@ class ImportTests(unittest.TestCase): # CRASHES importmodule(NULL) def test_importmodulenoblock(self): - # Test deprecated PyImport_ImportModuleNoBlock() + # Test deprecated (stable ABI only) PyImport_ImportModuleNoBlock() importmodulenoblock = _testlimitedcapi.PyImport_ImportModuleNoBlock with check_warnings(('', DeprecationWarning)): self.check_import_func(importmodulenoblock) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index ba7bcb4540a..651148336f7 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1942,6 +1942,23 @@ class TestUopsOptimization(unittest.TestCase): self.assertNotIn("_COMPARE_OP_INT", uops) self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + def test_call_isinstance_guards_removed(self): + def testfunc(n): + x = 0 + for _ in range(n): + y = isinstance(42, int) + if y: + x += 1 + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_CALL_ISINSTANCE", uops) + self.assertNotIn("_GUARD_THIRD_NULL", uops) + self.assertNotIn("_GUARD_CALLABLE_ISINSTANCE", uops) + def global_identity(x): return x diff --git a/Lib/test/test_clinic.py b/Lib/test/test_clinic.py index 6461b647925..f7fc3b38733 100644 --- a/Lib/test/test_clinic.py +++ b/Lib/test/test_clinic.py @@ -2835,6 +2835,10 @@ class ClinicExternalTest(TestCase): "size_t", "slice_index", "str", + "uint16", + "uint32", + "uint64", + "uint8", "unicode", "unsigned_char", "unsigned_int", diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py index b646042a3b8..32cf8aacaf6 100644 --- a/Lib/test/test_code.py +++ b/Lib/test/test_code.py @@ -220,6 +220,7 @@ try: import _testinternalcapi except ModuleNotFoundError: _testinternalcapi = None +import test._code_definitions as defs COPY_FREE_VARS = opmap['COPY_FREE_VARS'] @@ -671,8 +672,21 @@ class CodeTest(unittest.TestCase): VARARGS = CO_FAST_LOCAL | CO_FAST_ARG_VAR | CO_FAST_ARG_POS VARKWARGS = CO_FAST_LOCAL | CO_FAST_ARG_VAR | CO_FAST_ARG_KW - import test._code_definitions as defs funcs = { + defs.simple_script: {}, + defs.complex_script: { + 'obj': CO_FAST_LOCAL, + 'pickle': CO_FAST_LOCAL, + 'spam_minimal': CO_FAST_LOCAL, + 'data': CO_FAST_LOCAL, + 'res': CO_FAST_LOCAL, + }, + defs.script_with_globals: { + 'obj1': CO_FAST_LOCAL, + 'obj2': CO_FAST_LOCAL, + }, + defs.script_with_explicit_empty_return: {}, + defs.script_with_return: {}, defs.spam_minimal: {}, defs.spam_with_builtins: { 'x': CO_FAST_LOCAL, @@ -897,8 +911,20 @@ class CodeTest(unittest.TestCase): }, } - import test._code_definitions as defs funcs = { + defs.simple_script: new_var_counts(), + defs.complex_script: new_var_counts( + purelocals=5, + globalvars=1, + attrs=2, + ), + defs.script_with_globals: new_var_counts( + purelocals=2, + globalvars=1, + ), + defs.script_with_explicit_empty_return: new_var_counts(), + defs.script_with_return: new_var_counts(), + defs.spam_minimal: new_var_counts(), defs.spam_minimal: new_var_counts(), defs.spam_with_builtins: new_var_counts( purelocals=4, @@ -1025,42 +1051,35 @@ class CodeTest(unittest.TestCase): counts = _testinternalcapi.get_code_var_counts(func.__code__) self.assertEqual(counts, expected) - def func_with_globals_and_builtins(): - mod1 = _testinternalcapi - mod2 = dis - mods = (mod1, mod2) - checks = tuple(callable(m) for m in mods) - return callable(mod2), tuple(mods), list(mods), checks - - func = func_with_globals_and_builtins + func = defs.spam_with_globals_and_builtins with self.subTest(f'{func} code'): expected = new_var_counts( - purelocals=4, - globalvars=5, + purelocals=5, + globalvars=6, ) counts = _testinternalcapi.get_code_var_counts(func.__code__) self.assertEqual(counts, expected) with self.subTest(f'{func} with own globals and builtins'): expected = new_var_counts( - purelocals=4, - globalvars=(2, 3), + purelocals=5, + globalvars=(2, 4), ) counts = _testinternalcapi.get_code_var_counts(func) self.assertEqual(counts, expected) with self.subTest(f'{func} without globals'): expected = new_var_counts( - purelocals=4, - globalvars=(0, 3, 2), + purelocals=5, + globalvars=(0, 4, 2), ) counts = _testinternalcapi.get_code_var_counts(func, globalsns={}) self.assertEqual(counts, expected) with self.subTest(f'{func} without both'): expected = new_var_counts( - purelocals=4, - globalvars=5, + purelocals=5, + globalvars=6, ) counts = _testinternalcapi.get_code_var_counts(func, globalsns={}, builtinsns={}) @@ -1068,12 +1087,34 @@ class CodeTest(unittest.TestCase): with self.subTest(f'{func} without builtins'): expected = new_var_counts( - purelocals=4, - globalvars=(2, 0, 3), + purelocals=5, + globalvars=(2, 0, 4), ) counts = _testinternalcapi.get_code_var_counts(func, builtinsns={}) self.assertEqual(counts, expected) + @unittest.skipIf(_testinternalcapi is None, "missing _testinternalcapi") + def test_stateless(self): + self.maxDiff = None + + for func in defs.STATELESS_CODE: + with self.subTest((func, '(code)')): + _testinternalcapi.verify_stateless_code(func.__code__) + for func in defs.STATELESS_FUNCTIONS: + with self.subTest((func, '(func)')): + _testinternalcapi.verify_stateless_code(func) + + for func in defs.FUNCTIONS: + if func not in defs.STATELESS_CODE: + with self.subTest((func, '(code)')): + with self.assertRaises(Exception): + _testinternalcapi.verify_stateless_code(func.__code__) + + if func not in defs.STATELESS_FUNCTIONS: + with self.subTest((func, '(func)')): + with self.assertRaises(Exception): + _testinternalcapi.verify_stateless_code(func) + def isinterned(s): return s is sys.intern(('_' + s + '_')[1:-1]) diff --git a/Lib/test/test_crossinterp.py b/Lib/test/test_crossinterp.py index 5ac0080db43..b366a29645e 100644 --- a/Lib/test/test_crossinterp.py +++ b/Lib/test/test_crossinterp.py @@ -758,6 +758,126 @@ class CodeTests(_GetXIDataTests): ]) +class PureShareableScriptTests(_GetXIDataTests): + + MODE = 'script-pure' + + VALID_SCRIPTS = [ + '', + 'spam', + '# a comment', + 'print("spam")', + 'raise Exception("spam")', + """if True: + do_something() + """, + """if True: + def spam(x): + return x + class Spam: + def eggs(self): + return 42 + x = Spam().eggs() + raise ValueError(spam(x)) + """, + ] + INVALID_SCRIPTS = [ + ' pass', # IndentationError + '----', # SyntaxError + """if True: + def spam(): + # no body + spam() + """, # IndentationError + ] + + def test_valid_str(self): + self.assert_roundtrip_not_equal([ + *self.VALID_SCRIPTS, + ], expecttype=types.CodeType) + + def test_invalid_str(self): + self.assert_not_shareable([ + *self.INVALID_SCRIPTS, + ]) + + def test_valid_bytes(self): + self.assert_roundtrip_not_equal([ + *(s.encode('utf8') for s in self.VALID_SCRIPTS), + ], expecttype=types.CodeType) + + def test_invalid_bytes(self): + self.assert_not_shareable([ + *(s.encode('utf8') for s in self.INVALID_SCRIPTS), + ]) + + def test_pure_script_code(self): + self.assert_roundtrip_equal_not_identical([ + *(f.__code__ for f in defs.PURE_SCRIPT_FUNCTIONS), + ]) + + def test_impure_script_code(self): + self.assert_not_shareable([ + *(f.__code__ for f in defs.SCRIPT_FUNCTIONS + if f not in defs.PURE_SCRIPT_FUNCTIONS), + ]) + + def test_other_code(self): + self.assert_not_shareable([ + *(f.__code__ for f in defs.FUNCTIONS + if f not in defs.SCRIPT_FUNCTIONS), + *(f.__code__ for f in defs.FUNCTION_LIKE), + ]) + + def test_pure_script_function(self): + self.assert_roundtrip_not_equal([ + *defs.PURE_SCRIPT_FUNCTIONS, + ], expecttype=types.CodeType) + + def test_impure_script_function(self): + self.assert_not_shareable([ + *(f for f in defs.SCRIPT_FUNCTIONS + if f not in defs.PURE_SCRIPT_FUNCTIONS), + ]) + + def test_other_function(self): + self.assert_not_shareable([ + *(f for f in defs.FUNCTIONS + if f not in defs.SCRIPT_FUNCTIONS), + *defs.FUNCTION_LIKE, + ]) + + def test_other_objects(self): + self.assert_not_shareable([ + None, + True, + False, + Ellipsis, + NotImplemented, + (), + [], + {}, + object(), + ]) + + +class ShareableScriptTests(PureShareableScriptTests): + + MODE = 'script' + + def test_impure_script_code(self): + self.assert_roundtrip_equal_not_identical([ + *(f.__code__ for f in defs.SCRIPT_FUNCTIONS + if f not in defs.PURE_SCRIPT_FUNCTIONS), + ]) + + def test_impure_script_function(self): + self.assert_roundtrip_not_equal([ + *(f for f in defs.SCRIPT_FUNCTIONS + if f not in defs.PURE_SCRIPT_FUNCTIONS), + ], expecttype=types.CodeType) + + class ShareableTypeTests(_GetXIDataTests): MODE = 'xidata' diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 3104cbc66cb..69f1a098920 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -338,17 +338,34 @@ class DictTest(unittest.TestCase): self.assertRaises(Exc, baddict2.fromkeys, [1]) # test fast path for dictionary inputs + res = dict(zip(range(6), [0]*6)) d = dict(zip(range(6), range(6))) - self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) - + self.assertEqual(dict.fromkeys(d, 0), res) + # test fast path for set inputs + d = set(range(6)) + self.assertEqual(dict.fromkeys(d, 0), res) + # test slow path for other iterable inputs + d = list(range(6)) + self.assertEqual(dict.fromkeys(d, 0), res) + + # test fast path when object's constructor returns large non-empty dict class baddict3(dict): def __new__(cls): return d - d = {i : i for i in range(10)} + d = {i : i for i in range(1000)} res = d.copy() res.update(a=None, b=None, c=None) self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) + # test slow path when object is a proper subclass of dict + class baddict4(dict): + def __init__(self): + dict.__init__(self, d) + d = {i : i for i in range(1000)} + res = d.copy() + res.update(a=None, b=None, c=None) + self.assertEqual(baddict4.fromkeys({"a", "b", "c"}), res) + def test_copy(self): d = {1: 1, 2: 2, 3: 3} self.assertIsNot(d.copy(), d) diff --git a/Lib/test/test_free_threading/test_io.py b/Lib/test/test_free_threading/test_io.py new file mode 100644 index 00000000000..f9bec740ddf --- /dev/null +++ b/Lib/test/test_free_threading/test_io.py @@ -0,0 +1,109 @@ +import threading +from unittest import TestCase +from test.support import threading_helper +from random import randint +from io import BytesIO +from sys import getsizeof + + +class TestBytesIO(TestCase): + # Test pretty much everything that can break under free-threading. + # Non-deterministic, but at least one of these things will fail if + # BytesIO object is not free-thread safe. + + def check(self, funcs, *args): + barrier = threading.Barrier(len(funcs)) + threads = [] + + for func in funcs: + thread = threading.Thread(target=func, args=(barrier, *args)) + + threads.append(thread) + + with threading_helper.start_threads(threads): + pass + + @threading_helper.requires_working_threading() + @threading_helper.reap_threads + def test_free_threading(self): + """Test for segfaults and aborts.""" + + def write(barrier, b, *ignore): + barrier.wait() + try: b.write(b'0' * randint(100, 1000)) + except ValueError: pass # ignore write fail to closed file + + def writelines(barrier, b, *ignore): + barrier.wait() + b.write(b'0\n' * randint(100, 1000)) + + def truncate(barrier, b, *ignore): + barrier.wait() + try: b.truncate(0) + except: BufferError # ignore exported buffer + + def read(barrier, b, *ignore): + barrier.wait() + b.read() + + def read1(barrier, b, *ignore): + barrier.wait() + b.read1() + + def readline(barrier, b, *ignore): + barrier.wait() + b.readline() + + def readlines(barrier, b, *ignore): + barrier.wait() + b.readlines() + + def readinto(barrier, b, into, *ignore): + barrier.wait() + b.readinto(into) + + def close(barrier, b, *ignore): + barrier.wait() + b.close() + + def getvalue(barrier, b, *ignore): + barrier.wait() + b.getvalue() + + def getbuffer(barrier, b, *ignore): + barrier.wait() + b.getbuffer() + + def iter(barrier, b, *ignore): + barrier.wait() + list(b) + + def getstate(barrier, b, *ignore): + barrier.wait() + b.__getstate__() + + def setstate(barrier, b, st, *ignore): + barrier.wait() + b.__setstate__(st) + + def sizeof(barrier, b, *ignore): + barrier.wait() + getsizeof(b) + + self.check([write] * 10, BytesIO()) + self.check([writelines] * 10, BytesIO()) + self.check([write] * 10 + [truncate] * 10, BytesIO()) + self.check([truncate] + [read] * 10, BytesIO(b'0\n'*204800)) + self.check([truncate] + [read1] * 10, BytesIO(b'0\n'*204800)) + self.check([truncate] + [readline] * 10, BytesIO(b'0\n'*20480)) + self.check([truncate] + [readlines] * 10, BytesIO(b'0\n'*20480)) + self.check([truncate] + [readinto] * 10, BytesIO(b'0\n'*204800), bytearray(b'0\n'*204800)) + self.check([close] + [write] * 10, BytesIO()) + self.check([truncate] + [getvalue] * 10, BytesIO(b'0\n'*204800)) + self.check([truncate] + [getbuffer] * 10, BytesIO(b'0\n'*204800)) + self.check([truncate] + [iter] * 10, BytesIO(b'0\n'*20480)) + self.check([truncate] + [getstate] * 10, BytesIO(b'0\n'*204800)) + self.check([truncate] + [setstate] * 10, BytesIO(b'0\n'*204800), (b'123', 0, None)) + self.check([truncate] + [sizeof] * 10, BytesIO(b'0\n'*204800)) + + # no tests for seek or tell because they don't break anything diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 2e794b0fc95..f7e09fd771e 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -21,6 +21,7 @@ from weakref import proxy import contextlib from inspect import Signature +from test.support import ALWAYS_EQ from test.support import import_helper from test.support import threading_helper from test.support import cpython_only @@ -244,6 +245,13 @@ class TestPartial: actual_args, actual_kwds = p('x', 'y') self.assertEqual(actual_args, ('x', 0, 'y', 1)) self.assertEqual(actual_kwds, {}) + # Checks via `is` and not `eq` + # thus ALWAYS_EQ isn't treated as Placeholder + p = self.partial(capture, ALWAYS_EQ) + actual_args, actual_kwds = p() + self.assertEqual(len(actual_args), 1) + self.assertIs(actual_args[0], ALWAYS_EQ) + self.assertEqual(actual_kwds, {}) def test_placeholders_optimization(self): PH = self.module.Placeholder @@ -260,6 +268,17 @@ class TestPartial: self.assertEqual(p2.args, (PH, 0)) self.assertEqual(p2(1), ((1, 0), {})) + def test_placeholders_kw_restriction(self): + PH = self.module.Placeholder + with self.assertRaisesRegex(TypeError, "Placeholder"): + self.partial(capture, a=PH) + # Passes, as checks via `is` and not `eq` + p = self.partial(capture, a=ALWAYS_EQ) + actual_args, actual_kwds = p() + self.assertEqual(actual_args, ()) + self.assertEqual(len(actual_kwds), 1) + self.assertIs(actual_kwds['a'], ALWAYS_EQ) + def test_construct_placeholder_singleton(self): PH = self.module.Placeholder tp = type(PH) diff --git a/Lib/test/test_future_stmt/test_future.py b/Lib/test/test_future_stmt/test_future.py index 42c6cb3fefa..71f1e616116 100644 --- a/Lib/test/test_future_stmt/test_future.py +++ b/Lib/test/test_future_stmt/test_future.py @@ -422,6 +422,11 @@ class AnnotationsFutureTestCase(unittest.TestCase): eq('(((a)))', 'a') eq('(((a, b)))', '(a, b)') eq("1 + 2 + 3") + eq("t''") + eq("t'{a + b}'") + eq("t'{a!s}'") + eq("t'{a:b}'") + eq("t'{a:b=}'") def test_fstring_debug_annotations(self): # f-strings with '=' don't round trip very well, so set the expected diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index 8fae12c478c..95c98c6ac63 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -7,7 +7,7 @@ from test.support import (verbose, refcount_test, Py_GIL_DISABLED) from test.support.import_helper import import_module from test.support.os_helper import temp_dir, TESTFN, unlink -from test.support.script_helper import assert_python_ok, make_script +from test.support.script_helper import assert_python_ok, make_script, run_test_script from test.support import threading_helper, gc_threshold import gc @@ -1127,64 +1127,14 @@ class GCTests(unittest.TestCase): class IncrementalGCTests(unittest.TestCase): - - def setUp(self): - # Reenable GC as it is disabled module-wide - gc.enable() - - def tearDown(self): - gc.disable() - @unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi") @requires_gil_enabled("Free threading does not support incremental GC") - # Use small increments to emulate longer running process in a shorter time - @gc_threshold(200, 10) def test_incremental_gc_handles_fast_cycle_creation(self): - - class LinkedList: - - #Use slots to reduce number of implicit objects - __slots__ = "next", "prev", "surprise" - - def __init__(self, next=None, prev=None): - self.next = next - if next is not None: - next.prev = self - self.prev = prev - if prev is not None: - prev.next = self - - def make_ll(depth): - head = LinkedList() - for i in range(depth): - head = LinkedList(head, head.prev) - return head - - head = make_ll(1000) - count = 1000 - - # There will be some objects we aren't counting, - # e.g. the gc stats dicts. This test checks - # that the counts don't grow, so we try to - # correct for the uncounted objects - # This is just an estimate. - CORRECTION = 20 - - enabled = gc.isenabled() - gc.enable() - olds = [] - initial_heap_size = _testinternalcapi.get_tracked_heap_size() - for i in range(20_000): - newhead = make_ll(20) - count += 20 - newhead.surprise = head - olds.append(newhead) - if len(olds) == 20: - new_objects = _testinternalcapi.get_tracked_heap_size() - initial_heap_size - self.assertLess(new_objects, 27_000, f"Heap growing. Reached limit after {i} iterations") - del olds[:] - if not enabled: - gc.disable() + # Run this test in a fresh process. The number of alive objects (which can + # be from unit tests run before this one) can influence how quickly cyclic + # garbage is found. + script = support.findfile("_test_gc_fast_cycles.py") + run_test_script(script) class GCCallbackTests(unittest.TestCase): diff --git a/Lib/test/test_generated_cases.py b/Lib/test/test_generated_cases.py index d481cb07f75..a71ddc01d1c 100644 --- a/Lib/test/test_generated_cases.py +++ b/Lib/test/test_generated_cases.py @@ -2069,6 +2069,189 @@ class TestGeneratedAbstractCases(unittest.TestCase): with self.assertRaisesRegex(AssertionError, "All abstract uops"): self.run_cases_test(input, input2, output) + def test_validate_uop_input_length_mismatch(self): + input = """ + op(OP, (arg1 -- out)) { + SPAM(); + } + """ + input2 = """ + op(OP, (arg1, arg2 -- out)) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Must have the same number of inputs"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_output_length_mismatch(self): + input = """ + op(OP, (arg1 -- out)) { + SPAM(); + } + """ + input2 = """ + op(OP, (arg1 -- out1, out2)) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Must have the same number of outputs"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_input_name_mismatch(self): + input = """ + op(OP, (foo -- out)) { + SPAM(); + } + """ + input2 = """ + op(OP, (bar -- out)) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Inputs must have equal names"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_output_name_mismatch(self): + input = """ + op(OP, (arg1 -- foo)) { + SPAM(); + } + """ + input2 = """ + op(OP, (arg1 -- bar)) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Outputs must have equal names"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_unused_input(self): + input = """ + op(OP, (unused -- )) { + } + """ + input2 = """ + op(OP, (foo -- )) { + } + """ + output = """ + case OP: { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + """ + self.run_cases_test(input, input2, output) + + input = """ + op(OP, (foo -- )) { + } + """ + input2 = """ + op(OP, (unused -- )) { + } + """ + output = """ + case OP: { + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_validate_uop_unused_output(self): + input = """ + op(OP, ( -- unused)) { + } + """ + input2 = """ + op(OP, ( -- foo)) { + foo = NULL; + } + """ + output = """ + case OP: { + JitOptSymbol *foo; + foo = NULL; + stack_pointer[0] = foo; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + """ + self.run_cases_test(input, input2, output) + + input = """ + op(OP, ( -- foo)) { + foo = NULL; + } + """ + input2 = """ + op(OP, ( -- unused)) { + } + """ + output = """ + case OP: { + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); + break; + } + """ + self.run_cases_test(input, input2, output) + + def test_validate_uop_input_size_mismatch(self): + input = """ + op(OP, (arg1[2] -- )) { + } + """ + input2 = """ + op(OP, (arg1[4] -- )) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Inputs must have equal sizes"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_output_size_mismatch(self): + input = """ + op(OP, ( -- out[2])) { + } + """ + input2 = """ + op(OP, ( -- out[4])) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Outputs must have equal sizes"): + self.run_cases_test(input, input2, output) + + def test_validate_uop_unused_size_mismatch(self): + input = """ + op(OP, (foo[2] -- )) { + } + """ + input2 = """ + op(OP, (unused[4] -- )) { + } + """ + output = """ + """ + with self.assertRaisesRegex(SyntaxError, + "Inputs must have equal sizes"): + self.run_cases_test(input, input2, output) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py index 9af1e4d505c..f78dc399720 100644 --- a/Lib/test/test_importlib/test_threaded_import.py +++ b/Lib/test/test_importlib/test_threaded_import.py @@ -135,10 +135,12 @@ class ThreadedImportTests(unittest.TestCase): if verbose: print("OK.") - def test_parallel_module_init(self): + @support.bigmemtest(size=50, memuse=76*2**20, dry_run=False) + def test_parallel_module_init(self, size): self.check_parallel_module_init() - def test_parallel_meta_path(self): + @support.bigmemtest(size=50, memuse=76*2**20, dry_run=False) + def test_parallel_meta_path(self, size): finder = Finder() sys.meta_path.insert(0, finder) try: @@ -148,7 +150,8 @@ class ThreadedImportTests(unittest.TestCase): finally: sys.meta_path.remove(finder) - def test_parallel_path_hooks(self): + @support.bigmemtest(size=50, memuse=76*2**20, dry_run=False) + def test_parallel_path_hooks(self, size): # Here the Finder instance is only used to check concurrent calls # to path_hook(). finder = Finder() @@ -242,13 +245,15 @@ class ThreadedImportTests(unittest.TestCase): __import__(TESTFN) del sys.modules[TESTFN] - def test_concurrent_futures_circular_import(self): + @support.bigmemtest(size=1, memuse=1.8*2**30, dry_run=False) + def test_concurrent_futures_circular_import(self, size): # Regression test for bpo-43515 fn = os.path.join(os.path.dirname(__file__), 'partial', 'cfimport.py') script_helper.assert_python_ok(fn) - def test_multiprocessing_pool_circular_import(self): + @support.bigmemtest(size=1, memuse=1.8*2**30, dry_run=False) + def test_multiprocessing_pool_circular_import(self, size): # Regression test for bpo-41567 fn = os.path.join(os.path.dirname(__file__), 'partial', 'pool_in_threads.py') diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py index 3f113ec1be4..1e5adcc8db1 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -4214,6 +4214,89 @@ class ConfigDictTest(BaseTest): handler = logging.getHandlerByName('custom') self.assertEqual(handler.custom_kwargs, custom_kwargs) + # See gh-91555 and gh-90321 + @support.requires_subprocess() + def test_deadlock_in_queue(self): + queue = multiprocessing.Queue() + handler = logging.handlers.QueueHandler(queue) + logger = multiprocessing.get_logger() + level = logger.level + try: + logger.setLevel(logging.DEBUG) + logger.addHandler(handler) + logger.debug("deadlock") + finally: + logger.setLevel(level) + logger.removeHandler(handler) + + def test_recursion_in_custom_handler(self): + class BadHandler(logging.Handler): + def __init__(self): + super().__init__() + def emit(self, record): + logger.debug("recurse") + logger = logging.getLogger("test_recursion_in_custom_handler") + logger.addHandler(BadHandler()) + logger.setLevel(logging.DEBUG) + logger.debug("boom") + + @threading_helper.requires_working_threading() + def test_thread_supression_noninterference(self): + lock = threading.Lock() + logger = logging.getLogger("test_thread_supression_noninterference") + + # Block on the first call, allow others through + # + # NOTE: We need to bypass the base class's lock, otherwise that will + # block multiple calls to the same handler itself. + class BlockOnceHandler(TestHandler): + def __init__(self, barrier): + super().__init__(support.Matcher()) + self.barrier = barrier + + def createLock(self): + self.lock = None + + def handle(self, record): + self.emit(record) + + def emit(self, record): + if self.barrier: + barrier = self.barrier + self.barrier = None + barrier.wait() + with lock: + pass + super().emit(record) + logger.info("blow up if not supressed") + + barrier = threading.Barrier(2) + handler = BlockOnceHandler(barrier) + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + + t1 = threading.Thread(target=logger.debug, args=("1",)) + with lock: + + # Ensure first thread is blocked in the handler, hence supressing logging... + t1.start() + barrier.wait() + + # ...but the second thread should still be able to log... + t2 = threading.Thread(target=logger.debug, args=("2",)) + t2.start() + t2.join(timeout=3) + + self.assertEqual(len(handler.buffer), 1) + self.assertTrue(handler.matches(levelno=logging.DEBUG, message='2')) + + # The first thread should still be blocked here + self.assertTrue(t1.is_alive()) + + # Now the lock has been released the first thread should complete + t1.join() + self.assertEqual(len(handler.buffer), 2) + self.assertTrue(handler.matches(levelno=logging.DEBUG, message='1')) class ManagerTest(BaseTest): def test_manager_loggerclass(self): diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index 93029ab6e08..fc8114891d1 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -452,6 +452,11 @@ class TestPyReplAutoindent(TestCase): ) # fmt: on + events = code_to_events(input_code) + reader = self.prepare_reader(events) + output = multiline_input(reader) + self.assertEqual(output, output_code) + def test_auto_indent_continuation(self): # auto indenting according to previous user indentation # fmt: off diff --git a/Lib/test/test_pyrepl/test_reader.py b/Lib/test/test_pyrepl/test_reader.py index 4ee320a5a4d..57526f88f93 100644 --- a/Lib/test/test_pyrepl/test_reader.py +++ b/Lib/test/test_pyrepl/test_reader.py @@ -497,6 +497,26 @@ class TestReaderInColor(ScreenEqualMixin, TestCase): self.assert_screen_equal(reader, code, clean=True) self.assert_screen_equal(reader, expected) + def test_syntax_highlighting_indentation_error(self): + code = dedent( + """\ + def unfinished_function(): + var = 1 + oops + """ + ) + expected = dedent( + """\ + {k}def{z} {d}unfinished_function{z}{o}({z}{o}){z}{o}:{z} + var {o}={z} {n}1{z} + oops + """ + ).format(**colors) + events = code_to_events(code) + reader, _ = handle_all_events(events) + self.assert_screen_equal(reader, code, clean=True) + self.assert_screen_equal(reader, expected) + def test_control_characters(self): code = 'flag = "🏳️🌈"' events = code_to_events(code) diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py index c3aa3bf2d7b..291e0356253 100644 --- a/Lib/test/test_sqlite3/test_dbapi.py +++ b/Lib/test/test_sqlite3/test_dbapi.py @@ -550,17 +550,9 @@ class ConnectionTests(unittest.TestCase): cx.execute("insert into u values(0)") def test_connect_positional_arguments(self): - regex = ( - r"Passing more than 1 positional argument to sqlite3.connect\(\)" - " is deprecated. Parameters 'timeout', 'detect_types', " - "'isolation_level', 'check_same_thread', 'factory', " - "'cached_statements' and 'uri' will become keyword-only " - "parameters in Python 3.15." - ) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - cx = sqlite.connect(":memory:", 1.0) - cx.close() - self.assertEqual(cm.filename, __file__) + with self.assertRaisesRegex(TypeError, + r'connect\(\) takes at most 1 positional arguments'): + sqlite.connect(":memory:", 1.0) def test_connection_resource_warning(self): with self.assertWarns(ResourceWarning): diff --git a/Lib/test/test_sqlite3/test_factory.py b/Lib/test/test_sqlite3/test_factory.py index cc9f1ec5c4b..776659e3b16 100644 --- a/Lib/test/test_sqlite3/test_factory.py +++ b/Lib/test/test_sqlite3/test_factory.py @@ -71,18 +71,9 @@ class ConnectionFactoryTests(unittest.TestCase): def __init__(self, *args, **kwargs): super(Factory, self).__init__(*args, **kwargs) - regex = ( - r"Passing more than 1 positional argument to _sqlite3.Connection\(\) " - r"is deprecated. Parameters 'timeout', 'detect_types', " - r"'isolation_level', 'check_same_thread', 'factory', " - r"'cached_statements' and 'uri' will become keyword-only " - r"parameters in Python 3.15." - ) - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - with memory_database(5.0, 0, None, True, Factory) as con: - self.assertIsNone(con.isolation_level) - self.assertIsInstance(con, Factory) - self.assertEqual(cm.filename, __file__) + with self.assertRaisesRegex(TypeError, + r'connect\(\) takes at most 1 positional arguments'): + memory_database(5.0, 0, None, True, Factory) class CursorFactoryTests(MemoryDatabaseMixin, unittest.TestCase): diff --git a/Lib/test/test_sqlite3/test_hooks.py b/Lib/test/test_sqlite3/test_hooks.py index 53b8a39bf29..2b907e35131 100644 --- a/Lib/test/test_sqlite3/test_hooks.py +++ b/Lib/test/test_sqlite3/test_hooks.py @@ -220,16 +220,9 @@ class ProgressTests(MemoryDatabaseMixin, unittest.TestCase): """) def test_progress_handler_keyword_args(self): - regex = ( - r"Passing keyword argument 'progress_handler' to " - r"_sqlite3.Connection.set_progress_handler\(\) is deprecated. " - r"Parameter 'progress_handler' will become positional-only in " - r"Python 3.15." - ) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: + with self.assertRaisesRegex(TypeError, + 'takes at least 1 positional argument'): self.con.set_progress_handler(progress_handler=lambda: None, n=1) - self.assertEqual(cm.filename, __file__) class TraceCallbackTests(MemoryDatabaseMixin, unittest.TestCase): @@ -353,16 +346,9 @@ class TraceCallbackTests(MemoryDatabaseMixin, unittest.TestCase): cx.execute("select 1") def test_trace_keyword_args(self): - regex = ( - r"Passing keyword argument 'trace_callback' to " - r"_sqlite3.Connection.set_trace_callback\(\) is deprecated. " - r"Parameter 'trace_callback' will become positional-only in " - r"Python 3.15." - ) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: + with self.assertRaisesRegex(TypeError, + 'takes exactly 1 positional argument'): self.con.set_trace_callback(trace_callback=lambda: None) - self.assertEqual(cm.filename, __file__) if __name__ == "__main__": diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py index 3abc43a3b1a..11cf877a011 100644 --- a/Lib/test/test_sqlite3/test_userfunctions.py +++ b/Lib/test/test_sqlite3/test_userfunctions.py @@ -422,27 +422,9 @@ class FunctionTests(unittest.TestCase): self.con.execute, "select badreturn()") def test_func_keyword_args(self): - regex = ( - r"Passing keyword arguments 'name', 'narg' and 'func' to " - r"_sqlite3.Connection.create_function\(\) is deprecated. " - r"Parameters 'name', 'narg' and 'func' will become " - r"positional-only in Python 3.15." - ) - - def noop(): - return None - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - self.con.create_function("noop", 0, func=noop) - self.assertEqual(cm.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - self.con.create_function("noop", narg=0, func=noop) - self.assertEqual(cm.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - self.con.create_function(name="noop", narg=0, func=noop) - self.assertEqual(cm.filename, __file__) + with self.assertRaisesRegex(TypeError, + 'takes exactly 3 positional arguments'): + self.con.create_function("noop", 0, func=lambda: None) class WindowSumInt: @@ -737,25 +719,9 @@ class AggregateTests(unittest.TestCase): self.assertEqual(val, txt) def test_agg_keyword_args(self): - regex = ( - r"Passing keyword arguments 'name', 'n_arg' and 'aggregate_class' to " - r"_sqlite3.Connection.create_aggregate\(\) is deprecated. " - r"Parameters 'name', 'n_arg' and 'aggregate_class' will become " - r"positional-only in Python 3.15." - ) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: + with self.assertRaisesRegex(TypeError, + 'takes exactly 3 positional arguments'): self.con.create_aggregate("test", 1, aggregate_class=AggrText) - self.assertEqual(cm.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - self.con.create_aggregate("test", n_arg=1, aggregate_class=AggrText) - self.assertEqual(cm.filename, __file__) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: - self.con.create_aggregate(name="test", n_arg=0, - aggregate_class=AggrText) - self.assertEqual(cm.filename, __file__) class AuthorizerTests(unittest.TestCase): @@ -800,16 +766,9 @@ class AuthorizerTests(unittest.TestCase): self.con.execute("select c2 from t1") def test_authorizer_keyword_args(self): - regex = ( - r"Passing keyword argument 'authorizer_callback' to " - r"_sqlite3.Connection.set_authorizer\(\) is deprecated. " - r"Parameter 'authorizer_callback' will become positional-only in " - r"Python 3.15." - ) - - with self.assertWarnsRegex(DeprecationWarning, regex) as cm: + with self.assertRaisesRegex(TypeError, + 'takes exactly 1 positional argument'): self.con.set_authorizer(authorizer_callback=lambda: None) - self.assertEqual(cm.filename, __file__) class AuthorizerRaiseExceptionTests(AuthorizerTests): diff --git a/Lib/test/test_threadedtempfile.py b/Lib/test/test_threadedtempfile.py index 420fc6ec8be..acb427b0c78 100644 --- a/Lib/test/test_threadedtempfile.py +++ b/Lib/test/test_threadedtempfile.py @@ -15,6 +15,7 @@ provoking a 2.0 failure under Linux. import tempfile +from test import support from test.support import threading_helper import unittest import io @@ -49,7 +50,8 @@ class TempFileGreedy(threading.Thread): class ThreadedTempFileTest(unittest.TestCase): - def test_main(self): + @support.bigmemtest(size=NUM_THREADS, memuse=60*2**20, dry_run=False) + def test_main(self, size): threads = [TempFileGreedy() for i in range(NUM_THREADS)] with threading_helper.start_threads(threads, startEvent.set): pass diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 4ab38c2598b..abe63c10c0a 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py @@ -530,7 +530,8 @@ class ThreadTests(BaseTestCase): finally: sys.setswitchinterval(old_interval) - def test_join_from_multiple_threads(self): + @support.bigmemtest(size=20, memuse=72*2**20, dry_run=False) + def test_join_from_multiple_threads(self, size): # Thread.join() should be thread-safe errors = [] @@ -1431,7 +1432,8 @@ class ThreadJoinOnShutdown(BaseTestCase): self._run_and_join(script) @unittest.skipIf(sys.platform in platforms_to_skip, "due to known OS bug") - def test_4_daemon_threads(self): + @support.bigmemtest(size=40, memuse=70*2**20, dry_run=False) + def test_4_daemon_threads(self, size): # Check that a daemon thread cannot crash the interpreter on shutdown # by manipulating internal structures that are being disposed of in # the main thread. diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index d3af7a8489e..d4db5e60af7 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -817,6 +817,15 @@ class CosmeticTestCase(ASTTestCase): self.check_ast_roundtrip("def f[T: int = int, **P = int, *Ts = *int]():\n pass") self.check_ast_roundtrip("class C[T: int = int, **P = int, *Ts = *int]():\n pass") + def test_tstr(self): + self.check_ast_roundtrip("t'{a + b}'") + self.check_ast_roundtrip("t'{a + b:x}'") + self.check_ast_roundtrip("t'{a + b!s}'") + self.check_ast_roundtrip("t'{ {a}}'") + self.check_ast_roundtrip("t'{ {a}=}'") + self.check_ast_roundtrip("t'{{a}}'") + self.check_ast_roundtrip("t''") + class ManualASTCreationTestCase(unittest.TestCase): """Test that AST nodes created without a type_params field unparse correctly.""" diff --git a/Misc/NEWS.d/3.11.0a4.rst b/Misc/NEWS.d/3.11.0a4.rst index a2d36202045..47cbf33c3bb 100644 --- a/Misc/NEWS.d/3.11.0a4.rst +++ b/Misc/NEWS.d/3.11.0a4.rst @@ -1161,7 +1161,7 @@ no-op now. .. nonce: Lq2_gR .. section: C API -Replaced deprecated usage of :c:func:`PyImport_ImportModuleNoBlock` with +Replaced deprecated usage of :c:func:`!PyImport_ImportModuleNoBlock` with :c:func:`PyImport_ImportModule` in stdlib modules. Patch by Kumar Aditya. .. diff --git a/Misc/NEWS.d/3.13.0a1.rst b/Misc/NEWS.d/3.13.0a1.rst index 91e9fee7e37..6149b33b076 100644 --- a/Misc/NEWS.d/3.13.0a1.rst +++ b/Misc/NEWS.d/3.13.0a1.rst @@ -6538,7 +6538,7 @@ to hide implementation details. Patch by Victor Stinner. .. nonce: FQJG5B .. section: C API -Deprecate the :c:func:`PyImport_ImportModuleNoBlock` function which is just +Deprecate the :c:func:`!PyImport_ImportModuleNoBlock` function which is just an alias to :c:func:`PyImport_ImportModule` since Python 3.3. Patch by Victor Stinner. diff --git a/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst b/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst new file mode 100644 index 00000000000..9569456eb76 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-05-08-12-25-47.gh-issue-133644.Yb86Rm.rst @@ -0,0 +1,2 @@ +Remove deprecated alias :c:func:`!PyImport_ImportModuleNoBlock` of +:c:func:`PyImport_ImportModule`. Patch by Bénédikt Tran. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst new file mode 100644 index 00000000000..ca8eb999ae5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-03-13-36-01.gh-issue-131798.U4_QEJ.rst @@ -0,0 +1,2 @@ +Split ``CALL_ISINSTANCE`` into several uops, allowing the JIT to remove some +of them. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst new file mode 100644 index 00000000000..4f4cd847fa5 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-07-23-26-53.gh-issue-133541.bHIC55.rst @@ -0,0 +1,2 @@ +Inconsistent indentation in user input crashed the new REPL when syntax +highlighting was active. This is now fixed. diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst new file mode 100644 index 00000000000..80b830ebd78 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-05-08-13-48-02.gh-issue-132762.tKbygC.rst @@ -0,0 +1 @@ +:meth:`~dict.fromkeys` no longer loops forever when adding a small set of keys to a large base dict. Patch by Angela Liss. diff --git a/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst b/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst new file mode 100644 index 00000000000..09ebee4d41b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-28-06-54-22.gh-issue-125028.GEY8Ws.rst @@ -0,0 +1 @@ +:data:`functools.Placeholder` cannot be passed to :func:`functools.partial` as a keyword argument. diff --git a/Misc/NEWS.d/next/Library/2025-03-30-16-42-38.gh-issue-91555.ShVtwW.rst b/Misc/NEWS.d/next/Library/2025-03-30-16-42-38.gh-issue-91555.ShVtwW.rst new file mode 100644 index 00000000000..e8f5ba56fcc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-03-30-16-42-38.gh-issue-91555.ShVtwW.rst @@ -0,0 +1,2 @@ +Ignore log messages generated during handling of log messages, to avoid +deadlock or infinite recursion. diff --git a/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst b/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst new file mode 100644 index 00000000000..c8743d49ca0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-16-21-02-57.gh-issue-132551.Psa7pL.rst @@ -0,0 +1 @@ +Make :class:`io.BytesIO` safe in :term:`free-threaded <free threading>` build. diff --git a/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst b/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst new file mode 100644 index 00000000000..7fedc0818dc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-06-22-54-37.gh-issue-133551.rfy1tJ.rst @@ -0,0 +1,2 @@ +Support t-strings (:pep:`750`) in :mod:`annotationlib`. Patch by Jelle +Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst b/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst new file mode 100644 index 00000000000..3749904cd9b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-07-19-16-41.gh-issue-133581.kERUCJ.rst @@ -0,0 +1,4 @@ +Improve unparsing of t-strings in :func:`ast.unparse` and ``from __future__ +import annotations``. Empty t-strings now round-trip correctly and +formatting in interpolations is preserved. +Patch by Jelle Zijlstra. diff --git a/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst b/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst new file mode 100644 index 00000000000..a61c4bf1913 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-05-07-22-15-15.gh-issue-133595.c3U88r.rst @@ -0,0 +1,7 @@ +Clean up :class:`sqlite3.Connection` APIs. All parameters of +:func:`sqlite3.connect` except *database* are now keyword-only. The first +three parameters of methods :meth:`~sqlite3.Connection.create_function` and +:meth:`~sqlite3.Connection.create_aggregate` are now positional-only. The +first parameter of methods :meth:`~sqlite3.Connection.set_authorizer`, +:meth:`~sqlite3.Connection.set_progress_handler` and +:meth:`~sqlite3.Connection.set_trace_callback` is now positional-only. diff --git a/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst b/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst new file mode 100644 index 00000000000..68826cd95fa --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2025-05-08-15-06-01.gh-issue-133639.50-kbV.rst @@ -0,0 +1,2 @@ +Fix ``TestPyReplAutoindent.test_auto_indent_default()`` doesn't run +``input_code``. diff --git a/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst b/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst new file mode 100644 index 00000000000..837f7265bba --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-03-31-15-37-57.gh-issue-131942.jip_aL.rst @@ -0,0 +1 @@ +Use the Python-specific :c:macro:`Py_DEBUG` macro rather than :c:macro:`!_DEBUG` in Windows-related C code. Patch by Xuehai Pan. diff --git a/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst b/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst new file mode 100644 index 00000000000..6c80d96bb83 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2025-05-08-19-07-26.gh-issue-133626.yFTKYK.rst @@ -0,0 +1,2 @@ +Ensures packages are not accidentally bundled into the traditional +installer. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index d3e1f0db057..886979139ee 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -888,6 +888,7 @@ added = '3.2' [function.PyImport_ImportModuleNoBlock] added = '3.2' + abi_only = true [function.PyImport_ReloadModule] added = '3.2' [function.PyInterpreterState_Clear] diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 856b0376e5e..404178ca623 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -92,7 +92,7 @@ module _ctypes #include <sanitizer/msan_interface.h> #endif -#if defined(_DEBUG) || defined(__MINGW32__) +#if defined(Py_DEBUG) || defined(__MINGW32__) /* Don't use structured exception handling on Windows if this is defined. MingW, AFAIK, doesn't support it. */ diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c index e6c454faf4b..899eef50ecc 100644 --- a/Modules/_functoolsmodule.c +++ b/Modules/_functoolsmodule.c @@ -196,6 +196,19 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) return NULL; } + /* keyword Placeholder prohibition */ + if (kw != NULL) { + PyObject *key, *val; + Py_ssize_t pos = 0; + while (PyDict_Next(kw, &pos, &key, &val)) { + if (val == phold) { + PyErr_SetString(PyExc_TypeError, + "Placeholder cannot be passed as a keyword argument"); + return NULL; + } + } + } + /* check wrapped function / object */ pto_args = pto_kw = NULL; int res = PyObject_TypeCheck(func, state->partial_type); diff --git a/Modules/_io/bytesio.c b/Modules/_io/bytesio.c index e45a2d1a16d..4cde5f87032 100644 --- a/Modules/_io/bytesio.c +++ b/Modules/_io/bytesio.c @@ -1,8 +1,10 @@ #include "Python.h" +#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION() #include "pycore_object.h" -#include "pycore_sysmodule.h" // _PySys_GetSizeOf() +#include "pycore_pyatomic_ft_wrappers.h" +#include "pycore_sysmodule.h" // _PySys_GetSizeOf() -#include <stddef.h> // offsetof() +#include <stddef.h> // offsetof() #include "_iomodule.h" /*[clinic input] @@ -50,7 +52,7 @@ check_closed(bytesio *self) static int check_exports(bytesio *self) { - if (self->exports > 0) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) { PyErr_SetString(PyExc_BufferError, "Existing exports of data: object cannot be re-sized"); return 1; @@ -68,15 +70,17 @@ check_exports(bytesio *self) return NULL; \ } -#define SHARED_BUF(self) (Py_REFCNT((self)->buf) > 1) +#define SHARED_BUF(self) (!_PyObject_IsUniquelyReferenced((self)->buf)) /* Internal routine to get a line from the buffer of a BytesIO object. Returns the length between the current position to the next newline character. */ static Py_ssize_t -scan_eol(bytesio *self, Py_ssize_t len) +scan_eol_lock_held(bytesio *self, Py_ssize_t len) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + const char *start, *n; Py_ssize_t maxlen; @@ -109,11 +113,13 @@ scan_eol(bytesio *self, Py_ssize_t len) The caller should ensure that the 'size' argument is non-negative and not lesser than self->string_size. Returns 0 on success, -1 otherwise. */ static int -unshare_buffer(bytesio *self, size_t size) +unshare_buffer_lock_held(bytesio *self, size_t size) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + PyObject *new_buf; assert(SHARED_BUF(self)); - assert(self->exports == 0); + assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0); assert(size >= (size_t)self->string_size); new_buf = PyBytes_FromStringAndSize(NULL, size); if (new_buf == NULL) @@ -128,10 +134,12 @@ unshare_buffer(bytesio *self, size_t size) The caller should ensure that the 'size' argument is non-negative. Returns 0 on success, -1 otherwise. */ static int -resize_buffer(bytesio *self, size_t size) +resize_buffer_lock_held(bytesio *self, size_t size) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + assert(self->buf != NULL); - assert(self->exports == 0); + assert(FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0); /* Here, unsigned types are used to avoid dealing with signed integer overflow, which is undefined in C. */ @@ -160,7 +168,7 @@ resize_buffer(bytesio *self, size_t size) } if (SHARED_BUF(self)) { - if (unshare_buffer(self, alloc) < 0) + if (unshare_buffer_lock_held(self, alloc) < 0) return -1; } else { @@ -181,8 +189,10 @@ resize_buffer(bytesio *self, size_t size) Inlining is disabled because it's significantly decreases performance of writelines() in PGO build. */ Py_NO_INLINE static Py_ssize_t -write_bytes(bytesio *self, PyObject *b) +write_bytes_lock_held(bytesio *self, PyObject *b) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + if (check_closed(self)) { return -1; } @@ -202,13 +212,13 @@ write_bytes(bytesio *self, PyObject *b) assert(self->pos >= 0); size_t endpos = (size_t)self->pos + len; if (endpos > (size_t)PyBytes_GET_SIZE(self->buf)) { - if (resize_buffer(self, endpos) < 0) { + if (resize_buffer_lock_held(self, endpos) < 0) { len = -1; goto done; } } else if (SHARED_BUF(self)) { - if (unshare_buffer(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) { + if (unshare_buffer_lock_held(self, Py_MAX(endpos, (size_t)self->string_size)) < 0) { len = -1; goto done; } @@ -245,13 +255,17 @@ write_bytes(bytesio *self, PyObject *b) static PyObject * bytesio_get_closed(PyObject *op, void *Py_UNUSED(closure)) { + PyObject *ret; bytesio *self = bytesio_CAST(op); + Py_BEGIN_CRITICAL_SECTION(self); if (self->buf == NULL) { - Py_RETURN_TRUE; + ret = Py_True; } else { - Py_RETURN_FALSE; + ret = Py_False; } + Py_END_CRITICAL_SECTION(); + return ret; } /*[clinic input] @@ -311,6 +325,7 @@ _io_BytesIO_flush_impl(bytesio *self) } /*[clinic input] +@critical_section _io.BytesIO.getbuffer cls: defining_class @@ -321,7 +336,7 @@ Get a read-write view over the contents of the BytesIO object. static PyObject * _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls) -/*[clinic end generated code: output=045091d7ce87fe4e input=0668fbb48f95dffa]*/ +/*[clinic end generated code: output=045091d7ce87fe4e input=8295764061be77fd]*/ { _PyIO_State *state = get_io_state_by_cls(cls); PyTypeObject *type = state->PyBytesIOBuffer_Type; @@ -340,6 +355,7 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls) } /*[clinic input] +@critical_section _io.BytesIO.getvalue Retrieve the entire contents of the BytesIO object. @@ -347,16 +363,16 @@ Retrieve the entire contents of the BytesIO object. static PyObject * _io_BytesIO_getvalue_impl(bytesio *self) -/*[clinic end generated code: output=b3f6a3233c8fd628 input=4b403ac0af3973ed]*/ +/*[clinic end generated code: output=b3f6a3233c8fd628 input=c91bff398df0c352]*/ { CHECK_CLOSED(self); - if (self->string_size <= 1 || self->exports > 0) + if (self->string_size <= 1 || FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) return PyBytes_FromStringAndSize(PyBytes_AS_STRING(self->buf), self->string_size); if (self->string_size != PyBytes_GET_SIZE(self->buf)) { if (SHARED_BUF(self)) { - if (unshare_buffer(self, self->string_size) < 0) + if (unshare_buffer_lock_held(self, self->string_size) < 0) return NULL; } else { @@ -384,6 +400,7 @@ _io_BytesIO_isatty_impl(bytesio *self) } /*[clinic input] +@critical_section _io.BytesIO.tell Current file position, an integer. @@ -391,22 +408,24 @@ Current file position, an integer. static PyObject * _io_BytesIO_tell_impl(bytesio *self) -/*[clinic end generated code: output=b54b0f93cd0e5e1d input=b106adf099cb3657]*/ +/*[clinic end generated code: output=b54b0f93cd0e5e1d input=2c7b0e8f82e05c4d]*/ { CHECK_CLOSED(self); return PyLong_FromSsize_t(self->pos); } static PyObject * -read_bytes(bytesio *self, Py_ssize_t size) +read_bytes_lock_held(bytesio *self, Py_ssize_t size) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(self); + const char *output; assert(self->buf != NULL); assert(size <= self->string_size); if (size > 1 && self->pos == 0 && size == PyBytes_GET_SIZE(self->buf) && - self->exports == 0) { + FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) { self->pos += size; return Py_NewRef(self->buf); } @@ -417,6 +436,7 @@ read_bytes(bytesio *self, Py_ssize_t size) } /*[clinic input] +@critical_section _io.BytesIO.read size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -429,7 +449,7 @@ Return an empty bytes object at EOF. static PyObject * _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size) -/*[clinic end generated code: output=9cc025f21c75bdd2 input=74344a39f431c3d7]*/ +/*[clinic end generated code: output=9cc025f21c75bdd2 input=9e2f7ff3075fdd39]*/ { Py_ssize_t n; @@ -443,11 +463,12 @@ _io_BytesIO_read_impl(bytesio *self, Py_ssize_t size) size = 0; } - return read_bytes(self, size); + return read_bytes_lock_held(self, size); } /*[clinic input] +@critical_section _io.BytesIO.read1 size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -460,12 +481,13 @@ Return an empty bytes object at EOF. static PyObject * _io_BytesIO_read1_impl(bytesio *self, Py_ssize_t size) -/*[clinic end generated code: output=d0f843285aa95f1c input=440a395bf9129ef5]*/ +/*[clinic end generated code: output=d0f843285aa95f1c input=a08fc9e507ab380c]*/ { return _io_BytesIO_read_impl(self, size); } /*[clinic input] +@critical_section _io.BytesIO.readline size: Py_ssize_t(accept={int, NoneType}) = -1 / @@ -479,18 +501,19 @@ Return an empty bytes object at EOF. static PyObject * _io_BytesIO_readline_impl(bytesio *self, Py_ssize_t size) -/*[clinic end generated code: output=4bff3c251df8ffcd input=e7c3fbd1744e2783]*/ +/*[clinic end generated code: output=4bff3c251df8ffcd input=db09d47e23cf2c9e]*/ { Py_ssize_t n; CHECK_CLOSED(self); - n = scan_eol(self, size); + n = scan_eol_lock_held(self, size); - return read_bytes(self, n); + return read_bytes_lock_held(self, n); } /*[clinic input] +@critical_section _io.BytesIO.readlines size as arg: object = None / @@ -504,7 +527,7 @@ total number of bytes in the lines returned. static PyObject * _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) -/*[clinic end generated code: output=09b8e34c880808ff input=691aa1314f2c2a87]*/ +/*[clinic end generated code: output=09b8e34c880808ff input=5c57d7d78e409985]*/ { Py_ssize_t maxsize, size, n; PyObject *result, *line; @@ -533,7 +556,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) return NULL; output = PyBytes_AS_STRING(self->buf) + self->pos; - while ((n = scan_eol(self, -1)) != 0) { + while ((n = scan_eol_lock_held(self, -1)) != 0) { self->pos += n; line = PyBytes_FromStringAndSize(output, n); if (!line) @@ -556,6 +579,7 @@ _io_BytesIO_readlines_impl(bytesio *self, PyObject *arg) } /*[clinic input] +@critical_section _io.BytesIO.readinto buffer: Py_buffer(accept={rwbuffer}) / @@ -568,7 +592,7 @@ is set not to block and has no data to read. static PyObject * _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer) -/*[clinic end generated code: output=a5d407217dcf0639 input=1424d0fdce857919]*/ +/*[clinic end generated code: output=a5d407217dcf0639 input=093a8d330de3fcd1]*/ { Py_ssize_t len, n; @@ -592,8 +616,9 @@ _io_BytesIO_readinto_impl(bytesio *self, Py_buffer *buffer) } /*[clinic input] +@critical_section _io.BytesIO.truncate - size: Py_ssize_t(accept={int, NoneType}, c_default="((bytesio *)self)->pos") = None + size: object = None / Truncate the file to at most size bytes. @@ -603,44 +628,68 @@ The current file position is unchanged. Returns the new size. [clinic start generated code]*/ static PyObject * -_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size) -/*[clinic end generated code: output=9ad17650c15fa09b input=dae4295e11c1bbb4]*/ +_io_BytesIO_truncate_impl(bytesio *self, PyObject *size) +/*[clinic end generated code: output=ab42491b4824f384 input=b4acb5f80481c053]*/ { CHECK_CLOSED(self); CHECK_EXPORTS(self); - if (size < 0) { - PyErr_Format(PyExc_ValueError, - "negative size value %zd", size); - return NULL; + Py_ssize_t new_size; + + if (size == Py_None) { + new_size = self->pos; + } + else { + new_size = PyLong_AsLong(size); + if (new_size == -1 && PyErr_Occurred()) { + return NULL; + } + if (new_size < 0) { + PyErr_Format(PyExc_ValueError, + "negative size value %zd", new_size); + return NULL; + } } - if (size < self->string_size) { - self->string_size = size; - if (resize_buffer(self, size) < 0) + if (new_size < self->string_size) { + self->string_size = new_size; + if (resize_buffer_lock_held(self, new_size) < 0) return NULL; } - return PyLong_FromSsize_t(size); + return PyLong_FromSsize_t(new_size); } static PyObject * -bytesio_iternext(PyObject *op) +bytesio_iternext_lock_held(PyObject *op) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + Py_ssize_t n; bytesio *self = bytesio_CAST(op); CHECK_CLOSED(self); - n = scan_eol(self, -1); + n = scan_eol_lock_held(self, -1); if (n == 0) return NULL; - return read_bytes(self, n); + return read_bytes_lock_held(self, n); +} + +static PyObject * +bytesio_iternext(PyObject *op) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = bytesio_iternext_lock_held(op); + Py_END_CRITICAL_SECTION(); + return ret; } /*[clinic input] +@critical_section _io.BytesIO.seek pos: Py_ssize_t whence: int = 0 @@ -657,7 +706,7 @@ Returns the new absolute position. static PyObject * _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence) -/*[clinic end generated code: output=c26204a68e9190e4 input=1e875e6ebc652948]*/ +/*[clinic end generated code: output=c26204a68e9190e4 input=20f05ddf659255df]*/ { CHECK_CLOSED(self); @@ -700,6 +749,7 @@ _io_BytesIO_seek_impl(bytesio *self, Py_ssize_t pos, int whence) } /*[clinic input] +@critical_section _io.BytesIO.write b: object / @@ -711,13 +761,14 @@ Return the number of bytes written. static PyObject * _io_BytesIO_write_impl(bytesio *self, PyObject *b) -/*[clinic end generated code: output=d3e46bcec8d9e21c input=f5ec7c8c64ed720a]*/ +/*[clinic end generated code: output=d3e46bcec8d9e21c input=46c0c17eac7474a4]*/ { - Py_ssize_t n = write_bytes(self, b); + Py_ssize_t n = write_bytes_lock_held(self, b); return n >= 0 ? PyLong_FromSsize_t(n) : NULL; } /*[clinic input] +@critical_section _io.BytesIO.writelines lines: object / @@ -731,7 +782,7 @@ each element. static PyObject * _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines) -/*[clinic end generated code: output=03a43a75773bc397 input=e972539176fc8fc1]*/ +/*[clinic end generated code: output=03a43a75773bc397 input=5d6a616ae39dc9ca]*/ { PyObject *it, *item; @@ -742,7 +793,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines) return NULL; while ((item = PyIter_Next(it)) != NULL) { - Py_ssize_t ret = write_bytes(self, item); + Py_ssize_t ret = write_bytes_lock_held(self, item); Py_DECREF(item); if (ret < 0) { Py_DECREF(it); @@ -759,6 +810,7 @@ _io_BytesIO_writelines_impl(bytesio *self, PyObject *lines) } /*[clinic input] +@critical_section _io.BytesIO.close Disable all I/O operations. @@ -766,7 +818,7 @@ Disable all I/O operations. static PyObject * _io_BytesIO_close_impl(bytesio *self) -/*[clinic end generated code: output=1471bb9411af84a0 input=37e1f55556e61f60]*/ +/*[clinic end generated code: output=1471bb9411af84a0 input=34ce76d8bd17a23b]*/ { CHECK_EXPORTS(self); Py_CLEAR(self->buf); @@ -788,35 +840,49 @@ _io_BytesIO_close_impl(bytesio *self) function to use the efficient instance representation of PEP 307. */ + static PyObject * + bytesio_getstate_lock_held(PyObject *op) + { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + + bytesio *self = bytesio_CAST(op); + PyObject *initvalue = _io_BytesIO_getvalue_impl(self); + PyObject *dict; + PyObject *state; + + if (initvalue == NULL) + return NULL; + if (self->dict == NULL) { + dict = Py_NewRef(Py_None); + } + else { + dict = PyDict_Copy(self->dict); + if (dict == NULL) { + Py_DECREF(initvalue); + return NULL; + } + } + + state = Py_BuildValue("(OnN)", initvalue, self->pos, dict); + Py_DECREF(initvalue); + return state; +} + static PyObject * bytesio_getstate(PyObject *op, PyObject *Py_UNUSED(dummy)) { - bytesio *self = bytesio_CAST(op); - PyObject *initvalue = _io_BytesIO_getvalue_impl(self); - PyObject *dict; - PyObject *state; - - if (initvalue == NULL) - return NULL; - if (self->dict == NULL) { - dict = Py_NewRef(Py_None); - } - else { - dict = PyDict_Copy(self->dict); - if (dict == NULL) { - Py_DECREF(initvalue); - return NULL; - } - } - - state = Py_BuildValue("(OnN)", initvalue, self->pos, dict); - Py_DECREF(initvalue); - return state; + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = bytesio_getstate_lock_held(op); + Py_END_CRITICAL_SECTION(); + return ret; } static PyObject * -bytesio_setstate(PyObject *op, PyObject *state) +bytesio_setstate_lock_held(PyObject *op, PyObject *state) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + PyObject *result; PyObject *position_obj; PyObject *dict; @@ -890,13 +956,23 @@ bytesio_setstate(PyObject *op, PyObject *state) Py_RETURN_NONE; } +static PyObject * +bytesio_setstate(PyObject *op, PyObject *state) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = bytesio_setstate_lock_held(op, state); + Py_END_CRITICAL_SECTION(); + return ret; +} + static void bytesio_dealloc(PyObject *op) { bytesio *self = bytesio_CAST(op); PyTypeObject *tp = Py_TYPE(self); _PyObject_GC_UNTRACK(self); - if (self->exports > 0) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) { PyErr_SetString(PyExc_SystemError, "deallocated BytesIO object has exported buffers"); PyErr_Print(); @@ -932,6 +1008,7 @@ bytesio_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } /*[clinic input] +@critical_section _io.BytesIO.__init__ initial_bytes as initvalue: object(c_default="NULL") = b'' @@ -940,13 +1017,13 @@ Buffered I/O implementation using an in-memory bytes buffer. static int _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) -/*[clinic end generated code: output=65c0c51e24c5b621 input=aac7f31b67bf0fb6]*/ +/*[clinic end generated code: output=65c0c51e24c5b621 input=3da5a74ee4c4f1ac]*/ { /* In case, __init__ is called multiple times. */ self->string_size = 0; self->pos = 0; - if (self->exports > 0) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) > 0) { PyErr_SetString(PyExc_BufferError, "Existing exports of data: object cannot be re-sized"); return -1; @@ -970,8 +1047,10 @@ _io_BytesIO___init___impl(bytesio *self, PyObject *initvalue) } static PyObject * -bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) +bytesio_sizeof_lock_held(PyObject *op) { + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(op); + bytesio *self = bytesio_CAST(op); size_t res = _PyObject_SIZE(Py_TYPE(self)); if (self->buf && !SHARED_BUF(self)) { @@ -984,6 +1063,16 @@ bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) return PyLong_FromSize_t(res); } +static PyObject * +bytesio_sizeof(PyObject *op, PyObject *Py_UNUSED(dummy)) +{ + PyObject *ret; + Py_BEGIN_CRITICAL_SECTION(op); + ret = bytesio_sizeof_lock_held(op); + Py_END_CRITICAL_SECTION(); + return ret; +} + static int bytesio_traverse(PyObject *op, visitproc visit, void *arg) { @@ -999,7 +1088,7 @@ bytesio_clear(PyObject *op) { bytesio *self = bytesio_CAST(op); Py_CLEAR(self->dict); - if (self->exports == 0) { + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(self->exports) == 0) { Py_CLEAR(self->buf); } return 0; @@ -1077,18 +1166,15 @@ PyType_Spec bytesio_spec = { */ static int -bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags) +bytesiobuf_getbuffer_lock_held(PyObject *op, Py_buffer *view, int flags) { bytesiobuf *obj = bytesiobuf_CAST(op); bytesio *b = bytesio_CAST(obj->source); - if (view == NULL) { - PyErr_SetString(PyExc_BufferError, - "bytesiobuf_getbuffer: view==NULL argument is obsolete"); - return -1; - } - if (b->exports == 0 && SHARED_BUF(b)) { - if (unshare_buffer(b, b->string_size) < 0) + _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(b); + + if (FT_ATOMIC_LOAD_SSIZE_RELAXED(b->exports) == 0 && SHARED_BUF(b)) { + if (unshare_buffer_lock_held(b, b->string_size) < 0) return -1; } @@ -1096,16 +1182,32 @@ bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags) (void)PyBuffer_FillInfo(view, op, PyBytes_AS_STRING(b->buf), b->string_size, 0, flags); - b->exports++; + FT_ATOMIC_ADD_SSIZE(b->exports, 1); return 0; } +static int +bytesiobuf_getbuffer(PyObject *op, Py_buffer *view, int flags) +{ + if (view == NULL) { + PyErr_SetString(PyExc_BufferError, + "bytesiobuf_getbuffer: view==NULL argument is obsolete"); + return -1; + } + + int ret; + Py_BEGIN_CRITICAL_SECTION(bytesiobuf_CAST(op)->source); + ret = bytesiobuf_getbuffer_lock_held(op, view, flags); + Py_END_CRITICAL_SECTION(); + return ret; +} + static void bytesiobuf_releasebuffer(PyObject *op, Py_buffer *Py_UNUSED(view)) { bytesiobuf *obj = bytesiobuf_CAST(op); bytesio *b = bytesio_CAST(obj->source); - b->exports--; + FT_ATOMIC_ADD_SSIZE(b->exports, -1); } static int diff --git a/Modules/_io/clinic/bytesio.c.h b/Modules/_io/clinic/bytesio.c.h index aaf4884d173..8553ed05f70 100644 --- a/Modules/_io/clinic/bytesio.c.h +++ b/Modules/_io/clinic/bytesio.c.h @@ -7,6 +7,7 @@ preserve # include "pycore_runtime.h" // _Py_ID() #endif #include "pycore_abstract.h" // _Py_convert_optional_to_ssize_t() +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() PyDoc_STRVAR(_io_BytesIO_readable__doc__, @@ -96,11 +97,18 @@ _io_BytesIO_getbuffer_impl(bytesio *self, PyTypeObject *cls); static PyObject * _io_BytesIO_getbuffer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { + PyObject *return_value = NULL; + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { PyErr_SetString(PyExc_TypeError, "getbuffer() takes no arguments"); - return NULL; + goto exit; } - return _io_BytesIO_getbuffer_impl((bytesio *)self, cls); + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO_getbuffer_impl((bytesio *)self, cls); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; } PyDoc_STRVAR(_io_BytesIO_getvalue__doc__, @@ -118,7 +126,13 @@ _io_BytesIO_getvalue_impl(bytesio *self); static PyObject * _io_BytesIO_getvalue(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _io_BytesIO_getvalue_impl((bytesio *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO_getvalue_impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_BytesIO_isatty__doc__, @@ -156,7 +170,13 @@ _io_BytesIO_tell_impl(bytesio *self); static PyObject * _io_BytesIO_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _io_BytesIO_tell_impl((bytesio *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO_tell_impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_BytesIO_read__doc__, @@ -190,7 +210,9 @@ _io_BytesIO_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_read_impl((bytesio *)self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -227,7 +249,9 @@ _io_BytesIO_read1(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_read1_impl((bytesio *)self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -265,7 +289,9 @@ _io_BytesIO_readline(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_readline_impl((bytesio *)self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -301,7 +327,9 @@ _io_BytesIO_readlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } arg = args[0]; skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_readlines_impl((bytesio *)self, arg); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -332,7 +360,9 @@ _io_BytesIO_readinto(PyObject *self, PyObject *arg) _PyArg_BadArgument("readinto", "argument", "read-write bytes-like object", arg); goto exit; } + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_readinto_impl((bytesio *)self, &buffer); + Py_END_CRITICAL_SECTION(); exit: /* Cleanup for buffer */ @@ -356,13 +386,13 @@ PyDoc_STRVAR(_io_BytesIO_truncate__doc__, {"truncate", _PyCFunction_CAST(_io_BytesIO_truncate), METH_FASTCALL, _io_BytesIO_truncate__doc__}, static PyObject * -_io_BytesIO_truncate_impl(bytesio *self, Py_ssize_t size); +_io_BytesIO_truncate_impl(bytesio *self, PyObject *size); static PyObject * _io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - Py_ssize_t size = ((bytesio *)self)->pos; + PyObject *size = Py_None; if (!_PyArg_CheckPositional("truncate", nargs, 0, 1)) { goto exit; @@ -370,11 +400,11 @@ _io_BytesIO_truncate(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (nargs < 1) { goto skip_optional; } - if (!_Py_convert_optional_to_ssize_t(args[0], &size)) { - goto exit; - } + size = args[0]; skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_truncate_impl((bytesio *)self, size); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -428,7 +458,9 @@ _io_BytesIO_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) goto exit; } skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_seek_impl((bytesio *)self, pos, whence); + Py_END_CRITICAL_SECTION(); exit: return return_value; @@ -453,7 +485,9 @@ _io_BytesIO_write(PyObject *self, PyObject *b) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_write_impl((bytesio *)self, b); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -479,7 +513,9 @@ _io_BytesIO_writelines(PyObject *self, PyObject *lines) { PyObject *return_value = NULL; + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO_writelines_impl((bytesio *)self, lines); + Py_END_CRITICAL_SECTION(); return return_value; } @@ -499,7 +535,13 @@ _io_BytesIO_close_impl(bytesio *self); static PyObject * _io_BytesIO_close(PyObject *self, PyObject *Py_UNUSED(ignored)) { - return _io_BytesIO_close_impl((bytesio *)self); + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = _io_BytesIO_close_impl((bytesio *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; } PyDoc_STRVAR(_io_BytesIO___init____doc__, @@ -558,9 +600,11 @@ _io_BytesIO___init__(PyObject *self, PyObject *args, PyObject *kwargs) } initvalue = fastargs[0]; skip_optional_pos: + Py_BEGIN_CRITICAL_SECTION(self); return_value = _io_BytesIO___init___impl((bytesio *)self, initvalue); + Py_END_CRITICAL_SECTION(); exit: return return_value; } -/*[clinic end generated code: output=6dbfd82f4e9d4ef3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=580205daa01def2e input=a9049054013a1b77]*/ diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index f9b4c2a170e..462c2181fa6 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -17,6 +17,7 @@ #include <lzma.h> +#include "pycore_long.h" // _PyLong_UInt32_Converter() // Blocks output buffer wrappers #include "pycore_blocks_output_buffer.h" @@ -223,8 +224,6 @@ FUNCNAME(PyObject *obj, void *ptr) \ return 1; \ } -INT_TYPE_CONVERTER_FUNC(uint32_t, uint32_converter) -INT_TYPE_CONVERTER_FUNC(uint64_t, uint64_converter) INT_TYPE_CONVERTER_FUNC(lzma_vli, lzma_vli_converter) INT_TYPE_CONVERTER_FUNC(lzma_mode, lzma_mode_converter) INT_TYPE_CONVERTER_FUNC(lzma_match_finder, lzma_mf_converter) @@ -254,7 +253,7 @@ parse_filter_spec_lzma(_lzma_state *state, PyObject *spec) return NULL; } if (preset_obj != NULL) { - int ok = uint32_converter(preset_obj, &preset); + int ok = _PyLong_UInt32_Converter(preset_obj, &preset); Py_DECREF(preset_obj); if (!ok) { return NULL; @@ -275,14 +274,14 @@ parse_filter_spec_lzma(_lzma_state *state, PyObject *spec) if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OOO&O&O&O&O&O&O&O&", optnames, &id, &preset_obj, - uint32_converter, &options->dict_size, - uint32_converter, &options->lc, - uint32_converter, &options->lp, - uint32_converter, &options->pb, + _PyLong_UInt32_Converter, &options->dict_size, + _PyLong_UInt32_Converter, &options->lc, + _PyLong_UInt32_Converter, &options->lp, + _PyLong_UInt32_Converter, &options->pb, lzma_mode_converter, &options->mode, - uint32_converter, &options->nice_len, + _PyLong_UInt32_Converter, &options->nice_len, lzma_mf_converter, &options->mf, - uint32_converter, &options->depth)) { + _PyLong_UInt32_Converter, &options->depth)) { PyErr_SetString(PyExc_ValueError, "Invalid filter specifier for LZMA filter"); PyMem_Free(options); @@ -301,7 +300,7 @@ parse_filter_spec_delta(_lzma_state *state, PyObject *spec) lzma_options_delta *options; if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames, - &id, uint32_converter, &dist)) { + &id, _PyLong_UInt32_Converter, &dist)) { PyErr_SetString(PyExc_ValueError, "Invalid filter specifier for delta filter"); return NULL; @@ -325,7 +324,7 @@ parse_filter_spec_bcj(_lzma_state *state, PyObject *spec) lzma_options_bcj *options; if (!PyArg_ParseTupleAndKeywords(state->empty_tuple, spec, "|OO&", optnames, - &id, uint32_converter, &start_offset)) { + &id, _PyLong_UInt32_Converter, &start_offset)) { PyErr_SetString(PyExc_ValueError, "Invalid filter specifier for BCJ filter"); return NULL; @@ -806,7 +805,7 @@ Compressor_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) return NULL; } - if (preset_obj != Py_None && !uint32_converter(preset_obj, &preset)) { + if (preset_obj != Py_None && !_PyLong_UInt32_Converter(preset_obj, &preset)) { return NULL; } @@ -1226,7 +1225,7 @@ _lzma_LZMADecompressor_impl(PyTypeObject *type, int format, "Cannot specify memory limit with FORMAT_RAW"); return NULL; } - if (!uint64_converter(memlimit, &memlimit_)) { + if (!_PyLong_UInt64_Converter(memlimit, &memlimit_)) { return NULL; } } diff --git a/Modules/_sqlite/clinic/_sqlite3.connect.c.h b/Modules/_sqlite/clinic/_sqlite3.connect.c.h index 1bcda7702c2..e9d560666c1 100644 --- a/Modules/_sqlite/clinic/_sqlite3.connect.c.h +++ b/Modules/_sqlite/clinic/_sqlite3.connect.c.h @@ -9,23 +9,17 @@ preserve #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(pysqlite_connect__doc__, -"connect($module, /, database, timeout=5.0, detect_types=0,\n" +"connect($module, /, database, *, timeout=5.0, detect_types=0,\n" " isolation_level=\'\', check_same_thread=True,\n" -" factory=ConnectionType, cached_statements=128, uri=False, *,\n" +" factory=ConnectionType, cached_statements=128, uri=False,\n" " autocommit=sqlite3.LEGACY_TRANSACTION_CONTROL)\n" "--\n" "\n" "Open a connection to the SQLite database file \'database\'.\n" "\n" "You can use \":memory:\" to open a database connection to a database that\n" -"resides in RAM instead of on disk.\n" -"\n" -"Note: Passing more than 1 positional argument to _sqlite3.connect() is\n" -"deprecated. Parameters \'timeout\', \'detect_types\', \'isolation_level\',\n" -"\'check_same_thread\', \'factory\', \'cached_statements\' and \'uri\' will\n" -"become keyword-only parameters in Python 3.15.\n" -""); +"resides in RAM instead of on disk."); #define PYSQLITE_CONNECT_METHODDEF \ {"connect", _PyCFunction_CAST(pysqlite_connect), METH_FASTCALL|METH_KEYWORDS, pysqlite_connect__doc__}, -/*[clinic end generated code: output=69b9b00da71c3c0a input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3d83139ba65e0bb5 input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/clinic/connection.c.h b/Modules/_sqlite/clinic/connection.c.h index c8e1d0b7a73..f0e9fdb8894 100644 --- a/Modules/_sqlite/clinic/connection.c.h +++ b/Modules/_sqlite/clinic/connection.c.h @@ -16,17 +16,6 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, int cache_size, int uri, enum autocommit_mode autocommit); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.__init__'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.__init__'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.__init__'." -# endif -#endif - static int pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -72,25 +61,14 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) int uri = 0; enum autocommit_mode autocommit = LEGACY_TRANSACTION_CONTROL; - if (nargs > 1 && nargs <= 8) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing more than 1 positional argument to _sqlite3.Connection()" - " is deprecated. Parameters 'timeout', 'detect_types', " - "'isolation_level', 'check_same_thread', 'factory', " - "'cached_statements' and 'uri' will become keyword-only " - "parameters in Python 3.15.", 1)) - { - goto exit; - } - } fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, - /*minpos*/ 1, /*maxpos*/ 8, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); if (!fastargs) { goto exit; } database = fastargs[0]; if (!noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } if (fastargs[1]) { if (PyFloat_CheckExact(fastargs[1])) { @@ -104,7 +82,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) } } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[2]) { @@ -113,7 +91,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[3]) { @@ -121,7 +99,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[4]) { @@ -130,13 +108,13 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[5]) { factory = fastargs[5]; if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[6]) { @@ -145,7 +123,7 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } if (fastargs[7]) { @@ -154,13 +132,9 @@ pysqlite_connection_init(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; } if (!--noptargs) { - goto skip_optional_pos; + goto skip_optional_kwonly; } } -skip_optional_pos: - if (!noptargs) { - goto skip_optional_kwonly; - } if (!autocommit_converter(fastargs[8], &autocommit)) { goto exit; } @@ -424,15 +398,10 @@ pysqlite_connection_rollback(PyObject *self, PyObject *Py_UNUSED(ignored)) } PyDoc_STRVAR(pysqlite_connection_create_function__doc__, -"create_function($self, /, name, narg, func, *, deterministic=False)\n" +"create_function($self, name, narg, func, /, *, deterministic=False)\n" "--\n" "\n" -"Creates a new function.\n" -"\n" -"Note: Passing keyword arguments \'name\', \'narg\' and \'func\' to\n" -"_sqlite3.Connection.create_function() is deprecated. Parameters\n" -"\'name\', \'narg\' and \'func\' will become positional-only in Python 3.15.\n" -""); +"Creates a new function."); #define PYSQLITE_CONNECTION_CREATE_FUNCTION_METHODDEF \ {"create_function", _PyCFunction_CAST(pysqlite_connection_create_function), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_function__doc__}, @@ -443,24 +412,13 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self, int narg, PyObject *func, int deterministic); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.create_function'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.create_function'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.create_function'." -# endif -#endif - static PyObject * pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 4 + #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -469,7 +427,7 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(name), &_Py_ID(narg), &_Py_ID(func), &_Py_ID(deterministic), }, + .ob_item = { &_Py_ID(deterministic), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -478,7 +436,7 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"name", "narg", "func", "deterministic", NULL}; + static const char * const _keywords[] = {"", "", "", "deterministic", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "create_function", @@ -497,18 +455,8 @@ pysqlite_connection_create_function(PyObject *self, PyTypeObject *cls, PyObject if (!args) { goto exit; } - if (nargs < 3) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing keyword arguments 'name', 'narg' and 'func' to " - "_sqlite3.Connection.create_function() is deprecated. Parameters " - "'name', 'narg' and 'func' will become positional-only in Python " - "3.15.", 1)) - { - goto exit; - } - } if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("create_function", "argument 'name'", "str", args[0]); + _PyArg_BadArgument("create_function", "argument 1", "str", args[0]); goto exit; } Py_ssize_t name_length; @@ -618,16 +566,10 @@ exit: #endif /* defined(HAVE_WINDOW_FUNCTIONS) */ PyDoc_STRVAR(pysqlite_connection_create_aggregate__doc__, -"create_aggregate($self, /, name, n_arg, aggregate_class)\n" +"create_aggregate($self, name, n_arg, aggregate_class, /)\n" "--\n" "\n" -"Creates a new aggregate.\n" -"\n" -"Note: Passing keyword arguments \'name\', \'n_arg\' and \'aggregate_class\'\n" -"to _sqlite3.Connection.create_aggregate() is deprecated. Parameters\n" -"\'name\', \'n_arg\' and \'aggregate_class\' will become positional-only in\n" -"Python 3.15.\n" -""); +"Creates a new aggregate."); #define PYSQLITE_CONNECTION_CREATE_AGGREGATE_METHODDEF \ {"create_aggregate", _PyCFunction_CAST(pysqlite_connection_create_aggregate), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_create_aggregate__doc__}, @@ -638,42 +580,17 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self, const char *name, int n_arg, PyObject *aggregate_class); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.create_aggregate'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.create_aggregate'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.create_aggregate'." -# endif -#endif - static PyObject * pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 3 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(name), &_Py_ID(n_arg), &_Py_ID(aggregate_class), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else # define KWTUPLE NULL - #endif // !Py_BUILD_CORE + #endif - static const char * const _keywords[] = {"name", "n_arg", "aggregate_class", NULL}; + static const char * const _keywords[] = {"", "", "", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "create_aggregate", @@ -690,18 +607,8 @@ pysqlite_connection_create_aggregate(PyObject *self, PyTypeObject *cls, PyObject if (!args) { goto exit; } - if (nargs < 3) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing keyword arguments 'name', 'n_arg' and 'aggregate_class' " - "to _sqlite3.Connection.create_aggregate() is deprecated. " - "Parameters 'name', 'n_arg' and 'aggregate_class' will become " - "positional-only in Python 3.15.", 1)) - { - goto exit; - } - } if (!PyUnicode_Check(args[0])) { - _PyArg_BadArgument("create_aggregate", "argument 'name'", "str", args[0]); + _PyArg_BadArgument("create_aggregate", "argument 1", "str", args[0]); goto exit; } Py_ssize_t name_length; @@ -725,15 +632,10 @@ exit: } PyDoc_STRVAR(pysqlite_connection_set_authorizer__doc__, -"set_authorizer($self, /, authorizer_callback)\n" +"set_authorizer($self, authorizer_callback, /)\n" "--\n" "\n" -"Set authorizer callback.\n" -"\n" -"Note: Passing keyword argument \'authorizer_callback\' to\n" -"_sqlite3.Connection.set_authorizer() is deprecated. Parameter\n" -"\'authorizer_callback\' will become positional-only in Python 3.15.\n" -""); +"Set authorizer callback."); #define PYSQLITE_CONNECTION_SET_AUTHORIZER_METHODDEF \ {"set_authorizer", _PyCFunction_CAST(pysqlite_connection_set_authorizer), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_authorizer__doc__}, @@ -743,42 +645,17 @@ pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.set_authorizer'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.set_authorizer'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.set_authorizer'." -# endif -#endif - static PyObject * pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(authorizer_callback), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else # define KWTUPLE NULL - #endif // !Py_BUILD_CORE + #endif - static const char * const _keywords[] = {"authorizer_callback", NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "set_authorizer", @@ -793,16 +670,6 @@ pysqlite_connection_set_authorizer(PyObject *self, PyTypeObject *cls, PyObject * if (!args) { goto exit; } - if (nargs < 1) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing keyword argument 'authorizer_callback' to " - "_sqlite3.Connection.set_authorizer() is deprecated. Parameter " - "'authorizer_callback' will become positional-only in Python " - "3.15.", 1)) - { - goto exit; - } - } callable = args[0]; return_value = pysqlite_connection_set_authorizer_impl((pysqlite_Connection *)self, cls, callable); @@ -811,7 +678,7 @@ exit: } PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__, -"set_progress_handler($self, /, progress_handler, n)\n" +"set_progress_handler($self, progress_handler, /, n)\n" "--\n" "\n" "Set progress handler callback.\n" @@ -824,12 +691,7 @@ PyDoc_STRVAR(pysqlite_connection_set_progress_handler__doc__, " The number of SQLite virtual machine instructions that are\n" " executed between invocations of \'progress_handler\'.\n" "\n" -"If \'progress_handler\' is None or \'n\' is 0, the progress handler is disabled.\n" -"\n" -"Note: Passing keyword argument \'progress_handler\' to\n" -"_sqlite3.Connection.set_progress_handler() is deprecated. Parameter\n" -"\'progress_handler\' will become positional-only in Python 3.15.\n" -""); +"If \'progress_handler\' is None or \'n\' is 0, the progress handler is disabled."); #define PYSQLITE_CONNECTION_SET_PROGRESS_HANDLER_METHODDEF \ {"set_progress_handler", _PyCFunction_CAST(pysqlite_connection_set_progress_handler), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_progress_handler__doc__}, @@ -839,24 +701,13 @@ pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable, int n); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.set_progress_handler'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.set_progress_handler'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.set_progress_handler'." -# endif -#endif - static PyObject * pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - #define NUM_KEYWORDS 2 + #define NUM_KEYWORDS 1 static struct { PyGC_Head _this_is_not_used; PyObject_VAR_HEAD @@ -865,7 +716,7 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb } _kwtuple = { .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) .ob_hash = -1, - .ob_item = { &_Py_ID(progress_handler), _Py_LATIN1_CHR('n'), }, + .ob_item = { _Py_LATIN1_CHR('n'), }, }; #undef NUM_KEYWORDS #define KWTUPLE (&_kwtuple.ob_base.ob_base) @@ -874,7 +725,7 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb # define KWTUPLE NULL #endif // !Py_BUILD_CORE - static const char * const _keywords[] = {"progress_handler", "n", NULL}; + static const char * const _keywords[] = {"", "n", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "set_progress_handler", @@ -890,16 +741,6 @@ pysqlite_connection_set_progress_handler(PyObject *self, PyTypeObject *cls, PyOb if (!args) { goto exit; } - if (nargs < 1) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing keyword argument 'progress_handler' to " - "_sqlite3.Connection.set_progress_handler() is deprecated. " - "Parameter 'progress_handler' will become positional-only in " - "Python 3.15.", 1)) - { - goto exit; - } - } callable = args[0]; n = PyLong_AsInt(args[1]); if (n == -1 && PyErr_Occurred()) { @@ -912,15 +753,10 @@ exit: } PyDoc_STRVAR(pysqlite_connection_set_trace_callback__doc__, -"set_trace_callback($self, /, trace_callback)\n" +"set_trace_callback($self, trace_callback, /)\n" "--\n" "\n" -"Set a trace callback called for each SQL statement (passed as unicode).\n" -"\n" -"Note: Passing keyword argument \'trace_callback\' to\n" -"_sqlite3.Connection.set_trace_callback() is deprecated. Parameter\n" -"\'trace_callback\' will become positional-only in Python 3.15.\n" -""); +"Set a trace callback called for each SQL statement (passed as unicode)."); #define PYSQLITE_CONNECTION_SET_TRACE_CALLBACK_METHODDEF \ {"set_trace_callback", _PyCFunction_CAST(pysqlite_connection_set_trace_callback), METH_METHOD|METH_FASTCALL|METH_KEYWORDS, pysqlite_connection_set_trace_callback__doc__}, @@ -930,42 +766,17 @@ pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable); -// Emit compiler warnings when we get to Python 3.15. -#if PY_VERSION_HEX >= 0x030f00C0 -# error "Update the clinic input of '_sqlite3.Connection.set_trace_callback'." -#elif PY_VERSION_HEX >= 0x030f00A0 -# ifdef _MSC_VER -# pragma message ("Update the clinic input of '_sqlite3.Connection.set_trace_callback'.") -# else -# warning "Update the clinic input of '_sqlite3.Connection.set_trace_callback'." -# endif -#endif - static PyObject * pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) - - #define NUM_KEYWORDS 1 - static struct { - PyGC_Head _this_is_not_used; - PyObject_VAR_HEAD - Py_hash_t ob_hash; - PyObject *ob_item[NUM_KEYWORDS]; - } _kwtuple = { - .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) - .ob_hash = -1, - .ob_item = { &_Py_ID(trace_callback), }, - }; - #undef NUM_KEYWORDS - #define KWTUPLE (&_kwtuple.ob_base.ob_base) - - #else // !Py_BUILD_CORE + # define KWTUPLE (PyObject *)&_Py_SINGLETON(tuple_empty) + #else # define KWTUPLE NULL - #endif // !Py_BUILD_CORE + #endif - static const char * const _keywords[] = {"trace_callback", NULL}; + static const char * const _keywords[] = {"", NULL}; static _PyArg_Parser _parser = { .keywords = _keywords, .fname = "set_trace_callback", @@ -980,16 +791,6 @@ pysqlite_connection_set_trace_callback(PyObject *self, PyTypeObject *cls, PyObje if (!args) { goto exit; } - if (nargs < 1) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing keyword argument 'trace_callback' to " - "_sqlite3.Connection.set_trace_callback() is deprecated. " - "Parameter 'trace_callback' will become positional-only in Python" - " 3.15.", 1)) - { - goto exit; - } - } callable = args[0]; return_value = pysqlite_connection_set_trace_callback_impl((pysqlite_Connection *)self, cls, callable); @@ -1921,4 +1722,4 @@ exit: #ifndef DESERIALIZE_METHODDEF #define DESERIALIZE_METHODDEF #endif /* !defined(DESERIALIZE_METHODDEF) */ -/*[clinic end generated code: output=2f325c2444b4bb47 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6cb96e557133d553 input=a9049054013a1b77]*/ diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 2a184f78754..16ec6efc850 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -215,7 +215,7 @@ class sqlite3_int64_converter(CConverter): _sqlite3.Connection.__init__ as pysqlite_connection_init database: object - * [from 3.15] + * timeout: double = 5.0 detect_types: int = 0 isolation_level: IsolationLevel = "" @@ -223,7 +223,6 @@ _sqlite3.Connection.__init__ as pysqlite_connection_init factory: object(c_default='(PyObject*)clinic_state()->ConnectionType') = ConnectionType cached_statements as cache_size: int = 128 uri: bool = False - * autocommit: Autocommit(c_default='LEGACY_TRANSACTION_CONTROL') = sqlite3.LEGACY_TRANSACTION_CONTROL [clinic start generated code]*/ @@ -234,7 +233,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database, int check_same_thread, PyObject *factory, int cache_size, int uri, enum autocommit_mode autocommit) -/*[clinic end generated code: output=cba057313ea7712f input=219c3dbecbae7d99]*/ +/*[clinic end generated code: output=cba057313ea7712f input=5ca4883d8747a49b]*/ { if (PySys_Audit("sqlite3.connect", "O", database) < 0) { return -1; @@ -1158,11 +1157,10 @@ check_num_params(pysqlite_Connection *self, const int n, const char *name) _sqlite3.Connection.create_function as pysqlite_connection_create_function cls: defining_class - / name: str narg: int func: object - / [from 3.15] + / * deterministic: bool = False @@ -1174,7 +1172,7 @@ pysqlite_connection_create_function_impl(pysqlite_Connection *self, PyTypeObject *cls, const char *name, int narg, PyObject *func, int deterministic) -/*[clinic end generated code: output=8a811529287ad240 input=c7c313b0ca8b519e]*/ +/*[clinic end generated code: output=8a811529287ad240 input=a896096ed5390ae1]*/ { int rc; int flags = SQLITE_UTF8; @@ -1366,11 +1364,10 @@ create_window_function_impl(pysqlite_Connection *self, PyTypeObject *cls, _sqlite3.Connection.create_aggregate as pysqlite_connection_create_aggregate cls: defining_class - / name: str n_arg: int aggregate_class: object - / [from 3.15] + / Creates a new aggregate. [clinic start generated code]*/ @@ -1380,7 +1377,7 @@ pysqlite_connection_create_aggregate_impl(pysqlite_Connection *self, PyTypeObject *cls, const char *name, int n_arg, PyObject *aggregate_class) -/*[clinic end generated code: output=1b02d0f0aec7ff96 input=8087056db6eae1cf]*/ +/*[clinic end generated code: output=1b02d0f0aec7ff96 input=aa2773f6a42f7e17]*/ { int rc; @@ -1531,7 +1528,7 @@ _sqlite3.Connection.set_authorizer as pysqlite_connection_set_authorizer cls: defining_class authorizer_callback as callable: object - / [from 3.15] + / Set authorizer callback. [clinic start generated code]*/ @@ -1540,7 +1537,7 @@ static PyObject * pysqlite_connection_set_authorizer_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable) -/*[clinic end generated code: output=75fa60114fc971c3 input=a52bd4937c588752]*/ +/*[clinic end generated code: output=75fa60114fc971c3 input=e76469ab0bb1bbcd]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1576,7 +1573,7 @@ _sqlite3.Connection.set_progress_handler as pysqlite_connection_set_progress_han A callable that takes no arguments. If the callable returns non-zero, the current query is terminated, and an exception is raised. - / [from 3.15] + / n: int The number of SQLite virtual machine instructions that are executed between invocations of 'progress_handler'. @@ -1590,7 +1587,7 @@ static PyObject * pysqlite_connection_set_progress_handler_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable, int n) -/*[clinic end generated code: output=0739957fd8034a50 input=b4d6e2ef8b4d32f9]*/ +/*[clinic end generated code: output=0739957fd8034a50 input=74c943f1ae7d8880]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; @@ -1617,7 +1614,7 @@ _sqlite3.Connection.set_trace_callback as pysqlite_connection_set_trace_callback cls: defining_class trace_callback as callable: object - / [from 3.15] + / Set a trace callback called for each SQL statement (passed as unicode). [clinic start generated code]*/ @@ -1626,7 +1623,7 @@ static PyObject * pysqlite_connection_set_trace_callback_impl(pysqlite_Connection *self, PyTypeObject *cls, PyObject *callable) -/*[clinic end generated code: output=d91048c03bfcee05 input=d705d592ec03cf28]*/ +/*[clinic end generated code: output=d91048c03bfcee05 input=f4f59bf2f87f2026]*/ { if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { return NULL; diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index 27e8dab92e0..909ddd1f990 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -60,26 +60,16 @@ pysqlite_connect(PyObject *module, PyObject *const *args, Py_ssize_t nargsf, pysqlite_state *state = pysqlite_get_state(module); PyObject *factory = (PyObject *)state->ConnectionType; - static const int FACTORY_POS = 5; Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); - if (nargs > 1 && nargs <= 8) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Passing more than 1 positional argument to sqlite3.connect()" - " is deprecated. Parameters 'timeout', 'detect_types', " - "'isolation_level', 'check_same_thread', 'factory', " - "'cached_statements' and 'uri' will become keyword-only " - "parameters in Python 3.15.", 1)) - { - return NULL; - } - } - if (nargs > FACTORY_POS) { - factory = args[FACTORY_POS]; + if (nargs > 1) { + PyErr_Format(PyExc_TypeError, + "connect() takes at most 1 positional arguments (%zd given)", nargs); + return NULL; } - else if (kwnames != NULL) { + if (kwnames != NULL) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) { PyObject *item = PyTuple_GET_ITEM(kwnames, i); // borrowed ref. - if (PyUnicode_CompareWithASCIIString(item, "factory") == 0) { + if (PyUnicode_EqualToUTF8(item, "factory")) { factory = args[nargs + i]; break; } diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 97a29f4d0e1..1b26f503e73 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -4427,7 +4427,7 @@ _ssl__SSLContext_load_dh_params_impl(PySSLContext *self, PyObject *filepath) FILE *f; DH *dh; -#if defined(MS_WINDOWS) && defined(_DEBUG) +#if defined(MS_WINDOWS) && defined(Py_DEBUG) PyErr_SetString(PyExc_NotImplementedError, "load_dh_params: unavailable on Windows debug build"); return NULL; diff --git a/Modules/_ssl/debughelpers.c b/Modules/_ssl/debughelpers.c index 7c0b4876f43..f0a0a1674f3 100644 --- a/Modules/_ssl/debughelpers.c +++ b/Modules/_ssl/debughelpers.c @@ -175,7 +175,7 @@ _PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg, PySSLContext *self = PySSLContext_CAST(op); FILE *fp; -#if defined(MS_WINDOWS) && defined(_DEBUG) +#if defined(MS_WINDOWS) && defined(Py_DEBUG) PyErr_SetString(PyExc_NotImplementedError, "set_keylog_filename: unavailable on Windows debug build"); return -1; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index ae060c95fd5..3030f45d72c 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1165,6 +1165,47 @@ error: return NULL; } +static PyObject * +verify_stateless_code(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *codearg; + PyObject *globalnames = NULL; + PyObject *globalsns = NULL; + PyObject *builtinsns = NULL; + static char *kwlist[] = {"code", "globalnames", + "globalsns", "builtinsns", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O|O!O!O!:get_code_var_counts", kwlist, + &codearg, &PySet_Type, &globalnames, + &PyDict_Type, &globalsns, &PyDict_Type, &builtinsns)) + { + return NULL; + } + if (PyFunction_Check(codearg)) { + if (globalsns == NULL) { + globalsns = PyFunction_GET_GLOBALS(codearg); + } + if (builtinsns == NULL) { + builtinsns = PyFunction_GET_BUILTINS(codearg); + } + codearg = PyFunction_GET_CODE(codearg); + } + else if (!PyCode_Check(codearg)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a code object or a function"); + return NULL; + } + PyCodeObject *code = (PyCodeObject *)codearg; + + if (_PyCode_VerifyStateless( + tstate, code, globalnames, globalsns, builtinsns) < 0) + { + return NULL; + } + Py_RETURN_NONE; +} + #ifdef _Py_TIER2 static PyObject * @@ -1948,6 +1989,16 @@ get_crossinterp_data(PyObject *self, PyObject *args, PyObject *kwargs) goto error; } } + else if (strcmp(mode, "script") == 0) { + if (_PyCode_GetScriptXIData(tstate, obj, xidata) != 0) { + goto error; + } + } + else if (strcmp(mode, "script-pure") == 0) { + if (_PyCode_GetPureScriptXIData(tstate, obj, xidata) != 0) { + goto error; + } + } else { PyErr_Format(PyExc_ValueError, "unsupported mode %R", modeobj); goto error; @@ -2292,6 +2343,8 @@ static PyMethodDef module_functions[] = { {"get_co_localskinds", get_co_localskinds, METH_O, NULL}, {"get_code_var_counts", _PyCFunction_CAST(get_code_var_counts), METH_VARARGS | METH_KEYWORDS, NULL}, + {"verify_stateless_code", _PyCFunction_CAST(verify_stateless_code), + METH_VARARGS | METH_KEYWORDS, NULL}, #ifdef _Py_TIER2 {"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL}, {"invalidate_executors", invalidate_executors, METH_O, NULL}, diff --git a/Modules/_testlimitedcapi/import.c b/Modules/_testlimitedcapi/import.c index 3707dbedeea..f85daee57d7 100644 --- a/Modules/_testlimitedcapi/import.c +++ b/Modules/_testlimitedcapi/import.c @@ -108,20 +108,19 @@ pyimport_importmodule(PyObject *Py_UNUSED(module), PyObject *args) } -/* Test PyImport_ImportModuleNoBlock() */ +/* Test PyImport_ImportModuleNoBlock() (removed in 3.15) */ static PyObject * pyimport_importmodulenoblock(PyObject *Py_UNUSED(module), PyObject *args) { + // Get the function from the stable ABI. + PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock(const char *name); + const char *name; Py_ssize_t size; if (!PyArg_ParseTuple(args, "z#", &name, &size)) { return NULL; } - - _Py_COMP_DIAG_PUSH - _Py_COMP_DIAG_IGNORE_DEPR_DECLS return PyImport_ImportModuleNoBlock(name); - _Py_COMP_DIAG_POP } diff --git a/Modules/_zstd/_zstdmodule.c b/Modules/_zstd/_zstdmodule.c index 4d046859a15..4b14315462b 100644 --- a/Modules/_zstd/_zstdmodule.c +++ b/Modules/_zstd/_zstdmodule.c @@ -826,7 +826,7 @@ static int _zstd_exec(PyObject *module) { // ZstdDecompressor if (add_type_to_module(module, "ZstdDecompressor", - &ZstdDecompressor_type_spec, + &zstddecompressor_type_spec, &mod_state->ZstdDecompressor_type) < 0) { return -1; } @@ -890,9 +890,9 @@ _zstd_free(void *module) static struct PyModuleDef_Slot _zstd_slots[] = { {Py_mod_exec, _zstd_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {Py_mod_gil, Py_MOD_GIL_NOT_USED}, - - {0} + {0, NULL}, }; struct PyModuleDef _zstdmodule = { diff --git a/Modules/_zstd/_zstdmodule.h b/Modules/_zstd/_zstdmodule.h index 9322ee259c5..120fe9f84c7 100644 --- a/Modules/_zstd/_zstdmodule.h +++ b/Modules/_zstd/_zstdmodule.h @@ -32,7 +32,7 @@ get_zstd_state_from_type(PyTypeObject *type) { extern PyType_Spec zstddict_type_spec; extern PyType_Spec zstdcompressor_type_spec; -extern PyType_Spec ZstdDecompressor_type_spec; +extern PyType_Spec zstddecompressor_type_spec; struct _zstd_state { PyObject *empty_bytes; @@ -172,19 +172,6 @@ set_parameter_error(const _zstd_state* const state, int is_compress, static const char init_twice_msg[] = "__init__ method is called twice."; -extern int -_PyZstd_load_c_dict(ZstdCompressor *self, PyObject *dict); - -extern int -_PyZstd_load_d_dict(ZstdDecompressor *self, PyObject *dict); - -extern int -_PyZstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options, - const char *arg_name, const char *arg_type); - -extern int -_PyZstd_set_d_parameters(ZstdDecompressor *self, PyObject *options); - extern PyObject * decompress_impl(ZstdDecompressor *self, ZSTD_inBuffer *in, Py_ssize_t max_length, diff --git a/Modules/_zstd/compressor.c b/Modules/_zstd/compressor.c index b735981e747..fc1d3b9d210 100644 --- a/Modules/_zstd/compressor.c +++ b/Modules/_zstd/compressor.c @@ -25,9 +25,9 @@ class _zstd.ZstdCompressor "ZstdCompressor *" "clinic_state()->ZstdCompressor_ty #define ZstdCompressor_CAST(op) ((ZstdCompressor *)op) -int -_PyZstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options, - const char *arg_name, const char* arg_type) +static int +_zstd_set_c_parameters(ZstdCompressor *self, PyObject *level_or_options, + const char *arg_name, const char* arg_type) { size_t zstd_ret; _zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self)); @@ -197,8 +197,8 @@ success: return cdict; } -int -_PyZstd_load_c_dict(ZstdCompressor *self, PyObject *dict) { +static int +_zstd_load_c_dict(ZstdCompressor *self, PyObject *dict) { size_t zstd_ret; _zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self)); @@ -385,20 +385,20 @@ _zstd_ZstdCompressor___init___impl(ZstdCompressor *self, PyObject *level, /* Set compressLevel/options to compression context */ if (level != Py_None) { - if (_PyZstd_set_c_parameters(self, level, "level", "int") < 0) { + if (_zstd_set_c_parameters(self, level, "level", "int") < 0) { return -1; } } if (options != Py_None) { - if (_PyZstd_set_c_parameters(self, options, "options", "dict") < 0) { + if (_zstd_set_c_parameters(self, options, "options", "dict") < 0) { return -1; } } /* Load dictionary to compression context */ if (zstd_dict != Py_None) { - if (_PyZstd_load_c_dict(self, zstd_dict) < 0) { + if (_zstd_load_c_dict(self, zstd_dict) < 0) { return -1; } @@ -702,6 +702,6 @@ static PyType_Slot zstdcompressor_slots[] = { PyType_Spec zstdcompressor_type_spec = { .name = "_zstd.ZstdCompressor", .basicsize = sizeof(ZstdCompressor), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .slots = zstdcompressor_slots, }; diff --git a/Modules/_zstd/decompressor.c b/Modules/_zstd/decompressor.c index a4be180c008..4ac28d9c987 100644 --- a/Modules/_zstd/decompressor.c +++ b/Modules/_zstd/decompressor.c @@ -61,8 +61,8 @@ _get_DDict(ZstdDict *self) } /* Set decompression parameters to decompression context */ -int -_PyZstd_set_d_parameters(ZstdDecompressor *self, PyObject *options) +static int +_zstd_set_d_parameters(ZstdDecompressor *self, PyObject *options) { size_t zstd_ret; PyObject *key, *value; @@ -120,8 +120,8 @@ _PyZstd_set_d_parameters(ZstdDecompressor *self, PyObject *options) } /* Load dictionary or prefix to decompression context */ -int -_PyZstd_load_d_dict(ZstdDecompressor *self, PyObject *dict) +static int +_zstd_load_d_dict(ZstdDecompressor *self, PyObject *dict) { size_t zstd_ret; _zstd_state* const mod_state = PyType_GetModuleState(Py_TYPE(self)); @@ -709,7 +709,7 @@ _zstd_ZstdDecompressor___init___impl(ZstdDecompressor *self, /* Load dictionary to decompression context */ if (zstd_dict != Py_None) { - if (_PyZstd_load_d_dict(self, zstd_dict) < 0) { + if (_zstd_load_d_dict(self, zstd_dict) < 0) { return -1; } @@ -720,7 +720,7 @@ _zstd_ZstdDecompressor___init___impl(ZstdDecompressor *self, /* Set option to decompression context */ if (options != Py_None) { - if (_PyZstd_set_d_parameters(self, options) < 0) { + if (_zstd_set_d_parameters(self, options) < 0) { return -1; } } @@ -883,9 +883,9 @@ static PyType_Slot ZstdDecompressor_slots[] = { {0} }; -PyType_Spec ZstdDecompressor_type_spec = { +PyType_Spec zstddecompressor_type_spec = { .name = "_zstd.ZstdDecompressor", .basicsize = sizeof(ZstdDecompressor), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .slots = ZstdDecompressor_slots, }; diff --git a/Modules/_zstd/zstddict.c b/Modules/_zstd/zstddict.c index a19224c4a64..53c96b10410 100644 --- a/Modules/_zstd/zstddict.c +++ b/Modules/_zstd/zstddict.c @@ -281,6 +281,6 @@ static PyType_Slot zstddict_slots[] = { PyType_Spec zstddict_type_spec = { .name = "_zstd.ZstdDict", .basicsize = sizeof(ZstdDict), - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .slots = zstddict_slots, }; diff --git a/Modules/clinic/socketmodule.c.h b/Modules/clinic/socketmodule.c.h index 70ebbaa876b..573903be87e 100644 --- a/Modules/clinic/socketmodule.c.h +++ b/Modules/clinic/socketmodule.c.h @@ -6,6 +6,7 @@ preserve # include "pycore_gc.h" // PyGC_Head # include "pycore_runtime.h" // _Py_ID() #endif +#include "pycore_long.h" // _PyLong_UInt16_Converter() #include "pycore_modsupport.h" // _PyArg_UnpackKeywords() PyDoc_STRVAR(_socket_socket_close__doc__, @@ -369,4 +370,4 @@ exit: #ifndef _SOCKET_IF_INDEXTONAME_METHODDEF #define _SOCKET_IF_INDEXTONAME_METHODDEF #endif /* !defined(_SOCKET_IF_INDEXTONAME_METHODDEF) */ -/*[clinic end generated code: output=c971b79d2193b426 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=07776dd21d1e3b56 input=a9049054013a1b77]*/ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 47958379263..92c9aa8b510 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -111,7 +111,6 @@ Local naming conventions: #include "pycore_moduleobject.h" // _PyModule_GetState #include "pycore_time.h" // _PyTime_AsMilliseconds() #include "pycore_pystate.h" // _Py_AssertHoldsTstate() -#include "pycore_pyatomic_ft_wrappers.h" #ifdef _Py_MEMORY_SANITIZER # include <sanitizer/msan_interface.h> @@ -565,7 +564,6 @@ static int sock_cloexec_works = -1; static inline void set_sock_fd(PySocketSockObject *s, SOCKET_T fd) { -#ifdef Py_GIL_DISABLED #if SIZEOF_SOCKET_T == SIZEOF_INT _Py_atomic_store_int_relaxed((int *)&s->sock_fd, (int)fd); #elif SIZEOF_SOCKET_T == SIZEOF_LONG @@ -575,15 +573,11 @@ set_sock_fd(PySocketSockObject *s, SOCKET_T fd) #else #error "Unsupported SIZEOF_SOCKET_T" #endif -#else - s->sock_fd = fd; -#endif } static inline SOCKET_T get_sock_fd(PySocketSockObject *s) { -#ifdef Py_GIL_DISABLED #if SIZEOF_SOCKET_T == SIZEOF_INT return (SOCKET_T)_Py_atomic_load_int_relaxed((int *)&s->sock_fd); #elif SIZEOF_SOCKET_T == SIZEOF_LONG @@ -593,9 +587,6 @@ get_sock_fd(PySocketSockObject *s) #else #error "Unsupported SIZEOF_SOCKET_T" #endif -#else - return s->sock_fd; -#endif } #define _PySocketSockObject_CAST(op) ((PySocketSockObject *)(op)) @@ -638,33 +629,22 @@ _PyLong_##NAME##_Converter(PyObject *obj, void *ptr) \ return 1; \ } -UNSIGNED_INT_CONVERTER(UInt16, uint16_t) -UNSIGNED_INT_CONVERTER(UInt32, uint32_t) - #if defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS) # ifdef MS_WINDOWS UNSIGNED_INT_CONVERTER(NetIfindex, NET_IFINDEX) # else - UNSIGNED_INT_CONVERTER(NetIfindex, unsigned int) +# define _PyLong_NetIfindex_Converter _PyLong_UnsignedInt_Converter # define NET_IFINDEX unsigned int # endif #endif // defined(HAVE_IF_NAMEINDEX) || defined(MS_WINDOWS) /*[python input] -class uint16_converter(CConverter): - type = "uint16_t" - converter = '_PyLong_UInt16_Converter' - -class uint32_converter(CConverter): - type = "uint32_t" - converter = '_PyLong_UInt32_Converter' - class NET_IFINDEX_converter(CConverter): type = "NET_IFINDEX" converter = '_PyLong_NetIfindex_Converter' [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=3de2e4a03fbf83b8]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=1cf809c40a407c34]*/ /*[clinic input] module _socket diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 92eaf5e00bc..4f06a36a130 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1955,12 +1955,130 @@ finally: } +int +_PyCode_CheckNoInternalState(PyCodeObject *co, const char **p_errmsg) +{ + const char *errmsg = NULL; + // We don't worry about co_executors, co_instrumentation, + // or co_monitoring. They are essentially ephemeral. + if (co->co_extra != NULL) { + errmsg = "only basic code objects are supported"; + } + + if (errmsg != NULL) { + if (p_errmsg != NULL) { + *p_errmsg = errmsg; + } + return 0; + } + return 1; +} + +int +_PyCode_CheckNoExternalState(PyCodeObject *co, _PyCode_var_counts_t *counts, + const char **p_errmsg) +{ + const char *errmsg = NULL; + assert(counts->locals.hidden.total == 0); + if (counts->numfree > 0) { // It's a closure. + errmsg = "closures not supported"; + } + else if (counts->unbound.globals.numglobal > 0) { + errmsg = "globals not supported"; + } + else if (counts->unbound.globals.numbuiltin > 0 + && counts->unbound.globals.numunknown > 0) + { + errmsg = "globals not supported"; + } + // Otherwise we don't check counts.unbound.globals.numunknown since we can't + // distinguish beween globals and builtins here. + + if (errmsg != NULL) { + if (p_errmsg != NULL) { + *p_errmsg = errmsg; + } + return 0; + } + return 1; +} + +int +_PyCode_VerifyStateless(PyThreadState *tstate, + PyCodeObject *co, PyObject *globalnames, + PyObject *globalsns, PyObject *builtinsns) +{ + const char *errmsg; + _PyCode_var_counts_t counts = {0}; + _PyCode_GetVarCounts(co, &counts); + if (_PyCode_SetUnboundVarCounts( + tstate, co, &counts, globalnames, NULL, + globalsns, builtinsns) < 0) + { + return -1; + } + // We may consider relaxing the internal state constraints + // if it becomes a problem. + if (!_PyCode_CheckNoInternalState(co, &errmsg)) { + _PyErr_SetString(tstate, PyExc_ValueError, errmsg); + return -1; + } + if (builtinsns != NULL) { + // Make sure the next check will fail for globals, + // even if there aren't any builtins. + counts.unbound.globals.numbuiltin += 1; + } + if (!_PyCode_CheckNoExternalState(co, &counts, &errmsg)) { + _PyErr_SetString(tstate, PyExc_ValueError, errmsg); + return -1; + } + // Note that we don't check co->co_flags & CO_NESTED for anything here. + return 0; +} + + +int +_PyCode_CheckPureFunction(PyCodeObject *co, const char **p_errmsg) +{ + const char *errmsg = NULL; + if (co->co_flags & CO_GENERATOR) { + errmsg = "generators not supported"; + } + else if (co->co_flags & CO_COROUTINE) { + errmsg = "coroutines not supported"; + } + else if (co->co_flags & CO_ITERABLE_COROUTINE) { + errmsg = "coroutines not supported"; + } + else if (co->co_flags & CO_ASYNC_GENERATOR) { + errmsg = "generators not supported"; + } + + if (errmsg != NULL) { + if (p_errmsg != NULL) { + *p_errmsg = errmsg; + } + return 0; + } + return 1; +} + /* Here "value" means a non-None value, since a bare return is identical * to returning None explicitly. Likewise a missing return statement * at the end of the function is turned into "return None". */ static int code_returns_only_none(PyCodeObject *co) { + if (!_PyCode_CheckPureFunction(co, NULL)) { + return 0; + } + int len = (int)Py_SIZE(co); + assert(len > 0); + + // The last instruction either returns or raises. We can take advantage + // of that for a quick exit. + _Py_CODEUNIT final = _Py_GetBaseCodeUnit(co, len-1); + // Look up None in co_consts. Py_ssize_t nconsts = PyTuple_Size(co->co_consts); int none_index = 0; @@ -1971,26 +2089,42 @@ code_returns_only_none(PyCodeObject *co) } if (none_index == nconsts) { // None wasn't there, which means there was no implicit return, - // "return", or "return None". That means there must be - // an explicit return (non-None). - return 0; - } + // "return", or "return None". - // Walk the bytecode, looking for RETURN_VALUE. - Py_ssize_t len = Py_SIZE(co); - for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { - _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i); - if (IS_RETURN_OPCODE(inst.op.code)) { - assert(i != 0); - // Ignore it if it returns None. - _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1); - if (prev.op.code == LOAD_CONST) { - // We don't worry about EXTENDED_ARG for now. - if (prev.op.arg == none_index) { - continue; + // That means there must be + // an explicit return (non-None), or it only raises. + if (IS_RETURN_OPCODE(final.op.code)) { + // It was an explicit return (non-None). + return 0; + } + // It must end with a raise then. We still have to walk the + // bytecode to see if there's any explicit return (non-None). + assert(IS_RAISE_OPCODE(final.op.code)); + for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { + _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i); + if (IS_RETURN_OPCODE(inst.op.code)) { + // We alraedy know it isn't returning None. + return 0; + } + } + // It must only raise. + } + else { + // Walk the bytecode, looking for RETURN_VALUE. + for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { + _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i); + if (IS_RETURN_OPCODE(inst.op.code)) { + assert(i != 0); + // Ignore it if it returns None. + _Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1); + if (prev.op.code == LOAD_CONST) { + // We don't worry about EXTENDED_ARG for now. + if (prev.op.arg == none_index) { + continue; + } } + return 0; } - return 0; } } return 1; diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 59b0cf1ce7d..32356f0634d 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3178,9 +3178,10 @@ dict_set_fromkeys(PyInterpreterState *interp, PyDictObject *mp, Py_ssize_t pos = 0; PyObject *key; Py_hash_t hash; - - if (dictresize(interp, mp, - estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) { + uint8_t new_size = Py_MAX( + estimate_log2_keysize(PySet_GET_SIZE(iterable)), + DK_LOG_SIZE(mp->ma_keys)); + if (dictresize(interp, mp, new_size, 0)) { Py_DECREF(mp); return NULL; } diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 56df5730db0..27214a129c2 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1,12 +1,14 @@ /* Function object implementation */ #include "Python.h" +#include "pycore_code.h" // _PyCode_VerifyStateless() #include "pycore_dict.h" // _Py_INCREF_DICT() #include "pycore_function.h" // _PyFunction_Vectorcall #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_modsupport.h" // _PyArg_NoKeywords() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_pyerrors.h" // _PyErr_Occurred() +#include "pycore_setobject.h" // _PySet_NextEntry() #include "pycore_stats.h" @@ -1240,6 +1242,58 @@ PyTypeObject PyFunction_Type = { }; +int +_PyFunction_VerifyStateless(PyThreadState *tstate, PyObject *func) +{ + assert(!PyErr_Occurred()); + assert(PyFunction_Check(func)); + + // Check the globals. + PyObject *globalsns = PyFunction_GET_GLOBALS(func); + if (globalsns != NULL && !PyDict_Check(globalsns)) { + _PyErr_Format(tstate, PyExc_TypeError, + "unsupported globals %R", globalsns); + return -1; + } + // Check the builtins. + PyObject *builtinsns = PyFunction_GET_BUILTINS(func); + if (builtinsns != NULL && !PyDict_Check(builtinsns)) { + _PyErr_Format(tstate, PyExc_TypeError, + "unsupported builtins %R", builtinsns); + return -1; + } + // Disallow __defaults__. + PyObject *defaults = PyFunction_GET_DEFAULTS(func); + if (defaults != NULL && defaults != Py_None && PyDict_Size(defaults) > 0) + { + _PyErr_SetString(tstate, PyExc_ValueError, "defaults not supported"); + return -1; + } + // Disallow __kwdefaults__. + PyObject *kwdefaults = PyFunction_GET_KW_DEFAULTS(func); + if (kwdefaults != NULL && kwdefaults != Py_None + && PyDict_Size(kwdefaults) > 0) + { + _PyErr_SetString(tstate, PyExc_ValueError, + "keyword defaults not supported"); + return -1; + } + // Disallow __closure__. + PyObject *closure = PyFunction_GET_CLOSURE(func); + if (closure != NULL && closure != Py_None && PyTuple_GET_SIZE(closure) > 0) + { + _PyErr_SetString(tstate, PyExc_ValueError, "closures not supported"); + return -1; + } + // Check the code. + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + if (_PyCode_VerifyStateless(tstate, co, NULL, globalsns, builtinsns) < 0) { + return -1; + } + return 0; +} + + static int functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name) { diff --git a/Objects/longobject.c b/Objects/longobject.c index 40d90ecf4fa..0b2dfa003fa 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1760,6 +1760,10 @@ UNSIGNED_INT_CONVERTER(UnsignedInt, unsigned int) UNSIGNED_INT_CONVERTER(UnsignedLong, unsigned long) UNSIGNED_INT_CONVERTER(UnsignedLongLong, unsigned long long) UNSIGNED_INT_CONVERTER(Size_t, size_t) +UNSIGNED_INT_CONVERTER(UInt8, uint8_t) +UNSIGNED_INT_CONVERTER(UInt16, uint16_t) +UNSIGNED_INT_CONVERTER(UInt32, uint32_t) +UNSIGNED_INT_CONVERTER(UInt64, uint64_t) #define CHECK_BINOP(v,w) \ diff --git a/PC/launcher.c b/PC/launcher.c index 5c63d872bd4..fed5e156b92 100644 --- a/PC/launcher.c +++ b/PC/launcher.c @@ -140,7 +140,7 @@ static wchar_t * get_env(wchar_t * key) return buf; } -#if defined(_DEBUG) +#if defined(Py_DEBUG) /* Do not define EXECUTABLEPATH_VALUE in debug builds as it'll never point to the debug build. */ #if defined(_WINDOWS) diff --git a/PC/pyconfig.h.in b/PC/pyconfig.h.in index bbafaed808e..1d659e7cee6 100644 --- a/PC/pyconfig.h.in +++ b/PC/pyconfig.h.in @@ -94,6 +94,11 @@ WIN32 is still required for the locale module. #endif #endif /* Py_BUILD_CORE || Py_BUILD_CORE_BUILTIN || Py_BUILD_CORE_MODULE */ +/* _DEBUG implies Py_DEBUG */ +#ifdef _DEBUG +# define Py_DEBUG 1 +#endif + /* Define to 1 if you want to disable the GIL */ /* Uncomment the definition for free-threaded builds, or define it manually * when compiling extension modules. Note that we test with #ifdef, so @@ -319,21 +324,21 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ This is relevant when using build-system generator (e.g CMake) where the linking is explicitly handled */ # if defined(Py_GIL_DISABLED) -# if defined(_DEBUG) +# if defined(Py_DEBUG) # pragma comment(lib,"python315t_d.lib") # elif defined(Py_LIMITED_API) # pragma comment(lib,"python3t.lib") # else # pragma comment(lib,"python315t.lib") -# endif /* _DEBUG */ +# endif /* Py_DEBUG */ # else /* Py_GIL_DISABLED */ -# if defined(_DEBUG) +# if defined(Py_DEBUG) # pragma comment(lib,"python315_d.lib") # elif defined(Py_LIMITED_API) # pragma comment(lib,"python3.lib") # else # pragma comment(lib,"python315.lib") -# endif /* _DEBUG */ +# endif /* Py_DEBUG */ # endif /* Py_GIL_DISABLED */ # endif /* _MSC_VER && !Py_NO_LINK_LIB */ # endif /* Py_BUILD_CORE */ @@ -376,11 +381,6 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */ # define ALIGNOF_MAX_ALIGN_T 8 #endif -#ifdef _DEBUG -# define Py_DEBUG -#endif - - #ifdef MS_WIN32 #define SIZEOF_SHORT 2 diff --git a/PC/python_uwp.cpp b/PC/python_uwp.cpp index b9c408a580c..8cdb8d722cd 100644 --- a/PC/python_uwp.cpp +++ b/PC/python_uwp.cpp @@ -19,13 +19,13 @@ #include <winrt\Windows.Storage.h> #ifdef PYTHONW -#ifdef _DEBUG +#ifdef Py_DEBUG const wchar_t *PROGNAME = L"pythonw_d.exe"; #else const wchar_t *PROGNAME = L"pythonw.exe"; #endif #else -#ifdef _DEBUG +#ifdef Py_DEBUG const wchar_t *PROGNAME = L"python_d.exe"; #else const wchar_t *PROGNAME = L"python.exe"; diff --git a/PC/python_ver_rc.h b/PC/python_ver_rc.h index ee867fe4122..bb98144cd03 100644 --- a/PC/python_ver_rc.h +++ b/PC/python_ver_rc.h @@ -10,7 +10,7 @@ #define MS_WINDOWS #include "modsupport.h" #include "patchlevel.h" -#ifdef _DEBUG +#ifdef Py_DEBUG # define PYTHON_DEBUG_EXT "_d" #else # define PYTHON_DEBUG_EXT diff --git a/PCbuild/readme.txt b/PCbuild/readme.txt index 01e19aabdec..3ae3255d933 100644 --- a/PCbuild/readme.txt +++ b/PCbuild/readme.txt @@ -173,24 +173,27 @@ library which are implemented in C; each one builds a DLL (renamed to * _asyncio * _ctypes * _ctypes_test - * _zoneinfo * _decimal * _elementtree * _hashlib * _multiprocessing * _overlapped + * _queue + * _remote_debugging * _socket * _testbuffer * _testcapi - * _testlimitedcapi - * _testinternalcapi * _testclinic * _testclinic_limited * _testconsole * _testimportmultiple + * _testinternalcapi + * _testlimitedcapi * _testmultiphase * _testsinglephase - * _tkinter + * _uuid + * _wmi + * _zoneinfo * pyexpat * select * unicodedata @@ -202,18 +205,22 @@ interpreter, but they do implement several major features. See the "Getting External Sources" section below for additional information about getting the source for building these libraries. The sub-projects are: + _bz2 Python wrapper for version 1.0.8 of the libbzip2 compression library Homepage: http://www.bzip.org/ + _lzma - Python wrapper for version 5.2.2 of the liblzma compression library + Python wrapper for version 5.2.2 of the liblzma compression library, + which is itself built by liblzma.vcxproj. Homepage: https://tukaani.org/xz/ + _ssl Python wrapper for version 3.0.15 of the OpenSSL secure sockets - library, which is downloaded from our binaries repository at - https://github.com/python/cpython-bin-deps. + library, which is itself downloaded from our binaries repository at + https://github.com/python/cpython-bin-deps and built by openssl.vcxproj. Homepage: https://www.openssl.org/ @@ -233,6 +240,7 @@ _sqlite3 Wraps SQLite 3.49.1, which is itself built by sqlite3.vcxproj Homepage: https://www.sqlite.org/ + _tkinter Wraps version 8.6.15 of the Tk windowing system, which is downloaded from our binaries repository at @@ -245,13 +253,20 @@ _tkinter PCbuild\prepare_tcltk.bat. This will retrieve the version of the sources matched to the current commit from the Tcl and Tk branches in our source repository at - https://github.com/python/cpython-source-deps. + https://github.com/python/cpython-source-deps and build them via the + tcl.vcxproj and tk.vcxproj sub-projects. The two projects install their respective components in a directory alongside the source directories called "tcltk" on Win32 and "tcltk64" on x64. They also copy the Tcl and Tk DLLs into the current output directory, which should ensure that Tkinter is able to load Tcl/Tk without having to change your PATH. + +_zstd + Python wrapper for version 1.5.7 of the zstd compression library + Homepage: + https://facebook.github.io/zstd/ + zlib-ng Compiles zlib-ng as a static library, which is later included by pythoncore.vcxproj. This was generated using CMake against zlib-ng diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c index c121ec096ae..ae623e0b417 100644 --- a/Python/ast_unparse.c +++ b/Python/ast_unparse.c @@ -702,6 +702,13 @@ append_templatestr(PyUnicodeWriter *writer, expr_ty e) Py_ssize_t last_idx = 0; Py_ssize_t len = asdl_seq_LEN(e->v.TemplateStr.values); + if (len == 0) { + int result = _write_values_subarray(writer, e->v.TemplateStr.values, + 0, len - 1, 't', arena); + _PyArena_Free(arena); + return result; + } + for (Py_ssize_t i = 0; i < len; i++) { expr_ty value = asdl_seq_GET(e->v.TemplateStr.values, i); @@ -774,33 +781,38 @@ append_joinedstr(PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) } static int -append_interpolation_value(PyUnicodeWriter *writer, expr_ty e) +append_interpolation_str(PyUnicodeWriter *writer, PyObject *str) { const char *outer_brace = "{"; - /* Grammar allows PR_TUPLE, but use >PR_TEST for adding parenthesis - around a lambda with ':' */ - PyObject *temp_fv_str = expr_as_unicode(e, PR_TEST + 1); - if (!temp_fv_str) { - return -1; - } - if (PyUnicode_Find(temp_fv_str, _Py_LATIN1_CHR('{'), 0, 1, 1) == 0) { + if (PyUnicode_Find(str, _Py_LATIN1_CHR('{'), 0, 1, 1) == 0) { /* Expression starts with a brace, split it with a space from the outer one. */ outer_brace = "{ "; } if (-1 == append_charp(writer, outer_brace)) { - Py_DECREF(temp_fv_str); return -1; } - if (-1 == PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { - Py_DECREF(temp_fv_str); + if (-1 == PyUnicodeWriter_WriteStr(writer, str)) { return -1; } - Py_DECREF(temp_fv_str); return 0; } static int +append_interpolation_value(PyUnicodeWriter *writer, expr_ty e) +{ + /* Grammar allows PR_TUPLE, but use >PR_TEST for adding parenthesis + around a lambda with ':' */ + PyObject *temp_fv_str = expr_as_unicode(e, PR_TEST + 1); + if (!temp_fv_str) { + return -1; + } + int result = append_interpolation_str(writer, temp_fv_str); + Py_DECREF(temp_fv_str); + return result; +} + +static int append_interpolation_conversion(PyUnicodeWriter *writer, int conversion) { if (conversion < 0) { @@ -843,7 +855,7 @@ append_interpolation_format_spec(PyUnicodeWriter *writer, expr_ty e) static int append_interpolation(PyUnicodeWriter *writer, expr_ty e) { - if (-1 == append_interpolation_value(writer, e->v.Interpolation.value)) { + if (-1 == append_interpolation_str(writer, e->v.Interpolation.str)) { return -1; } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 6a076662640..42e4f581894 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4041,6 +4041,10 @@ dummy_func( DEOPT_IF(!PyStackRef_IsNull(null)); } + op(_GUARD_THIRD_NULL, (null, unused, unused -- null, unused, unused)) { + DEOPT_IF(!PyStackRef_IsNull(null)); + } + op(_GUARD_CALLABLE_TYPE_1, (callable, unused, unused -- callable, unused, unused)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); DEOPT_IF(callable_o != (PyObject *)&PyType_Type); @@ -4359,31 +4363,37 @@ dummy_func( res = PyStackRef_FromPyObjectSteal(res_o); } - inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - /* isinstance(o, o2) */ + op(_GUARD_CALLABLE_ISINSTANCE, (callable, unused, unused, unused -- callable, unused, unused, unused)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - - int total_args = oparg; - _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null)) { - arguments--; - total_args++; - } - DEOPT_IF(total_args != 2); PyInterpreterState *interp = tstate->interp; DEOPT_IF(callable_o != interp->callable_cache.isinstance); + } + + op(_CALL_ISINSTANCE, (callable, null, instance, cls -- res)) { + /* isinstance(o, o2) */ STAT_INC(CALL, hit); - _PyStackRef cls_stackref = arguments[1]; - _PyStackRef inst_stackref = arguments[0]; - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + PyObject *inst_o = PyStackRef_AsPyObjectBorrow(instance); + PyObject *cls_o = PyStackRef_AsPyObjectBorrow(cls); + int retval = PyObject_IsInstance(inst_o, cls_o); if (retval < 0) { ERROR_NO_POP(); } + (void)null; // Silence compiler warnings about unused variables + PyStackRef_CLOSE(cls); + PyStackRef_CLOSE(instance); + DEAD(null); + PyStackRef_CLOSE(callable); res = retval ? PyStackRef_True : PyStackRef_False; assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); } + macro(CALL_ISINSTANCE) = + unused/1 + + unused/2 + + _GUARD_THIRD_NULL + + _GUARD_CALLABLE_ISINSTANCE + + _CALL_ISINSTANCE; + // This is secretly a super-instruction inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, arg -- )) { assert(oparg == 1); diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 74ce02f1a26..7d7e6551c3f 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -6,8 +6,10 @@ #include "osdefs.h" // MAXPATHLEN #include "pycore_ceval.h" // _Py_simple_func #include "pycore_crossinterp.h" // _PyXIData_t +#include "pycore_function.h" // _PyFunction_VerifyStateless() #include "pycore_initconfig.h" // _PyStatus_OK() #include "pycore_namespace.h" // _PyNamespace_New() +#include "pycore_pythonrun.h" // _Py_SourceAsString() #include "pycore_typeobject.h" // _PyStaticType_InitBuiltin() @@ -784,6 +786,131 @@ _PyMarshal_GetXIData(PyThreadState *tstate, PyObject *obj, _PyXIData_t *xidata) } +/* script wrapper */ + +static int +verify_script(PyThreadState *tstate, PyCodeObject *co, int checked, int pure) +{ + // Make sure it isn't a closure and (optionally) doesn't use globals. + PyObject *builtins = NULL; + if (pure) { + builtins = _PyEval_GetBuiltins(tstate); + assert(builtins != NULL); + } + if (checked) { + assert(_PyCode_VerifyStateless(tstate, co, NULL, NULL, builtins) == 0); + } + else if (_PyCode_VerifyStateless(tstate, co, NULL, NULL, builtins) < 0) { + return -1; + } + // Make sure it doesn't have args. + if (co->co_argcount > 0 + || co->co_posonlyargcount > 0 + || co->co_kwonlyargcount > 0 + || co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) + { + _PyErr_SetString(tstate, PyExc_ValueError, + "code with args not supported"); + return -1; + } + // Make sure it doesn't return anything. + if (!_PyCode_ReturnsOnlyNone(co)) { + _PyErr_SetString(tstate, PyExc_ValueError, + "code that returns a value is not a script"); + return -1; + } + return 0; +} + +static int +get_script_xidata(PyThreadState *tstate, PyObject *obj, int pure, + _PyXIData_t *xidata) +{ + // Get the corresponding code object. + PyObject *code = NULL; + int checked = 0; + if (PyCode_Check(obj)) { + code = obj; + Py_INCREF(code); + } + else if (PyFunction_Check(obj)) { + code = PyFunction_GET_CODE(obj); + assert(code != NULL); + Py_INCREF(code); + if (pure) { + if (_PyFunction_VerifyStateless(tstate, obj) < 0) { + goto error; + } + checked = 1; + } + } + else { + const char *filename = "<script>"; + int optimize = 0; + PyCompilerFlags cf = _PyCompilerFlags_INIT; + cf.cf_flags = PyCF_SOURCE_IS_UTF8; + PyObject *ref = NULL; + const char *script = _Py_SourceAsString(obj, "???", "???", &cf, &ref); + if (script == NULL) { + if (!_PyObject_SupportedAsScript(obj)) { + // We discard the raised exception. + _PyErr_Format(tstate, PyExc_TypeError, + "unsupported script %R", obj); + } + goto error; + } + code = Py_CompileStringExFlags( + script, filename, Py_file_input, &cf, optimize); + Py_XDECREF(ref); + if (code == NULL) { + goto error; + } + // Compiled text can't have args or any return statements, + // nor be a closure. It can use globals though. + if (!pure) { + // We don't need to check for globals either. + checked = 1; + } + } + + // Make sure it's actually a script. + if (verify_script(tstate, (PyCodeObject *)code, checked, pure) < 0) { + goto error; + } + + // Convert the code object. + int res = _PyCode_GetXIData(tstate, code, xidata); + Py_DECREF(code); + if (res < 0) { + return -1; + } + return 0; + +error: + Py_XDECREF(code); + PyObject *cause = _PyErr_GetRaisedException(tstate); + assert(cause != NULL); + _set_xid_lookup_failure( + tstate, NULL, "object not a valid script", cause); + Py_DECREF(cause); + return -1; +} + +int +_PyCode_GetScriptXIData(PyThreadState *tstate, + PyObject *obj, _PyXIData_t *xidata) +{ + return get_script_xidata(tstate, obj, 0, xidata); +} + +int +_PyCode_GetPureScriptXIData(PyThreadState *tstate, + PyObject *obj, _PyXIData_t *xidata) +{ + return get_script_xidata(tstate, obj, 1, xidata); +} + + /* using cross-interpreter data */ PyObject * diff --git a/Python/dynload_win.c b/Python/dynload_win.c index 6324063401e..de9b0a77817 100644 --- a/Python/dynload_win.c +++ b/Python/dynload_win.c @@ -108,7 +108,7 @@ static char *GetPythonImport (HINSTANCE hModule) char *pch; /* Don't claim that python3.dll is a Python DLL. */ -#ifdef _DEBUG +#ifdef Py_DEBUG if (strcmp(import_name, "python3_d.dll") == 0) { #else if (strcmp(import_name, "python3.dll") == 0) { @@ -120,7 +120,7 @@ static char *GetPythonImport (HINSTANCE hModule) /* Ensure python prefix is followed only by numbers to the end of the basename */ pch = import_name + 6; -#ifdef _DEBUG +#ifdef Py_DEBUG while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') { #else while (*pch && *pch != '.') { @@ -300,7 +300,7 @@ dl_funcptr _PyImport_FindSharedFuncptrWindows(const char *prefix, char buffer[256]; PyOS_snprintf(buffer, sizeof(buffer), -#ifdef _DEBUG +#ifdef Py_DEBUG "python%d%d_d.dll", #else "python%d%d.dll", diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 3e51ac41fa3..41c9bd5ba70 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5276,6 +5276,16 @@ break; } + case _GUARD_THIRD_NULL: { + _PyStackRef null; + null = stack_pointer[-3]; + if (!PyStackRef_IsNull(null)) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + break; + } + case _GUARD_CALLABLE_TYPE_1: { _PyStackRef callable; callable = stack_pointer[-3]; @@ -5855,58 +5865,57 @@ break; } - case _CALL_ISINSTANCE: { - _PyStackRef *args; - _PyStackRef self_or_null; + case _GUARD_CALLABLE_ISINSTANCE: { _PyStackRef callable; - _PyStackRef res; - oparg = CURRENT_OPARG(); - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; + callable = stack_pointer[-4]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; - _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null)) { - arguments--; - total_args++; - } - if (total_args != 2) { - UOP_STAT_INC(uopcode, miss); - JUMP_TO_JUMP_TARGET(); - } PyInterpreterState *interp = tstate->interp; if (callable_o != interp->callable_cache.isinstance) { UOP_STAT_INC(uopcode, miss); JUMP_TO_JUMP_TARGET(); } + break; + } + + case _CALL_ISINSTANCE: { + _PyStackRef cls; + _PyStackRef instance; + _PyStackRef null; + _PyStackRef callable; + _PyStackRef res; + cls = stack_pointer[-1]; + instance = stack_pointer[-2]; + null = stack_pointer[-3]; + callable = stack_pointer[-4]; STAT_INC(CALL, hit); - _PyStackRef cls_stackref = arguments[1]; - _PyStackRef inst_stackref = arguments[0]; + PyObject *inst_o = PyStackRef_AsPyObjectBorrow(instance); + PyObject *cls_o = PyStackRef_AsPyObjectBorrow(cls); _PyFrame_SetStackPointer(frame, stack_pointer); - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); + int retval = PyObject_IsInstance(inst_o, cls_o); stack_pointer = _PyFrame_GetStackPointer(frame); if (retval < 0) { JUMP_TO_ERROR(); } - res = retval ? PyStackRef_True : PyStackRef_False; - assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); + (void)null; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = callable; - callable = res; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); + PyStackRef_CLOSE(cls); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1 - oparg; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(instance); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = retval ? PyStackRef_True : PyStackRef_False; + assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); + stack_pointer[0] = res; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); break; } diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index 757e9cb3227..d2ea5b5e06b 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -1927,8 +1927,7 @@ get_process_mem_usage(void) } #elif __linux__ - // Linux, use smaps_rollup (Kernel >= 4.4) for RSS + Swap - FILE* fp = fopen("/proc/self/smaps_rollup", "r"); + FILE* fp = fopen("/proc/self/status", "r"); if (fp == NULL) { return -1; } @@ -1938,11 +1937,11 @@ get_process_mem_usage(void) long long swap_kb = -1; while (fgets(line_buffer, sizeof(line_buffer), fp) != NULL) { - if (rss_kb == -1 && strncmp(line_buffer, "Rss:", 4) == 0) { - sscanf(line_buffer + 4, "%lld", &rss_kb); + if (rss_kb == -1 && strncmp(line_buffer, "VmRSS:", 6) == 0) { + sscanf(line_buffer + 6, "%lld", &rss_kb); } - else if (swap_kb == -1 && strncmp(line_buffer, "Swap:", 5) == 0) { - sscanf(line_buffer + 5, "%lld", &swap_kb); + else if (swap_kb == -1 && strncmp(line_buffer, "VmSwap:", 7) == 0) { + sscanf(line_buffer + 7, "%lld", &swap_kb); } if (rss_kb != -1 && swap_kb != -1) { break; // Found both diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7e8b05b747e..b3f2a2067f7 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2777,60 +2777,67 @@ next_instr += 4; INSTRUCTION_STATS(CALL_ISINSTANCE); static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size"); + _PyStackRef null; _PyStackRef callable; - _PyStackRef self_or_null; - _PyStackRef *args; + _PyStackRef instance; + _PyStackRef cls; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ - args = &stack_pointer[-oparg]; - self_or_null = stack_pointer[-1 - oparg]; - callable = stack_pointer[-2 - oparg]; - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); - int total_args = oparg; - _PyStackRef *arguments = args; - if (!PyStackRef_IsNull(self_or_null)) { - arguments--; - total_args++; - } - if (total_args != 2) { - UPDATE_MISS_STATS(CALL); - assert(_PyOpcode_Deopt[opcode] == (CALL)); - JUMP_TO_PREDICTED(CALL); - } - PyInterpreterState *interp = tstate->interp; - if (callable_o != interp->callable_cache.isinstance) { - UPDATE_MISS_STATS(CALL); - assert(_PyOpcode_Deopt[opcode] == (CALL)); - JUMP_TO_PREDICTED(CALL); + // _GUARD_THIRD_NULL + { + null = stack_pointer[-3]; + if (!PyStackRef_IsNull(null)) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } } - STAT_INC(CALL, hit); - _PyStackRef cls_stackref = arguments[1]; - _PyStackRef inst_stackref = arguments[0]; - _PyFrame_SetStackPointer(frame, stack_pointer); - int retval = PyObject_IsInstance(PyStackRef_AsPyObjectBorrow(inst_stackref), PyStackRef_AsPyObjectBorrow(cls_stackref)); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (retval < 0) { - JUMP_TO_LABEL(error); + // _GUARD_CALLABLE_ISINSTANCE + { + callable = stack_pointer[-4]; + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); + PyInterpreterState *interp = tstate->interp; + if (callable_o != interp->callable_cache.isinstance) { + UPDATE_MISS_STATS(CALL); + assert(_PyOpcode_Deopt[opcode] == (CALL)); + JUMP_TO_PREDICTED(CALL); + } } - res = retval ? PyStackRef_True : PyStackRef_False; - assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp = callable; - callable = res; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); + // _CALL_ISINSTANCE + { + cls = stack_pointer[-1]; + instance = stack_pointer[-2]; + STAT_INC(CALL, hit); + PyObject *inst_o = PyStackRef_AsPyObjectBorrow(instance); + PyObject *cls_o = PyStackRef_AsPyObjectBorrow(cls); + _PyFrame_SetStackPointer(frame, stack_pointer); + int retval = PyObject_IsInstance(inst_o, cls_o); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (retval < 0) { + JUMP_TO_LABEL(error); + } + (void)null; + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(cls); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(instance); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += -2; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(callable); + stack_pointer = _PyFrame_GetStackPointer(frame); + res = retval ? PyStackRef_True : PyStackRef_False; + assert((!PyStackRef_IsNull(res)) ^ (_PyErr_Occurred(tstate) != NULL)); } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -1 - oparg; + stack_pointer[0] = res; + stack_pointer += 1; assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } diff --git a/Python/import.c b/Python/import.c index afdc28eda31..9dec0f488a3 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3434,8 +3434,10 @@ PyImport_ImportModule(const char *name) * ImportError instead of blocking. * * Returns the module object with incremented ref count. + * + * Removed in 3.15, but kept for stable ABI compatibility. */ -PyObject * +PyAPI_FUNC(PyObject *) PyImport_ImportModuleNoBlock(const char *name) { if (PyErr_WarnEx(PyExc_DeprecationWarning, diff --git a/Python/marshal.c b/Python/marshal.c index b39c1a5b1ad..afbef6ee679 100644 --- a/Python/marshal.c +++ b/Python/marshal.c @@ -38,7 +38,7 @@ module marshal * On Windows PGO builds, the r_object function overallocates its stack and * can cause a stack overflow. We reduce the maximum depth for all Windows * releases to protect against this. - * #if defined(MS_WINDOWS) && defined(_DEBUG) + * #if defined(MS_WINDOWS) && defined(Py_DEBUG) */ #if defined(MS_WINDOWS) # define MAX_MARSHAL_STACK_DEPTH 1000 diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index e99421a3aff..7c160cdcb0c 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -104,18 +104,18 @@ dummy_func(void) { res = sym_new_null(ctx); } - op(_GUARD_TOS_INT, (tos -- tos)) { - if (sym_matches_type(tos, &PyLong_Type)) { + op(_GUARD_TOS_INT, (value -- value)) { + if (sym_matches_type(value, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyLong_Type); + sym_set_type(value, &PyLong_Type); } - op(_GUARD_NOS_INT, (nos, unused -- nos, unused)) { - if (sym_matches_type(nos, &PyLong_Type)) { + op(_GUARD_NOS_INT, (left, unused -- left, unused)) { + if (sym_matches_type(left, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyLong_Type); + sym_set_type(left, &PyLong_Type); } op(_GUARD_TYPE_VERSION, (type_version/2, owner -- owner)) { @@ -141,25 +141,25 @@ dummy_func(void) { } } - op(_GUARD_TOS_FLOAT, (tos -- tos)) { - if (sym_matches_type(tos, &PyFloat_Type)) { + op(_GUARD_TOS_FLOAT, (value -- value)) { + if (sym_matches_type(value, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyFloat_Type); + sym_set_type(value, &PyFloat_Type); } - op(_GUARD_NOS_FLOAT, (nos, unused -- nos, unused)) { - if (sym_matches_type(nos, &PyFloat_Type)) { + op(_GUARD_NOS_FLOAT, (left, unused -- left, unused)) { + if (sym_matches_type(left, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyFloat_Type); + sym_set_type(left, &PyFloat_Type); } - op(_BINARY_OP, (left, right -- res)) { - bool lhs_int = sym_matches_type(left, &PyLong_Type); - bool rhs_int = sym_matches_type(right, &PyLong_Type); - bool lhs_float = sym_matches_type(left, &PyFloat_Type); - bool rhs_float = sym_matches_type(right, &PyFloat_Type); + op(_BINARY_OP, (lhs, rhs -- res)) { + bool lhs_int = sym_matches_type(lhs, &PyLong_Type); + bool rhs_int = sym_matches_type(rhs, &PyLong_Type); + bool lhs_float = sym_matches_type(lhs, &PyFloat_Type); + bool rhs_float = sym_matches_type(rhs, &PyFloat_Type); if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { // There's something other than an int or float involved: res = sym_new_unknown(ctx); @@ -185,11 +185,11 @@ dummy_func(void) { // Case C: res = sym_new_type(ctx, &PyFloat_Type); } - else if (!sym_is_const(ctx, right)) { + else if (!sym_is_const(ctx, rhs)) { // Case A or B... can't know without the sign of the RHS: res = sym_new_unknown(ctx); } - else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, right))) { + else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, rhs))) { // Case B: res = sym_new_type(ctx, &PyFloat_Type); } @@ -366,7 +366,7 @@ dummy_func(void) { ctx->done = true; } - op(_BINARY_OP_SUBSCR_STR_INT, (left, right -- res)) { + op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res)) { res = sym_new_type(ctx, &PyUnicode_Type); } @@ -398,11 +398,11 @@ dummy_func(void) { } } - op(_TO_BOOL_BOOL, (value -- res)) { - int already_bool = optimize_to_bool(this_instr, ctx, value, &res); + op(_TO_BOOL_BOOL, (value -- value)) { + int already_bool = optimize_to_bool(this_instr, ctx, value, &value); if (!already_bool) { sym_set_type(value, &PyBool_Type); - res = sym_new_truthiness(ctx, value, true); + value = sym_new_truthiness(ctx, value, true); } } @@ -493,20 +493,20 @@ dummy_func(void) { res = sym_new_type(ctx, &PyBool_Type); } - op(_IS_OP, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + op(_IS_OP, (left, right -- b)) { + b = sym_new_type(ctx, &PyBool_Type); } - op(_CONTAINS_OP, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + op(_CONTAINS_OP, (left, right -- b)) { + b = sym_new_type(ctx, &PyBool_Type); } - op(_CONTAINS_OP_SET, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + op(_CONTAINS_OP_SET, (left, right -- b)) { + b = sym_new_type(ctx, &PyBool_Type); } - op(_CONTAINS_OP_DICT, (left, right -- res)) { - res = sym_new_type(ctx, &PyBool_Type); + op(_CONTAINS_OP_DICT, (left, right -- b)) { + b = sym_new_type(ctx, &PyBool_Type); } op(_LOAD_CONST, (-- value)) { @@ -707,10 +707,10 @@ dummy_func(void) { } } - op(_MAYBE_EXPAND_METHOD, (callable, self_or_null, args[oparg] -- func, maybe_self, args[oparg])) { + op(_MAYBE_EXPAND_METHOD, (callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { (void)args; - func = sym_new_not_null(ctx); - maybe_self = sym_new_not_null(ctx); + callable = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); } op(_PY_FRAME_GENERAL, (callable, self_or_null, args[oparg] -- new_frame: _Py_UOpsAbstractFrame *)) { @@ -730,14 +730,14 @@ dummy_func(void) { ctx->done = true; } - op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, null, args[oparg] -- self, init, args[oparg])) { + op(_CHECK_AND_ALLOCATE_OBJECT, (type_version/2, callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) { (void)type_version; (void)args; - self = sym_new_not_null(ctx); - init = sym_new_not_null(ctx); + callable = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); } - op(_CREATE_INIT_FRAME, (self, init, args[oparg] -- init_frame: _Py_UOpsAbstractFrame *)) { + op(_CREATE_INIT_FRAME, (init, self, args[oparg] -- init_frame: _Py_UOpsAbstractFrame *)) { init_frame = NULL; ctx->done = true; } @@ -789,21 +789,23 @@ dummy_func(void) { } } - op(_YIELD_VALUE, (unused -- res)) { - res = sym_new_unknown(ctx); + op(_YIELD_VALUE, (unused -- value)) { + value = sym_new_unknown(ctx); } - op(_FOR_ITER_GEN_FRAME, ( -- )) { + op(_FOR_ITER_GEN_FRAME, (unused -- unused, gen_frame: _Py_UOpsAbstractFrame*)) { + gen_frame = NULL; /* We are about to hit the end of the trace */ ctx->done = true; } - op(_SEND_GEN_FRAME, ( -- )) { + op(_SEND_GEN_FRAME, (unused, unused -- unused, gen_frame: _Py_UOpsAbstractFrame *)) { + gen_frame = NULL; // We are about to hit the end of the trace: ctx->done = true; } - op(_CHECK_STACK_SPACE, ( --)) { + op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { assert(corresponding_check_stack == NULL); corresponding_check_stack = this_instr; } @@ -848,14 +850,16 @@ dummy_func(void) { corresponding_check_stack = NULL; } - op(_UNPACK_SEQUENCE, (seq -- values[oparg])) { + op(_UNPACK_SEQUENCE, (seq -- values[oparg], top[0])) { + (void)top; /* This has to be done manually */ for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); } } - op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8])) { + op(_UNPACK_EX, (seq -- values[oparg & 0xFF], unused, unused[oparg >> 8], top[0])) { + (void)top; /* This has to be done manually */ int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { @@ -904,27 +908,27 @@ dummy_func(void) { sym_set_const(flag, Py_False); } - op(_GUARD_IS_NONE_POP, (flag -- )) { - if (sym_is_const(ctx, flag)) { - PyObject *value = sym_get_const(ctx, flag); + op(_GUARD_IS_NONE_POP, (val -- )) { + if (sym_is_const(ctx, val)) { + PyObject *value = sym_get_const(ctx, val); assert(value != NULL); eliminate_pop_guard(this_instr, !Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); + else if (sym_has_type(val)) { + assert(!sym_matches_type(val, &_PyNone_Type)); eliminate_pop_guard(this_instr, true); } - sym_set_const(flag, Py_None); + sym_set_const(val, Py_None); } - op(_GUARD_IS_NOT_NONE_POP, (flag -- )) { - if (sym_is_const(ctx, flag)) { - PyObject *value = sym_get_const(ctx, flag); + op(_GUARD_IS_NOT_NONE_POP, (val -- )) { + if (sym_is_const(ctx, val)) { + PyObject *value = sym_get_const(ctx, val); assert(value != NULL); eliminate_pop_guard(this_instr, Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); + else if (sym_has_type(val)) { + assert(!sym_matches_type(val, &_PyNone_Type)); eliminate_pop_guard(this_instr, false); } } @@ -969,7 +973,7 @@ dummy_func(void) { list = sym_new_type(ctx, &PyList_Type); } - op(_BUILD_SLICE, (values[oparg] -- slice)) { + op(_BUILD_SLICE, (args[oparg] -- slice)) { slice = sym_new_type(ctx, &PySlice_Type); } @@ -977,7 +981,7 @@ dummy_func(void) { map = sym_new_type(ctx, &PyDict_Type); } - op(_BUILD_STRING, (values[oparg] -- str)) { + op(_BUILD_STRING, (pieces[oparg] -- str)) { str = sym_new_type(ctx, &PyUnicode_Type); } @@ -1063,6 +1067,13 @@ dummy_func(void) { sym_set_null(null); } + op(_GUARD_THIRD_NULL, (null, unused, unused -- null, unused, unused)) { + if (sym_is_null(null)) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + sym_set_null(null); + } + op(_GUARD_CALLABLE_TYPE_1, (callable, unused, unused -- callable, unused, unused)) { if (sym_get_const(ctx, callable) == (PyObject *)&PyType_Type) { REPLACE_OP(this_instr, _NOP, 0, 0); @@ -1096,6 +1107,14 @@ dummy_func(void) { sym_set_const(callable, len); } + op(_GUARD_CALLABLE_ISINSTANCE, (callable, unused, unused, unused -- callable, unused, unused, unused)) { + PyObject *isinstance = _PyInterpreterState_GET()->callable_cache.isinstance; + if (sym_get_const(ctx, callable) == isinstance) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + sym_set_const(callable, isinstance); + } + // END BYTECODES // } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 56b4b9983fb..deb912662e4 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -171,14 +171,13 @@ case _TO_BOOL_BOOL: { JitOptSymbol *value; - JitOptSymbol *res; value = stack_pointer[-1]; - int already_bool = optimize_to_bool(this_instr, ctx, value, &res); + int already_bool = optimize_to_bool(this_instr, ctx, value, &value); if (!already_bool) { sym_set_type(value, &PyBool_Type); - res = sym_new_truthiness(ctx, value, true); + value = sym_new_truthiness(ctx, value, true); } - stack_pointer[-1] = res; + stack_pointer[-1] = value; break; } @@ -292,22 +291,22 @@ } case _GUARD_NOS_INT: { - JitOptSymbol *nos; - nos = stack_pointer[-2]; - if (sym_matches_type(nos, &PyLong_Type)) { + JitOptSymbol *left; + left = stack_pointer[-2]; + if (sym_matches_type(left, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyLong_Type); + sym_set_type(left, &PyLong_Type); break; } case _GUARD_TOS_INT: { - JitOptSymbol *tos; - tos = stack_pointer[-1]; - if (sym_matches_type(tos, &PyLong_Type)) { + JitOptSymbol *value; + value = stack_pointer[-1]; + if (sym_matches_type(value, &PyLong_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyLong_Type); + sym_set_type(value, &PyLong_Type); break; } @@ -396,22 +395,22 @@ } case _GUARD_NOS_FLOAT: { - JitOptSymbol *nos; - nos = stack_pointer[-2]; - if (sym_matches_type(nos, &PyFloat_Type)) { + JitOptSymbol *left; + left = stack_pointer[-2]; + if (sym_matches_type(left, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(nos, &PyFloat_Type); + sym_set_type(left, &PyFloat_Type); break; } case _GUARD_TOS_FLOAT: { - JitOptSymbol *tos; - tos = stack_pointer[-1]; - if (sym_matches_type(tos, &PyFloat_Type)) { + JitOptSymbol *value; + value = stack_pointer[-1]; + if (sym_matches_type(value, &PyFloat_Type)) { REPLACE_OP(this_instr, _NOP, 0, 0); } - sym_set_type(tos, &PyFloat_Type); + sym_set_type(value, &PyFloat_Type); break; } @@ -811,14 +810,17 @@ /* _SEND is not a viable micro-op for tier 2 */ case _SEND_GEN_FRAME: { + _Py_UOpsAbstractFrame *gen_frame; + gen_frame = NULL; ctx->done = true; + stack_pointer[-1] = (JitOptSymbol *)gen_frame; break; } case _YIELD_VALUE: { - JitOptSymbol *res; - res = sym_new_unknown(ctx); - stack_pointer[-1] = res; + JitOptSymbol *value; + value = sym_new_unknown(ctx); + stack_pointer[-1] = value; break; } @@ -858,7 +860,10 @@ case _UNPACK_SEQUENCE: { JitOptSymbol **values; + JitOptSymbol **top; values = &stack_pointer[-1]; + top = &stack_pointer[-1 + oparg]; + (void)top; for (int i = 0; i < oparg; i++) { values[i] = sym_new_unknown(ctx); } @@ -907,7 +912,10 @@ case _UNPACK_EX: { JitOptSymbol **values; + JitOptSymbol **top; values = &stack_pointer[-1]; + top = &stack_pointer[(oparg & 0xFF) + (oparg >> 8)]; + (void)top; int totalargs = (oparg & 0xFF) + (oparg >> 8) + 1; for (int i = 0; i < totalargs; i++) { values[i] = sym_new_unknown(ctx); @@ -1376,18 +1384,18 @@ } case _IS_OP: { - JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; + JitOptSymbol *b; + b = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = b; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; } case _CONTAINS_OP: { - JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; + JitOptSymbol *b; + b = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = b; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1405,18 +1413,18 @@ } case _CONTAINS_OP_SET: { - JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; + JitOptSymbol *b; + b = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = b; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; } case _CONTAINS_OP_DICT: { - JitOptSymbol *res; - res = sym_new_type(ctx, &PyBool_Type); - stack_pointer[-2] = res; + JitOptSymbol *b; + b = sym_new_type(ctx, &PyBool_Type); + stack_pointer[-2] = b; stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; @@ -1600,7 +1608,12 @@ } case _FOR_ITER_GEN_FRAME: { + _Py_UOpsAbstractFrame *gen_frame; + gen_frame = NULL; ctx->done = true; + stack_pointer[0] = (JitOptSymbol *)gen_frame; + stack_pointer += 1; + assert(WITHIN_STACK_BOUNDS()); break; } @@ -1721,15 +1734,16 @@ case _MAYBE_EXPAND_METHOD: { JitOptSymbol **args; - JitOptSymbol *func; - JitOptSymbol *maybe_self; - args = &stack_pointer[-oparg]; + JitOptSymbol *self_or_null; + JitOptSymbol *callable; args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; (void)args; - func = sym_new_not_null(ctx); - maybe_self = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = func; - stack_pointer[-1 - oparg] = maybe_self; + callable = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = callable; + stack_pointer[-1 - oparg] = self_or_null; break; } @@ -1921,6 +1935,16 @@ break; } + case _GUARD_THIRD_NULL: { + JitOptSymbol *null; + null = stack_pointer[-3]; + if (sym_is_null(null)) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + sym_set_null(null); + break; + } + case _GUARD_CALLABLE_TYPE_1: { JitOptSymbol *callable; callable = stack_pointer[-3]; @@ -2001,17 +2025,18 @@ case _CHECK_AND_ALLOCATE_OBJECT: { JitOptSymbol **args; - JitOptSymbol *self; - JitOptSymbol *init; - args = &stack_pointer[-oparg]; + JitOptSymbol *self_or_null; + JitOptSymbol *callable; args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; uint32_t type_version = (uint32_t)this_instr->operand0; (void)type_version; (void)args; - self = sym_new_not_null(ctx); - init = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = self; - stack_pointer[-1 - oparg] = init; + callable = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + stack_pointer[-2 - oparg] = callable; + stack_pointer[-1 - oparg] = self_or_null; break; } @@ -2087,11 +2112,22 @@ break; } + case _GUARD_CALLABLE_ISINSTANCE: { + JitOptSymbol *callable; + callable = stack_pointer[-4]; + PyObject *isinstance = _PyInterpreterState_GET()->callable_cache.isinstance; + if (sym_get_const(ctx, callable) == isinstance) { + REPLACE_OP(this_instr, _NOP, 0, 0); + } + sym_set_const(callable, isinstance); + break; + } + case _CALL_ISINSTANCE: { JitOptSymbol *res; res = sym_new_not_null(ctx); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + stack_pointer[-4] = res; + stack_pointer += -3; assert(WITHIN_STACK_BOUNDS()); break; } @@ -2270,15 +2306,15 @@ } case _BINARY_OP: { - JitOptSymbol *right; - JitOptSymbol *left; - JitOptSymbol *res; - right = stack_pointer[-1]; - left = stack_pointer[-2]; - bool lhs_int = sym_matches_type(left, &PyLong_Type); - bool rhs_int = sym_matches_type(right, &PyLong_Type); - bool lhs_float = sym_matches_type(left, &PyFloat_Type); - bool rhs_float = sym_matches_type(right, &PyFloat_Type); + JitOptSymbol *rhs; + JitOptSymbol *lhs; + JitOptSymbol *res; + rhs = stack_pointer[-1]; + lhs = stack_pointer[-2]; + bool lhs_int = sym_matches_type(lhs, &PyLong_Type); + bool rhs_int = sym_matches_type(rhs, &PyLong_Type); + bool lhs_float = sym_matches_type(lhs, &PyFloat_Type); + bool rhs_float = sym_matches_type(rhs, &PyFloat_Type); if (!((lhs_int || lhs_float) && (rhs_int || rhs_float))) { res = sym_new_unknown(ctx); } @@ -2289,10 +2325,10 @@ else if (lhs_float) { res = sym_new_type(ctx, &PyFloat_Type); } - else if (!sym_is_const(ctx, right)) { + else if (!sym_is_const(ctx, rhs)) { res = sym_new_unknown(ctx); } - else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, right))) { + else if (_PyLong_IsNegative((PyLongObject *)sym_get_const(ctx, rhs))) { res = sym_new_type(ctx, &PyFloat_Type); } else { @@ -2375,33 +2411,33 @@ } case _GUARD_IS_NONE_POP: { - JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(ctx, flag)) { - PyObject *value = sym_get_const(ctx, flag); + JitOptSymbol *val; + val = stack_pointer[-1]; + if (sym_is_const(ctx, val)) { + PyObject *value = sym_get_const(ctx, val); assert(value != NULL); eliminate_pop_guard(this_instr, !Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); + else if (sym_has_type(val)) { + assert(!sym_matches_type(val, &_PyNone_Type)); eliminate_pop_guard(this_instr, true); } - sym_set_const(flag, Py_None); + sym_set_const(val, Py_None); stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); break; } case _GUARD_IS_NOT_NONE_POP: { - JitOptSymbol *flag; - flag = stack_pointer[-1]; - if (sym_is_const(ctx, flag)) { - PyObject *value = sym_get_const(ctx, flag); + JitOptSymbol *val; + val = stack_pointer[-1]; + if (sym_is_const(ctx, val)) { + PyObject *value = sym_get_const(ctx, val); assert(value != NULL); eliminate_pop_guard(this_instr, Py_IsNone(value)); } - else if (sym_has_type(flag)) { - assert(!sym_matches_type(flag, &_PyNone_Type)); + else if (sym_has_type(val)) { + assert(!sym_matches_type(val, &_PyNone_Type)); eliminate_pop_guard(this_instr, false); } stack_pointer += -1; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index c4c1d9fd9e1..8394245d373 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3144,7 +3144,7 @@ static inline void _Py_NO_RETURN fatal_error_exit(int status) { if (status < 0) { -#if defined(MS_WINDOWS) && defined(_DEBUG) +#if defined(MS_WINDOWS) && defined(Py_DEBUG) DebugBreak(); #endif abort(); diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 4ee287af72f..f67b72aa91f 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1524,6 +1524,26 @@ Py_CompileStringExFlags(const char *str, const char *filename_str, int start, return co; } +int +_PyObject_SupportedAsScript(PyObject *cmd) +{ + if (PyUnicode_Check(cmd)) { + return 1; + } + else if (PyBytes_Check(cmd)) { + return 1; + } + else if (PyByteArray_Check(cmd)) { + return 1; + } + else if (PyObject_CheckBuffer(cmd)) { + return 1; + } + else { + return 0; + } +} + const char * _Py_SourceAsString(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, PyObject **cmd_copy) { diff --git a/Python/specialize.c b/Python/specialize.c index bbe725c8ec8..06995d46d8b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2158,7 +2158,7 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) if (nargs == 2) { /* isinstance(o1, o2) */ PyInterpreterState *interp = _PyInterpreterState_GET(); - if (callable == interp->callable_cache.isinstance) { + if (callable == interp->callable_cache.isinstance && instr->op.arg == 2) { specialize(instr, CALL_ISINSTANCE); return 0; } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 00dce4527fb..41b9a6b276a 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1670,6 +1670,9 @@ _sys_getwindowsversion_from_kernel32(void) !GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) || !VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) { PyErr_SetFromWindowsErr(0); + if (verblock) { + PyMem_RawFree(verblock); + } return NULL; } diff --git a/Tools/build/.warningignore_macos b/Tools/build/.warningignore_macos index 05dce817dfd..d7b62bc6a43 100644 --- a/Tools/build/.warningignore_macos +++ b/Tools/build/.warningignore_macos @@ -3,7 +3,6 @@ # Keep lines sorted lexicographically to help avoid merge conflicts. # Format example: # /path/to/file (number of warnings in file) -Modules/_sqlite/clinic/connection.c.h 6 Modules/expat/siphash.h 7 Modules/expat/xmlparse.c 13 Modules/expat/xmltok.c 3 diff --git a/Tools/build/.warningignore_ubuntu b/Tools/build/.warningignore_ubuntu index a70f75c948a..469c727abfb 100644 --- a/Tools/build/.warningignore_ubuntu +++ b/Tools/build/.warningignore_ubuntu @@ -3,4 +3,3 @@ # Keep lines sorted lexicographically to help avoid merge conflicts. # Format example: # /path/to/file (number of warnings in file) -Modules/_sqlite/clinic/connection.c.h 6 diff --git a/Tools/build/mypy.ini b/Tools/build/mypy.ini index db546c6fb34..fab35bf6890 100644 --- a/Tools/build/mypy.ini +++ b/Tools/build/mypy.ini @@ -1,7 +1,11 @@ [mypy] + +# Please, when adding new files here, also add them to: +# .github/workflows/mypy.yml files = Tools/build/compute-changes.py, Tools/build/generate_sbom.py, + Tools/build/verify_ensurepip_wheels.py, Tools/build/update_file.py pretty = True diff --git a/Tools/build/verify_ensurepip_wheels.py b/Tools/build/verify_ensurepip_wheels.py index a37da2f7075..46c42916d93 100755 --- a/Tools/build/verify_ensurepip_wheels.py +++ b/Tools/build/verify_ensurepip_wheels.py @@ -20,13 +20,13 @@ ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding=" GITHUB_ACTIONS = os.getenv("GITHUB_ACTIONS") == "true" -def print_notice(file_path: str, message: str) -> None: +def print_notice(file_path: str | Path, message: str) -> None: if GITHUB_ACTIONS: message = f"::notice file={file_path}::{message}" print(message, end="\n\n") -def print_error(file_path: str, message: str) -> None: +def print_error(file_path: str | Path, message: str) -> None: if GITHUB_ACTIONS: message = f"::error file={file_path}::{message}" print(message, end="\n\n") @@ -67,6 +67,7 @@ def verify_wheel(package_name: str) -> bool: return False release_files = json.loads(raw_text)["releases"][package_version] + expected_digest = "" for release_info in release_files: if package_path.name != release_info["filename"]: continue @@ -95,6 +96,7 @@ def verify_wheel(package_name: str) -> bool: return True + if __name__ == "__main__": exit_status = int(not verify_wheel("pip")) raise SystemExit(exit_status) diff --git a/Tools/cases_generator/optimizer_generator.py b/Tools/cases_generator/optimizer_generator.py index 7a32275347e..fda022a44e5 100644 --- a/Tools/cases_generator/optimizer_generator.py +++ b/Tools/cases_generator/optimizer_generator.py @@ -30,16 +30,52 @@ DEFAULT_ABSTRACT_INPUT = (ROOT / "Python/optimizer_bytecodes.c").absolute().as_p def validate_uop(override: Uop, uop: Uop) -> None: - # To do - pass + """ + Check that the overridden uop (defined in 'optimizer_bytecodes.c') + has the same stack effects as the original uop (defined in 'bytecodes.c'). + + Ensure that: + - The number of inputs and outputs is the same. + - The names of the inputs and outputs are the same + (except for 'unused' which is ignored). + - The sizes of the inputs and outputs are the same. + """ + for stack_effect in ('inputs', 'outputs'): + orig_effects = getattr(uop.stack, stack_effect) + new_effects = getattr(override.stack, stack_effect) + + if len(orig_effects) != len(new_effects): + msg = ( + f"{uop.name}: Must have the same number of {stack_effect} " + "in bytecodes.c and optimizer_bytecodes.c " + f"({len(orig_effects)} != {len(new_effects)})" + ) + raise analysis_error(msg, override.body.open) + + for orig, new in zip(orig_effects, new_effects, strict=True): + if orig.name != new.name and orig.name != "unused" and new.name != "unused": + msg = ( + f"{uop.name}: {stack_effect.capitalize()} must have " + "equal names in bytecodes.c and optimizer_bytecodes.c " + f"({orig.name} != {new.name})" + ) + raise analysis_error(msg, override.body.open) + + if orig.size != new.size: + msg = ( + f"{uop.name}: {stack_effect.capitalize()} must have " + "equal sizes in bytecodes.c and optimizer_bytecodes.c " + f"({orig.size!r} != {new.size!r})" + ) + raise analysis_error(msg, override.body.open) def type_name(var: StackItem) -> str: if var.is_array(): - return f"JitOptSymbol **" + return "JitOptSymbol **" if var.type: return var.type - return f"JitOptSymbol *" + return "JitOptSymbol *" def declare_variables(uop: Uop, out: CWriter, skip_inputs: bool) -> None: diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py index 633fb5f56a6..39d0ac557a6 100644 --- a/Tools/clinic/libclinic/converters.py +++ b/Tools/clinic/libclinic/converters.py @@ -17,6 +17,54 @@ from libclinic.converter import ( TypeSet = set[bltns.type[object]] +class BaseUnsignedIntConverter(CConverter): + + def use_converter(self) -> None: + if self.converter: + self.add_include('pycore_long.h', + f'{self.converter}()') + + def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: + if not limited_capi: + return super().parse_arg(argname, displayname, limited_capi=limited_capi) + return self.format_code(""" + {{{{ + Py_ssize_t _bytes = PyLong_AsNativeBytes({argname}, &{paramname}, sizeof({type}), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_REJECT_NEGATIVE | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) {{{{ + goto exit; + }}}} + if ((size_t)_bytes > sizeof({type})) {{{{ + PyErr_SetString(PyExc_OverflowError, + "Python int too large for C {type}"); + goto exit; + }}}} + }}}} + """, + argname=argname, + type=self.type) + + +class uint8_converter(BaseUnsignedIntConverter): + type = "uint8_t" + converter = '_PyLong_UInt8_Converter' + +class uint16_converter(BaseUnsignedIntConverter): + type = "uint16_t" + converter = '_PyLong_UInt16_Converter' + +class uint32_converter(BaseUnsignedIntConverter): + type = "uint32_t" + converter = '_PyLong_UInt32_Converter' + +class uint64_converter(BaseUnsignedIntConverter): + type = "uint64_t" + converter = '_PyLong_UInt64_Converter' + + class bool_converter(CConverter): type = 'int' default_type = bool @@ -211,29 +259,7 @@ class short_converter(CConverter): return super().parse_arg(argname, displayname, limited_capi=limited_capi) -def format_inline_unsigned_int_converter(self: CConverter, argname: str) -> str: - return self.format_code(""" - {{{{ - Py_ssize_t _bytes = PyLong_AsNativeBytes({argname}, &{paramname}, sizeof({type}), - Py_ASNATIVEBYTES_NATIVE_ENDIAN | - Py_ASNATIVEBYTES_ALLOW_INDEX | - Py_ASNATIVEBYTES_REJECT_NEGATIVE | - Py_ASNATIVEBYTES_UNSIGNED_BUFFER); - if (_bytes < 0) {{{{ - goto exit; - }}}} - if ((size_t)_bytes > sizeof({type})) {{{{ - PyErr_SetString(PyExc_OverflowError, - "Python int too large for C {type}"); - goto exit; - }}}} - }}}} - """, - argname=argname, - type=self.type) - - -class unsigned_short_converter(CConverter): +class unsigned_short_converter(BaseUnsignedIntConverter): type = 'unsigned short' default_type = int c_ignored_default = "0" @@ -244,11 +270,6 @@ class unsigned_short_converter(CConverter): else: self.converter = '_PyLong_UnsignedShort_Converter' - def use_converter(self) -> None: - if self.converter == '_PyLong_UnsignedShort_Converter': - self.add_include('pycore_long.h', - '_PyLong_UnsignedShort_Converter()') - def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: if self.format_unit == 'H': return self.format_code(""" @@ -258,9 +279,7 @@ class unsigned_short_converter(CConverter): }}}} """, argname=argname) - if not limited_capi: - return super().parse_arg(argname, displayname, limited_capi=limited_capi) - return format_inline_unsigned_int_converter(self, argname) + return super().parse_arg(argname, displayname, limited_capi=limited_capi) @add_legacy_c_converter('C', accept={str}) @@ -311,7 +330,7 @@ class int_converter(CConverter): return super().parse_arg(argname, displayname, limited_capi=limited_capi) -class unsigned_int_converter(CConverter): +class unsigned_int_converter(BaseUnsignedIntConverter): type = 'unsigned int' default_type = int c_ignored_default = "0" @@ -322,11 +341,6 @@ class unsigned_int_converter(CConverter): else: self.converter = '_PyLong_UnsignedInt_Converter' - def use_converter(self) -> None: - if self.converter == '_PyLong_UnsignedInt_Converter': - self.add_include('pycore_long.h', - '_PyLong_UnsignedInt_Converter()') - def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: if self.format_unit == 'I': return self.format_code(""" @@ -336,9 +350,7 @@ class unsigned_int_converter(CConverter): }}}} """, argname=argname) - if not limited_capi: - return super().parse_arg(argname, displayname, limited_capi=limited_capi) - return format_inline_unsigned_int_converter(self, argname) + return super().parse_arg(argname, displayname, limited_capi=limited_capi) class long_converter(CConverter): @@ -359,7 +371,7 @@ class long_converter(CConverter): return super().parse_arg(argname, displayname, limited_capi=limited_capi) -class unsigned_long_converter(CConverter): +class unsigned_long_converter(BaseUnsignedIntConverter): type = 'unsigned long' default_type = int c_ignored_default = "0" @@ -370,11 +382,6 @@ class unsigned_long_converter(CConverter): else: self.converter = '_PyLong_UnsignedLong_Converter' - def use_converter(self) -> None: - if self.converter == '_PyLong_UnsignedLong_Converter': - self.add_include('pycore_long.h', - '_PyLong_UnsignedLong_Converter()') - def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: if self.format_unit == 'k': return self.format_code(""" @@ -387,9 +394,7 @@ class unsigned_long_converter(CConverter): argname=argname, bad_argument=self.bad_argument(displayname, 'int', limited_capi=limited_capi), ) - if not limited_capi: - return super().parse_arg(argname, displayname, limited_capi=limited_capi) - return format_inline_unsigned_int_converter(self, argname) + return super().parse_arg(argname, displayname, limited_capi=limited_capi) class long_long_converter(CConverter): @@ -410,7 +415,7 @@ class long_long_converter(CConverter): return super().parse_arg(argname, displayname, limited_capi=limited_capi) -class unsigned_long_long_converter(CConverter): +class unsigned_long_long_converter(BaseUnsignedIntConverter): type = 'unsigned long long' default_type = int c_ignored_default = "0" @@ -421,11 +426,6 @@ class unsigned_long_long_converter(CConverter): else: self.converter = '_PyLong_UnsignedLongLong_Converter' - def use_converter(self) -> None: - if self.converter == '_PyLong_UnsignedLongLong_Converter': - self.add_include('pycore_long.h', - '_PyLong_UnsignedLongLong_Converter()') - def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: if self.format_unit == 'K': return self.format_code(""" @@ -438,9 +438,7 @@ class unsigned_long_long_converter(CConverter): argname=argname, bad_argument=self.bad_argument(displayname, 'int', limited_capi=limited_capi), ) - if not limited_capi: - return super().parse_arg(argname, displayname, limited_capi=limited_capi) - return format_inline_unsigned_int_converter(self, argname) + return super().parse_arg(argname, displayname, limited_capi=limited_capi) class Py_ssize_t_converter(CConverter): @@ -557,15 +555,11 @@ class slice_index_converter(CConverter): argname=argname) -class size_t_converter(CConverter): +class size_t_converter(BaseUnsignedIntConverter): type = 'size_t' converter = '_PyLong_Size_t_Converter' c_ignored_default = "0" - def use_converter(self) -> None: - self.add_include('pycore_long.h', - '_PyLong_Size_t_Converter()') - def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None: if self.format_unit == 'n': return self.format_code(""" @@ -575,9 +569,7 @@ class size_t_converter(CConverter): }}}} """, argname=argname) - if not limited_capi: - return super().parse_arg(argname, displayname, limited_capi=limited_capi) - return format_inline_unsigned_int_converter(self, argname) + return super().parse_arg(argname, displayname, limited_capi=limited_capi) class fildes_converter(CConverter): diff --git a/Tools/msi/lib/lib.wixproj b/Tools/msi/lib/lib.wixproj index 02078e503d7..3ea46dd40ea 100644 --- a/Tools/msi/lib/lib.wixproj +++ b/Tools/msi/lib/lib.wixproj @@ -15,12 +15,11 @@ <EmbeddedResource Include="*.wxl" /> </ItemGroup> <ItemGroup> - <ExcludeFolders Include="Lib\test;Lib\tests;Lib\tkinter;Lib\idlelib;Lib\turtledemo" /> + <ExcludeFolders Include="Lib\site-packages;Lib\test;Lib\tests;Lib\tkinter;Lib\idlelib;Lib\turtledemo" /> <InstallFiles Include="$(PySourcePath)Lib\**\*" Exclude="$(PySourcePath)Lib\**\*.pyc; $(PySourcePath)Lib\**\*.pyo; $(PySourcePath)Lib\turtle.py; - $(PySourcePath)Lib\site-packages\README; @(ExcludeFolders->'$(PySourcePath)%(Identity)\*'); @(ExcludeFolders->'$(PySourcePath)%(Identity)\**\*')"> <SourceBase>$(PySourcePath)Lib</SourceBase> diff --git a/Tools/peg_generator/pegen/parser_generator.py b/Tools/peg_generator/pegen/parser_generator.py index 6ce0649aefe..52ae743c26b 100644 --- a/Tools/peg_generator/pegen/parser_generator.py +++ b/Tools/peg_generator/pegen/parser_generator.py @@ -81,6 +81,11 @@ class RuleCheckingVisitor(GrammarVisitor): self.tokens.add("FSTRING_START") self.tokens.add("FSTRING_END") self.tokens.add("FSTRING_MIDDLE") + # If python < 3.14 add the virtual tstring tokens + if sys.version_info < (3, 14, 0, 'beta', 1): + self.tokens.add("TSTRING_START") + self.tokens.add("TSTRING_END") + self.tokens.add("TSTRING_MIDDLE") def visit_NameLeaf(self, node: NameLeaf) -> None: if node.value not in self.rules and node.value not in self.tokens: diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 21224e490b8..3230f969436 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -46,4 +46,12 @@ race:list_inplace_repeat_lock_held # PyObject_Realloc internally does memcpy which isn't atomic so can race # with non-locking reads. See #132070 -race:PyObject_Realloc
\ No newline at end of file +race:PyObject_Realloc + +# gh-133467. Some of these could be hard to trigger. +race_top:update_one_slot +race_top:_Py_slot_tp_getattr_hook +race_top:slot_tp_descr_get +race_top:type_set_name +race_top:set_tp_bases +race_top:type_set_bases_unlocked diff --git a/Tools/wasm/wasi.py b/Tools/wasm/wasi.py index c0f7ccd51aa..b49b27cbbbe 100644 --- a/Tools/wasm/wasi.py +++ b/Tools/wasm/wasi.py @@ -3,7 +3,7 @@ if __name__ == "__main__": import runpy import sys - print("⚠️ WARNING: This script is deprecated and slated for removal in Python 3.19; " + print("⚠️ WARNING: This script is deprecated and slated for removal in Python 3.20; " "execute the `wasi/` directory instead (i.e. `python Tools/wasm/wasi`)\n", file=sys.stderr) diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index 6af9b5f12cb..ba5faeb9e20 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -258,7 +258,7 @@ def configure_wasi_python(context, working_dir): with exec_script.open("w", encoding="utf-8") as file: file.write(f'#!/bin/sh\nexec {host_runner} {python_wasm} "$@"\n') exec_script.chmod(0o755) - print(f"🏃♀️ Created {exec_script} ... ") + print(f"🏃♀️ Created {exec_script} (--host-runner)... ") sys.stdout.flush() @@ -270,10 +270,10 @@ def make_wasi_python(context, working_dir): quiet=context.quiet) exec_script = working_dir / "python.sh" - subprocess.check_call([exec_script, "--version"]) + call([exec_script, "--version"], quiet=False) print( - f"🎉 Use '{exec_script.relative_to(context.init_dir)}' " - "to run CPython in wasm runtime" + f"🎉 Use `{exec_script.relative_to(context.init_dir)}` " + "to run CPython w/ the WASI host specified by --host-runner" ) |