Merge branch 'main' into list-thread-safety-docs

This commit is contained in:
Lysandros Nikolaou 2025-12-18 18:02:29 +02:00
commit 8728c54be4
No known key found for this signature in database
GPG key ID: 43E92D11D08F5F29
420 changed files with 40119 additions and 7252 deletions

2
.gitattributes vendored
View file

@ -68,6 +68,7 @@ PCbuild/readme.txt dos
**/clinic/*.cpp.h generated
**/clinic/*.h.h generated
*_db.h generated
Doc/_static/tachyon-example-*.html generated
Doc/c-api/lifecycle.dot.svg generated
Doc/data/stable_abi.dat generated
Doc/library/token-list.inc generated
@ -88,6 +89,7 @@ Lib/test/certdata/*.pem generated
Lib/test/certdata/*.0 generated
Lib/test/levenshtein_examples.json generated
Lib/test/test_stable_abi_ctypes.py generated
Lib/test/test_zoneinfo/data/*.json generated
Lib/token.py generated
Misc/sbom.spdx.json generated
Objects/typeslots.inc generated

11
.github/CODEOWNERS vendored
View file

@ -289,10 +289,10 @@ Tools/jit/ @brandtbucher @savannahostrowski @diegorusso
InternalDocs/jit.md @brandtbucher @savannahostrowski @diegorusso @AA-Turner
# Micro-op / μop / Tier 2 Optimiser
Python/optimizer.c @markshannon
Python/optimizer.c @markshannon @Fidget-Spinner
Python/optimizer_analysis.c @markshannon @tomasr8 @Fidget-Spinner
Python/optimizer_bytecodes.c @markshannon @tomasr8 @Fidget-Spinner
Python/optimizer_symbols.c @markshannon @tomasr8
Python/optimizer_symbols.c @markshannon @tomasr8 @Fidget-Spinner
# Parser, Lexer, and Grammar
Grammar/python.gram @pablogsal @lysnikolaou
@ -322,7 +322,7 @@ Tools/build/generate_global_objects.py @ericsnowcurrently
# Remote Debugging
Python/remote_debug.h @pablogsal
Python/remote_debugging.c @pablogsal
Modules/_remote_debugging_module.c @pablogsal @ambv @1st1
Modules/_remote_debugging/ @pablogsal
# Sub-Interpreters
**/*crossinterp* @ericsnowcurrently
@ -537,6 +537,11 @@ Lib/pydoc.py @AA-Turner
Lib/pydoc_data/ @AA-Turner
Lib/test/test_pydoc/ @AA-Turner
# Profiling (Sampling)
Doc/library/profiling*.rst @pablogsal
Lib/profiling/ @pablogsal
Lib/test/test_profiling/ @pablogsal
# PyREPL
Lib/_pyrepl/ @pablogsal @lysnikolaou @ambv
Lib/test/test_pyrepl/ @pablogsal @lysnikolaou @ambv

View file

@ -706,7 +706,6 @@ jobs:
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
with:
allowed-failures: >-
build-ios,
build-windows-msi,
build-ubuntu-ssltests-awslc,
build-ubuntu-ssltests-openssl,

View file

@ -26,6 +26,7 @@ on:
- "Tools/build/update_file.py"
- "Tools/build/verify_ensurepip_wheels.py"
- "Tools/cases_generator/**"
- "Tools/check-c-api-docs/**"
- "Tools/clinic/**"
- "Tools/jit/**"
- "Tools/peg_generator/**"
@ -58,6 +59,7 @@ jobs:
"Lib/tomllib",
"Tools/build",
"Tools/cases_generator",
"Tools/check-c-api-docs",
"Tools/clinic",
"Tools/jit",
"Tools/peg_generator",

1
.gitignore vendored
View file

@ -45,6 +45,7 @@ gmon.out
.pytest_cache/
.ruff_cache/
.DS_Store
.pixi/
*.exe

3260
Doc/_static/tachyon-example-flamegraph.html generated Normal file

File diff suppressed because one or more lines are too long

3804
Doc/_static/tachyon-example-heatmap.html generated Normal file

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@ and must be named after the module name plus an extension listed in
Extension export hook
.....................
.. versionadded:: next
.. versionadded:: 3.15
Support for the :samp:`PyModExport_{<name>}` export hook was added in Python
3.15. The older way of defining modules is still available: consult either
@ -191,7 +191,7 @@ the :c:data:`Py_mod_multiple_interpreters` slot.
``PyInit`` function
...................
.. deprecated:: next
.. deprecated:: 3.15
This functionality is :term:`soft deprecated`.
It will not get new features, but there are no plans to remove it.
@ -272,7 +272,7 @@ For example, a module called ``spam`` would be defined like this::
Legacy single-phase initialization
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: next
.. deprecated:: 3.15
Single-phase initialization is :term:`soft deprecated`.
It is a legacy mechanism to initialize extension
@ -282,7 +282,7 @@ Legacy single-phase initialization
However, there are no plans to remove support for it.
In single-phase initialization, the old-style
:ref:`initializaton function <extension-pyinit>` (``PyInit_modulename``)
:ref:`initialization function <extension-pyinit>` (``PyInit_modulename``)
should create, populate and return a module object.
This is typically done using :c:func:`PyModule_Create` and functions like
:c:func:`PyModule_AddObjectRef`.

View file

@ -129,8 +129,7 @@ Importing Modules
of :class:`~importlib.machinery.SourceFileLoader` otherwise.
The module's :attr:`~module.__file__` attribute will be set to the code
object's :attr:`~codeobject.co_filename`. If applicable,
:attr:`~module.__cached__` will also be set.
object's :attr:`~codeobject.co_filename`.
This function will reload the module if it was already imported. See
:c:func:`PyImport_ReloadModule` for the intended way to reload a module.
@ -142,10 +141,13 @@ Importing Modules
:c:func:`PyImport_ExecCodeModuleWithPathnames`.
.. versionchanged:: 3.12
The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__`
The setting of ``__cached__`` and :attr:`~module.__loader__`
is deprecated. See :class:`~importlib.machinery.ModuleSpec` for
alternatives.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
@ -157,16 +159,19 @@ Importing Modules
.. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname)
Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__`
attribute of the module object is set to *cpathname* if it is
non-``NULL``. Of the three functions, this is the preferred one to use.
Like :c:func:`PyImport_ExecCodeModuleEx`, but the path to any compiled file
via *cpathname* is used appropriately when non-``NULL``. Of the three
functions, this is the preferred one to use.
.. versionadded:: 3.3
.. versionchanged:: 3.12
Setting :attr:`~module.__cached__` is deprecated. See
Setting ``__cached__`` is deprecated. See
:class:`~importlib.machinery.ModuleSpec` for alternatives.
.. versionchanged:: 3.15
``__cached__`` no longer set.
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname)

View file

@ -142,7 +142,7 @@ Modules created using the C API are typically defined using an
array of :dfn:`slots`.
The slots provide a "description" of how a module should be created.
.. versionchanged:: next
.. versionchanged:: 3.15
Previously, a :c:type:`PyModuleDef` struct was necessary to define modules.
The older way of defining modules is still available: consult either the
@ -190,7 +190,7 @@ Metadata slots
However, it is still recommended to include this slot for introspection
and debugging purposes.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_name` instead to support previous versions.
@ -201,7 +201,7 @@ Metadata slots
Usually it is set to a variable created with :c:macro:`PyDoc_STRVAR`.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_doc` instead to support previous versions.
@ -332,7 +332,7 @@ Creation and initialization slots
.. versionadded:: 3.5
.. versionchanged:: next
.. versionchanged:: 3.15
The *slots* argument may be a ``ModuleSpec``-like object, rather than
a true :py:class:`~importlib.machinery.ModuleSpec` instance.
@ -365,7 +365,7 @@ Creation and initialization slots
.. versionadded:: 3.5
.. versionchanged:: next
.. versionchanged:: 3.15
Repeated ``Py_mod_exec`` slots are disallowed, except in
:c:type:`PyModuleDef.m_slots`.
@ -384,7 +384,7 @@ Creation and initialization slots
The table must be statically allocated (or otherwise guaranteed to outlive
the module object).
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_methods` instead to support previous versions.
@ -434,7 +434,7 @@ To retrieve the state from a given module, use the following functions:
On error, set *\*result* to -1, and return -1 with an exception set.
.. versionadded:: next
.. versionadded:: 3.15
@ -459,7 +459,7 @@ defining the module state.
Use :c:func:`PyModule_GetStateSize` to retrieve the size of a given module.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
@ -482,7 +482,7 @@ defining the module state.
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
@ -510,7 +510,7 @@ defining the module state.
the cyclic garbage collector is not involved and
the :c:macro:`Py_mod_state_free` function is called directly.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_clear` instead to support previous versions.
@ -532,7 +532,7 @@ defining the module state.
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
.. versionadded:: next
.. versionadded:: 3.15
Use :c:member:`PyModuleDef.m_free` instead to support previous versions.
@ -588,12 +588,12 @@ A module's token -- and the *your_token* value to use in the above code -- is:
behave as if it was created from that :c:type:`PyModuleDef`.
In particular, the module state must have matching layout and semantics.
Modules created from :c:type:`PyModuleDef` allways use the address of
Modules created from :c:type:`PyModuleDef` always use the address of
the :c:type:`PyModuleDef` as the token.
This means that :c:macro:`!Py_mod_token` cannot be used in
:c:member:`PyModuleDef.m_slots`.
.. versionadded:: next
.. versionadded:: 3.15
.. c:function:: int PyModule_GetToken(PyObject *module, void** result)
@ -601,7 +601,7 @@ A module's token -- and the *your_token* value to use in the above code -- is:
On error, set *\*result* to NULL, and return -1 with an exception set.
.. versionadded:: next
.. versionadded:: 3.15
See also :c:func:`PyType_GetModuleByToken`.
@ -641,7 +641,7 @@ rather than from an extension's :ref:`export hook <extension-export-hook>`.
:c:func:`!PyModule_FromSlotsAndSpec` call.
In particular, it may be heap-allocated.
.. versionadded:: next
.. versionadded:: 3.15
.. c:function:: int PyModule_Exec(PyObject *module)
@ -654,7 +654,7 @@ rather than from an extension's :ref:`export hook <extension-export-hook>`.
:ref:`legacy single-phase initialization <single-phase-initialization>`,
this function does nothing and returns 0.
.. versionadded:: next
.. versionadded:: 3.15

View file

@ -111,7 +111,7 @@ Object Protocol
object type name: str
object repr : 'abcdef'
.. versionadded:: next
.. versionadded:: 3.15
.. c:function:: int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name)

View file

@ -148,8 +148,11 @@ Tuple Objects
Struct Sequence Objects
-----------------------
Struct sequence objects are the C equivalent of :func:`~collections.namedtuple`
objects, i.e. a sequence whose items can also be accessed through attributes.
A struct sequence object is a :term:`named tuple`, that is, a sequence
whose items can also be accessed through attributes.
It is similar to :func:`collections.namedtuple`, but provides a slightly
different interface.
To create a struct sequence, you first have to create a specific struct sequence
type.

View file

@ -317,7 +317,7 @@ Type Objects
and other places where a method's defining class cannot be passed using the
:c:type:`PyCMethod` calling convention.
.. versionadded:: next
.. versionadded:: 3.15
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)

View file

@ -436,7 +436,12 @@ latex_appendices = ['glossary', 'about', 'license', 'copyright']
epub_author = 'Python Documentation Authors'
epub_publisher = 'Python Software Foundation'
epub_exclude_files = ('index.xhtml', 'download.xhtml')
epub_exclude_files = (
'index.xhtml',
'download.xhtml',
'_static/tachyon-example-flamegraph.html',
'_static/tachyon-example-heatmap.html',
)
# index pages are not valid xhtml
# https://github.com/sphinx-doc/sphinx/issues/12359

View file

@ -1,6 +1,13 @@
Pending removal in Python 3.20
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* :c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and
:c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed in
3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the result in
the module state, then call :c:func:`PyObject_CallMethod` or
:c:func:`PyObject_GetAttr`.
(Contributed by Victor Stinner in :gh:`141049`.)
* The ``cval`` field in :c:type:`PyComplexObject` (:gh:`128813`).
Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex`
to convert a Python complex number to/from the C :c:type:`Py_complex`

View file

@ -3,9 +3,9 @@ Pending removal in Python 3.15
* The import system:
* Setting :attr:`~module.__cached__` on a module while
* Setting ``__cached__`` on a module while
failing to set :attr:`__spec__.cached <importlib.machinery.ModuleSpec.cached>`
is deprecated. In Python 3.15, :attr:`!__cached__` will cease to be set or
is deprecated. In Python 3.15, ``__cached__`` will cease to be set or
take into consideration by the import system or standard library. (:gh:`97879`)
* Setting :attr:`~module.__package__` on a module while

View file

@ -1,14 +1,16 @@
Pending removal in Python 3.20
------------------------------
* The ``__version__`` attribute has been deprecated in these standard library
modules and will be removed in Python 3.20.
Use :py:data:`sys.version_info` instead.
* The ``__version__``, ``version`` and ``VERSION`` attributes have been
deprecated in these standard library modules and will be removed in
Python 3.20. Use :py:data:`sys.version_info` instead.
- :mod:`argparse`
- :mod:`csv`
- :mod:`ctypes`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`http.server`
- :mod:`imaplib`
- :mod:`ipaddress`
- :mod:`json`
@ -21,6 +23,10 @@ Pending removal in Python 3.20
- :mod:`tabnanny`
- :mod:`tkinter.font`
- :mod:`tkinter.ttk`
- :mod:`wsgiref.simple_server`
- :mod:`xml.etree.ElementTree`
- :mod:`!xml.sax.expatreader`
- :mod:`xml.sax.handler`
- :mod:`zlib`
(Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.)

View file

@ -134,6 +134,14 @@ Glossary
iterator's :meth:`~object.__anext__` method until it raises a
:exc:`StopAsyncIteration` exception. Introduced by :pep:`492`.
atomic operation
An operation that appears to execute as a single, indivisible step: no
other thread can observe it half-done, and its effects become visible all
at once. Python does not guarantee that high-level statements are atomic
(for example, ``x += 1`` performs multiple bytecode operations and is not
atomic). Atomicity is only guaranteed where explicitly documented. See
also :term:`race condition` and :term:`data race`.
attached thread state
A :term:`thread state` that is active for the current OS thread.
@ -289,6 +297,22 @@ Glossary
advanced mathematical feature. If you're not aware of a need for them,
it's almost certain you can safely ignore them.
concurrency
The ability of a computer program to perform multiple tasks at the same
time. Python provides libraries for writing programs that make use of
different forms of concurrency. :mod:`asyncio` is a library for dealing
with asynchronous tasks and coroutines. :mod:`threading` provides
access to operating system threads and :mod:`multiprocessing` to
operating system processes. Multi-core processors can execute threads and
processes on different CPU cores at the same time (see
:term:`parallelism`).
concurrent modification
When multiple threads modify shared data at the same time. Concurrent
modification without proper synchronization can cause
:term:`race conditions <race condition>`, and might also trigger a
:term:`data race <data race>`, data corruption, or both.
context
This term has different meanings depending on where and how it is used.
Some common meanings:
@ -363,6 +387,28 @@ Glossary
the :term:`cyclic garbage collector <garbage collection>` is to identify these groups and break the reference
cycles so that the memory can be reclaimed.
data race
A situation where multiple threads access the same memory location
concurrently, at least one of the accesses is a write, and the threads
do not use any synchronization to control their access. Data races
lead to :term:`non-deterministic` behavior and can cause data corruption.
Proper use of :term:`locks <lock>` and other :term:`synchronization primitives
<synchronization primitive>` prevents data races. Note that data races
can only happen in native code, but that :term:`native code` might be
exposed in a Python API. See also :term:`race condition` and
:term:`thread-safe`.
deadlock
A situation in which two or more tasks (threads, processes, or coroutines)
wait indefinitely for each other to release resources or complete actions,
preventing any from making progress. For example, if thread A holds lock
1 and waits for lock 2, while thread B holds lock 2 and waits for lock 1,
both threads will wait indefinitely. In Python this often arises from
acquiring multiple locks in conflicting orders or from circular
join/await dependencies. Deadlocks can be avoided by always acquiring
multiple :term:`locks <lock>` in a consistent order. See also
:term:`lock` and :term:`reentrant`.
decorator
A function returning another function, usually applied as a function
transformation using the ``@wrapper`` syntax. Common examples for
@ -662,6 +708,14 @@ Glossary
requires the GIL to be held in order to use it. This refers to having an
:term:`attached thread state`.
global state
Data that is accessible throughout a program, such as module-level
variables, class variables, or C static variables in :term:`extension modules
<extension module>`. In multi-threaded programs, global state shared
between threads typically requires synchronization to avoid
:term:`race conditions <race condition>` and
:term:`data races <data race>`.
hash-based pyc
A bytecode cache file that uses the hash rather than the last-modified
time of the corresponding source file to determine its validity. See
@ -706,7 +760,9 @@ Glossary
tuples. Such an object cannot be altered. A new object has to
be created if a different value has to be stored. They play an important
role in places where a constant hash value is needed, for example as a key
in a dictionary.
in a dictionary. Immutable objects are inherently :term:`thread-safe`
because their state cannot be modified after creation, eliminating concerns
about improperly synchronized :term:`concurrent modification`.
import path
A list of locations (or :term:`path entries <path entry>`) that are
@ -796,8 +852,9 @@ Glossary
CPython does not consistently apply the requirement that an iterator
define :meth:`~iterator.__iter__`.
And also please note that the free-threading CPython does not guarantee
the thread-safety of iterator operations.
And also please note that :term:`free-threaded <free threading>`
CPython does not guarantee :term:`thread-safe` behavior of iterator
operations.
key function
@ -813,7 +870,7 @@ Glossary
:func:`itertools.groupby`.
There are several ways to create a key function. For example. the
:meth:`str.lower` method can serve as a key function for case insensitive
:meth:`str.casefold` method can serve as a key function for case insensitive
sorts. Alternatively, a key function can be built from a
:keyword:`lambda` expression such as ``lambda r: (r[0], r[2])``. Also,
:func:`operator.attrgetter`, :func:`operator.itemgetter`, and
@ -835,10 +892,11 @@ Glossary
:keyword:`if` statements.
In a multi-threaded environment, the LBYL approach can risk introducing a
race condition between "the looking" and "the leaping". For example, the
code, ``if key in mapping: return mapping[key]`` can fail if another
:term:`race condition` between "the looking" and "the leaping". For example,
the code, ``if key in mapping: return mapping[key]`` can fail if another
thread removes *key* from *mapping* after the test, but before the lookup.
This issue can be solved with locks or by using the EAFP approach.
This issue can be solved with :term:`locks <lock>` or by using the
:term:`EAFP` approach. See also :term:`thread-safe`.
lexical analyzer
@ -857,6 +915,19 @@ Glossary
clause is optional. If omitted, all elements in ``range(256)`` are
processed.
lock
A :term:`synchronization primitive` that allows only one thread at a
time to access a shared resource. A thread must acquire a lock before
accessing the protected resource and release it afterward. If a thread
attempts to acquire a lock that is already held by another thread, it
will block until the lock becomes available. Python's :mod:`threading`
module provides :class:`~threading.Lock` (a basic lock) and
:class:`~threading.RLock` (a :term:`reentrant` lock). Locks are used
to prevent :term:`race conditions <race condition>` and ensure
:term:`thread-safe` access to shared data. Alternative design patterns
to locks exist such as queues, producer/consumer patterns, and
thread-local state. See also :term:`deadlock`, and :term:`reentrant`.
loader
An object that loads a module.
It must define the :meth:`!exec_module` and :meth:`!create_module` methods
@ -942,8 +1013,11 @@ Glossary
See :term:`method resolution order`.
mutable
Mutable objects can change their value but keep their :func:`id`. See
also :term:`immutable`.
An :term:`object` with state that is allowed to change during the course
of the program. In multi-threaded programs, mutable objects that are
shared between threads require careful synchronization to avoid
:term:`race conditions <race condition>`. See also :term:`immutable`,
:term:`thread-safe`, and :term:`concurrent modification`.
named tuple
The term "named tuple" applies to any type or class that inherits from
@ -995,6 +1069,13 @@ Glossary
See also :term:`module`.
native code
Code that is compiled to machine instructions and runs directly on the
processor, as opposed to code that is interpreted or runs in a virtual
machine. In the context of Python, native code typically refers to
C, C++, Rust or Fortran code in :term:`extension modules <extension module>`
that can be called from Python. See also :term:`extension module`.
nested scope
The ability to refer to a variable in an enclosing definition. For
instance, a function defined inside another function can refer to
@ -1011,6 +1092,15 @@ Glossary
properties, :meth:`~object.__getattribute__`, class methods, and static
methods.
non-deterministic
Behavior where the outcome of a program can vary between executions with
the same inputs. In multi-threaded programs, non-deterministic behavior
often results from :term:`race conditions <race condition>` where the
relative timing or interleaving of threads affects the result.
Proper synchronization using :term:`locks <lock>` and other
:term:`synchronization primitives <synchronization primitive>` helps
ensure deterministic behavior.
object
Any data with state (attributes or value) and defined behavior
(methods). Also the ultimate base class of any :term:`new-style
@ -1041,6 +1131,16 @@ Glossary
See also :term:`regular package` and :term:`namespace package`.
parallelism
Executing multiple operations at the same time (e.g. on multiple CPU
cores). In Python builds with the
:term:`global interpreter lock (GIL) <global interpreter lock>`, only one
thread runs Python bytecode at a time, so taking advantage of multiple
CPU cores typically involves multiple processes
(e.g. :mod:`multiprocessing`) or native extensions that release the GIL.
In :term:`free-threaded <free threading>` Python, multiple Python threads
can run Python code simultaneously on different cores.
parameter
A named entity in a :term:`function` (or method) definition that
specifies an :term:`argument` (or in some cases, arguments) that the
@ -1215,6 +1315,18 @@ Glossary
>>> email.mime.text.__name__
'email.mime.text'
race condition
A condition of a program where the its behavior
depends on the relative timing or ordering of events, particularly in
multi-threaded programs. Race conditions can lead to
:term:`non-deterministic` behavior and bugs that are difficult to
reproduce. A :term:`data race` is a specific type of race condition
involving unsynchronized access to shared memory. The :term:`LBYL`
coding style is particularly susceptible to race conditions in
multi-threaded code. Using :term:`locks <lock>` and other
:term:`synchronization primitives <synchronization primitive>`
helps prevent race conditions.
reference count
The number of references to an object. When the reference count of an
object drops to zero, it is deallocated. Some objects are
@ -1236,6 +1348,25 @@ Glossary
See also :term:`namespace package`.
reentrant
A property of a function or :term:`lock` that allows it to be called or
acquired multiple times by the same thread without causing errors or a
:term:`deadlock`.
For functions, reentrancy means the function can be safely called again
before a previous invocation has completed, which is important when
functions may be called recursively or from signal handlers. Thread-unsafe
functions may be :term:`non-deterministic` if they're called reentrantly in a
multithreaded program.
For locks, Python's :class:`threading.RLock` (reentrant lock) is
reentrant, meaning a thread that already holds the lock can acquire it
again without blocking. In contrast, :class:`threading.Lock` is not
reentrant - attempting to acquire it twice from the same thread will cause
a deadlock.
See also :term:`lock` and :term:`deadlock`.
REPL
An acronym for the "readevalprint loop", another name for the
:term:`interactive` interpreter shell.
@ -1340,6 +1471,18 @@ Glossary
See also :term:`borrowed reference`.
synchronization primitive
A basic building block for coordinating (synchronizing) the execution of
multiple threads to ensure :term:`thread-safe` access to shared resources.
Python's :mod:`threading` module provides several synchronization primitives
including :class:`~threading.Lock`, :class:`~threading.RLock`,
:class:`~threading.Semaphore`, :class:`~threading.Condition`,
:class:`~threading.Event`, and :class:`~threading.Barrier`. Additionally,
the :mod:`queue` module provides multi-producer, multi-consumer queues
that are especially useful in multithreaded programs. These
primitives help prevent :term:`race conditions <race condition>` and
coordinate thread execution. See also :term:`lock`.
t-string
t-strings
String literals prefixed with ``t`` or ``T`` are commonly called
@ -1392,6 +1535,19 @@ Glossary
See :ref:`Thread State and the Global Interpreter Lock <threads>` for more
information.
thread-safe
A module, function, or class that behaves correctly when used by multiple
threads concurrently. Thread-safe code uses appropriate
:term:`synchronization primitives <synchronization primitive>` like
:term:`locks <lock>` to protect shared mutable state, or is designed
to avoid shared mutable state entirely. In the
:term:`free-threaded <free threading>` build, built-in types like
:class:`dict`, :class:`list`, and :class:`set` use internal locking
to make many operations thread-safe, although thread safety is not
necessarily guaranteed. Code that is not thread-safe may experience
:term:`race conditions <race condition>` and :term:`data races <data race>`
when used in multi-threaded programs.
token
A small unit of source code, generated by the

View file

@ -136,7 +136,7 @@ enabled::
at Objects/unicodeobject.c:551
#7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569
#8 0x0000000000584abd in PyDict_GetItemString (v=
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171
Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed

View file

@ -645,6 +645,27 @@ are set.
.. versionadded:: 3.14
To highlight inline code in your description or epilog text, you can use
backticks::
>>> parser = argparse.ArgumentParser(
... formatter_class=argparse.RawDescriptionHelpFormatter,
... epilog='''Examples:
... `python -m myapp --verbose`
... `python -m myapp --config settings.json`
... ''')
When colors are enabled, the text inside backticks will be displayed in a
distinct color to help examples stand out. When colors are disabled, backticks
are preserved as-is, which is readable in plain text.
.. note::
Backtick markup only applies to description and epilog text. It does not
apply to individual argument ``help`` strings.
.. versionadded:: 3.15
The add_argument() method
-------------------------
@ -1349,7 +1370,7 @@ behavior::
>>> parser.parse_args('--foo XXX'.split())
Namespace(bar='XXX')
.. versionchanged:: next
.. versionchanged:: 3.15
Single-dash long option now takes precedence over short options.
@ -1452,7 +1473,7 @@ this API may be passed as the ``action`` parameter to
.. versionadded:: 3.9
.. versionchanged:: next
.. versionchanged:: 3.15
Added support for single-dash options.
Added support for alternate prefix_chars_.
@ -1679,7 +1700,7 @@ The Namespace object
Other utilities
---------------
Sub-commands
Subcommands
^^^^^^^^^^^^
.. method:: ArgumentParser.add_subparsers(*, [title], [description], [prog], \
@ -1708,7 +1729,7 @@ Sub-commands
* *description* - description for the sub-parser group in help output, by
default ``None``
* *prog* - usage information that will be displayed with sub-command help,
* *prog* - usage information that will be displayed with subcommand help,
by default the name of the program and any positional arguments before the
subparser argument
@ -1718,7 +1739,7 @@ Sub-commands
* action_ - the basic type of action to be taken when this argument is
encountered at the command line
* dest_ - name of the attribute under which sub-command name will be
* dest_ - name of the attribute under which subcommand name will be
stored; by default ``None`` and no value is stored
* required_ - Whether or not a subcommand must be provided, by default

View file

@ -139,12 +139,13 @@ Node classes
The :meth:`~object.__repr__` output of :class:`~ast.AST` nodes includes
the values of the node fields.
.. deprecated:: 3.8
.. deprecated-removed:: 3.8 3.14
Old classes :class:`!ast.Num`, :class:`!ast.Str`, :class:`!ast.Bytes`,
:class:`!ast.NameConstant` and :class:`!ast.Ellipsis` are still available,
but they will be removed in future Python releases. In the meantime,
instantiating them will return an instance of a different class.
Previous versions of Python provided the AST classes :class:`!ast.Num`,
:class:`!ast.Str`, :class:`!ast.Bytes`, :class:`!ast.NameConstant` and
:class:`!ast.Ellipsis`, which were deprecated in Python 3.8. These classes
were removed in Python 3.14, and their functionality has been replaced with
:class:`ast.Constant`.
.. deprecated:: 3.9
@ -2419,12 +2420,12 @@ and classes for traversing abstract syntax trees:
during traversal. For this a special visitor exists
(:class:`NodeTransformer`) that allows modifications.
.. deprecated:: 3.8
.. deprecated-removed:: 3.8 3.14
Methods :meth:`!visit_Num`, :meth:`!visit_Str`, :meth:`!visit_Bytes`,
:meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` are deprecated
now and will not be called in future Python versions. Add the
:meth:`visit_Constant` method to handle all constant nodes.
:meth:`!visit_NameConstant` and :meth:`!visit_Ellipsis` will not be called
in Python 3.14+. Add the :meth:`visit_Constant` method instead to handle
all constant nodes.
.. class:: NodeTransformer()

View file

@ -107,7 +107,7 @@ Queue
The queue can no longer grow.
Future calls to :meth:`~Queue.put` raise :exc:`QueueShutDown`.
Currently blocked callers of :meth:`~Queue.put` will be unblocked
and will raise :exc:`QueueShutDown` in the formerly blocked thread.
and will raise :exc:`QueueShutDown` in the formerly awaiting task.
If *immediate* is false (the default), the queue can be wound
down normally with :meth:`~Queue.get` calls to extract tasks

View file

@ -1388,6 +1388,9 @@ On Linux, :func:`~ctypes.util.find_library` tries to run external programs
(``/sbin/ldconfig``, ``gcc``, ``objdump`` and ``ld``) to find the library file.
It returns the filename of the library file.
Note that if the output of these programs does not correspond to the dynamic
linker used by Python, the result of this function may be misleading.
.. versionchanged:: 3.6
On Linux, the value of the environment variable ``LD_LIBRARY_PATH`` is used
when searching for libraries, if a library cannot be found by any other means.
@ -2132,6 +2135,8 @@ Utility functions
The exact functionality is system dependent.
See :ref:`ctypes-finding-shared-libraries` for complete documentation.
.. function:: find_msvcrt()
:module: ctypes.util

View file

@ -34,10 +34,12 @@ The :mod:`decimal` module provides support for fast correctly rounded
decimal floating-point arithmetic. It offers several advantages over the
:class:`float` datatype:
* Decimal "is based on a floating-point model which was designed with people
in mind, and necessarily has a paramount guiding principle -- computers must
provide an arithmetic that works in the same way as the arithmetic that
people learn at school." -- excerpt from the decimal arithmetic specification.
* Decimal "is based on a `floating-point model
<https://speleotrove.com/decimal/damodel.html#refnumber>`__ which was designed
with people in mind, and necessarily has a paramount guiding principle --
computers must provide an arithmetic that works in the same way as the
arithmetic that people learn at school." -- excerpt from the decimal
arithmetic specification.
* Decimal numbers can be represented exactly. In contrast, numbers like
``1.1`` and ``2.2`` do not have exact representations in binary
@ -238,6 +240,26 @@ floating-point flying circus:
>>> c % a
Decimal('0.77')
Decimals can be formatted (with :func:`format` built-in or :ref:`f-strings`) in
fixed-point or scientific notation, using the same formatting syntax (see
:ref:`formatspec`) as builtin :class:`float` type:
.. doctest::
>>> format(Decimal('2.675'), "f")
'2.675'
>>> format(Decimal('2.675'), ".2f")
'2.68'
>>> f"{Decimal('2.675'):.2f}"
'2.68'
>>> format(Decimal('2.675'), ".2e")
'2.68e+0'
>>> with localcontext() as ctx:
... ctx.rounding = ROUND_DOWN
... print(format(Decimal('2.675'), ".2f"))
...
2.67
And some mathematical functions are also available to Decimal:
>>> getcontext().prec = 28

View file

@ -742,8 +742,8 @@ depending on the system error code.
.. attribute:: characters_written
An integer containing the number of characters written to the stream
before it blocked. This attribute is available when using the
An integer containing the number of **bytes** written to the stream
before it blocked. This attribute is available when using the
buffered I/O classes from the :mod:`io` module.
.. exception:: ChildProcessError

View file

@ -340,8 +340,8 @@ are always available. They are listed here in alphabetical order.
It is needed to unambiguous :ref:`filter <warning-filter>` syntax warnings
by module name.
This function raises :exc:`SyntaxError` if the compiled source is invalid,
and :exc:`ValueError` if the source contains null bytes.
This function raises :exc:`SyntaxError` or :exc:`ValueError` if the compiled
source is invalid.
If you want to parse Python code into its AST representation, see
:func:`ast.parse`.
@ -526,7 +526,7 @@ are always available. They are listed here in alphabetical order.
>>> dir() # show the names in the module namespace # doctest: +SKIP
['__builtins__', '__name__', 'struct']
>>> dir(struct) # show the names in the struct module # doctest: +SKIP
['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__',
['Struct', '__all__', '__builtins__', '__doc__', '__file__',
'__initializing__', '__loader__', '__name__', '__package__',
'_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
'unpack', 'unpack_from']
@ -606,16 +606,16 @@ are always available. They are listed here in alphabetical order.
This function executes arbitrary code. Calling it with
user-supplied input may lead to security vulnerabilities.
The *expression* argument is parsed and evaluated as a Python expression
The *source* argument is parsed and evaluated as a Python expression
(technically speaking, a condition list) using the *globals* and *locals*
mappings as global and local namespace. If the *globals* dictionary is
present and does not contain a value for the key ``__builtins__``, a
reference to the dictionary of the built-in module :mod:`builtins` is
inserted under that key before *expression* is parsed. That way you can
inserted under that key before *source* is parsed. That way you can
control what builtins are available to the executed code by inserting your
own ``__builtins__`` dictionary into *globals* before passing it to
:func:`eval`. If the *locals* mapping is omitted it defaults to the
*globals* dictionary. If both mappings are omitted, the expression is
*globals* dictionary. If both mappings are omitted, the source is
executed with the *globals* and *locals* in the environment where
:func:`eval` is called. Note, *eval()* will only have access to the
:term:`nested scopes <nested scope>` (non-locals) in the enclosing

View file

@ -118,7 +118,7 @@ The :mod:`gc` module provides the following functions:
.. versionadded:: 3.4
.. versionchanged:: next
.. versionchanged:: 3.15
Add ``duration`` and ``candidates``.
@ -340,7 +340,7 @@ values but should not rebind them):
.. versionadded:: 3.3
.. versionchanged:: next
.. versionchanged:: 3.15
Add "duration" and "candidates".

View file

@ -319,6 +319,12 @@ HTTPConnection Objects
:class:`str` or bytes-like object that is not also a file as the
body representation.
.. note::
Note that you must have read the whole response or call :meth:`close`
if :meth:`getresponse` raised an non-:exc:`ConnectionError` exception
before you can send a new request to the server.
.. versionchanged:: 3.2
*body* can now be an iterable.
@ -334,16 +340,15 @@ HTTPConnection Objects
Should be called after a request is sent to get the response from the server.
Returns an :class:`HTTPResponse` instance.
.. note::
Note that you must have read the whole response before you can send a new
request to the server.
.. versionchanged:: 3.5
If a :exc:`ConnectionError` or subclass is raised, the
:class:`HTTPConnection` object will be ready to reconnect when
a new request is sent.
Note that this does not apply to :exc:`OSError`\s raised by the underlying
socket. Instead the caller is responsible to call :meth:`close` on the
existing connection.
.. method:: HTTPConnection.set_debuglevel(level)

View file

@ -210,6 +210,12 @@ Functions
:exc:`ModuleNotFoundError` is raised when the module being reloaded lacks
a :class:`~importlib.machinery.ModuleSpec`.
.. versionchanged:: 3.15
If *module* is a lazy module that has not yet been materialized (i.e.,
loaded via :class:`importlib.util.LazyLoader` and not yet accessed),
calling :func:`reload` is a no-op and returns the module unchanged.
This prevents the reload from unintentionally triggering the lazy load.
.. warning::
This function is not thread-safe. Calling it from multiple threads can result
in unexpected behavior. It's recommended to use the :class:`threading.Lock`
@ -1197,8 +1203,7 @@ find and load modules.
.. attribute:: cached
The filename of a compiled version of the module's code
(see :attr:`module.__cached__`).
The filename of a compiled version of the module's code.
The :term:`finder` should always set this attribute but it may be ``None``
for modules that do not need compiled code stored.
@ -1300,7 +1305,7 @@ an :term:`importer`.
.. versionadded:: 3.4
.. function:: cache_from_source(path, debug_override=None, *, optimization=None)
.. function:: cache_from_source(path, *, optimization=None)
Return the :pep:`3147`/:pep:`488` path to the byte-compiled file associated
with the source *path*. For example, if *path* is ``/foo/bar/baz.py`` the return
@ -1319,12 +1324,6 @@ an :term:`importer`.
``/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc``. The string representation
of *optimization* can only be alphanumeric, else :exc:`ValueError` is raised.
The *debug_override* parameter is deprecated and can be used to override
the system's value for ``__debug__``. A ``True`` value is the equivalent of
setting *optimization* to the empty string. A ``False`` value is the same as
setting *optimization* to ``1``. If both *debug_override* an *optimization*
are not ``None`` then :exc:`TypeError` is raised.
.. versionadded:: 3.4
.. versionchanged:: 3.5
@ -1334,6 +1333,9 @@ an :term:`importer`.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. versionchanged:: 3.15
The *debug_override* parameter was removed.
.. function:: source_from_cache(path)

View file

@ -640,7 +640,7 @@ Retrieving source code
Added parameters *inherit_class_doc* and *fallback_to_class_doc*.
Documentation strings on :class:`~functools.cached_property`
objects are now inherited if not overriden.
objects are now inherited if not overridden.
.. function:: getcomments(object)

View file

@ -48,8 +48,19 @@ The :mod:`locale` module defines the following exception and functions:
If *locale* is omitted or ``None``, the current setting for *category* is
returned.
Example::
>>> import locale
>>> loc = locale.setlocale(locale.LC_ALL) # get current locale
# use German locale; name and availability varies with platform
>>> locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
>>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut
>>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale
>>> locale.setlocale(locale.LC_ALL, 'C') # use default (C) locale
>>> locale.setlocale(locale.LC_ALL, loc) # restore saved locale
:func:`setlocale` is not thread-safe on most systems. Applications typically
start with a call of ::
start with a call of::
import locale
locale.setlocale(locale.LC_ALL, '')
@ -580,18 +591,6 @@ The :mod:`locale` module defines the following exception and functions:
:func:`localeconv`.
Example::
>>> import locale
>>> loc = locale.getlocale() # get current locale
# use German locale; name might vary with platform
>>> locale.setlocale(locale.LC_ALL, 'de_DE')
>>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut
>>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale
>>> locale.setlocale(locale.LC_ALL, 'C') # use default (C) locale
>>> locale.setlocale(locale.LC_ALL, loc) # restore saved locale
Background, details, hints, tips and caveats
--------------------------------------------

View file

@ -328,6 +328,17 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
.. versionadded:: 3.13
.. method:: set_name(name, /)
Annotate the memory mapping with the given *name* for easier identification
in ``/proc/<pid>/maps`` if the kernel supports the feature and :option:`-X dev <-X>` is passed
to Python or if Python is built in :ref:`debug mode <debug-build>`.
The length of *name* must not exceed 67 bytes including the ``'\0'`` terminator.
.. availability:: Linux >= 5.17 (kernel built with ``CONFIG_ANON_VMA_NAME`` option)
.. versionadded:: next
.. method:: size()
Return the length of the file, which can be larger than the size of the

View file

@ -521,6 +521,21 @@ Reference
The :mod:`multiprocessing` package mostly replicates the API of the
:mod:`threading` module.
.. _global-start-method:
Global start method
^^^^^^^^^^^^^^^^^^^
Python supports several ways to create and initialize a process.
The global start method sets the default mechanism for creating a process.
Several multiprocessing functions and methods that may also instantiate
certain objects will implicitly set the global start method to the system's default,
if it hasnt been set already. The global start method can only be set once.
If you need to change the start method from the system default, you must
proactively set the global start method before calling functions or methods,
or creating these objects.
:class:`Process` and exceptions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -910,6 +925,9 @@ For an example of the usage of queues for interprocess communication see
locks/semaphores. When a process first puts an item on the queue a feeder
thread is started which transfers objects from a buffer into the pipe.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
The usual :exc:`queue.Empty` and :exc:`queue.Full` exceptions from the
standard library's :mod:`queue` module are raised to signal timeouts.
@ -1025,6 +1043,9 @@ For an example of the usage of queues for interprocess communication see
It is a simplified :class:`Queue` type, very close to a locked :class:`Pipe`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
.. method:: close()
Close the queue: release internal resources.
@ -1055,6 +1076,9 @@ For an example of the usage of queues for interprocess communication see
:class:`JoinableQueue`, a :class:`Queue` subclass, is a queue which
additionally has :meth:`task_done` and :meth:`join` methods.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
.. method:: task_done()
Indicate that a formerly enqueued task is complete. Used by queue
@ -1167,8 +1191,8 @@ Miscellaneous
:mod:`multiprocessing` module.
If *method* is ``None`` then the default context is returned. Note that if
the global start method has not been set, this will set it to the
default method.
the global start method has not been set, this will set it to the system default
See :ref:`global-start-method` for more details.
Otherwise *method* should be ``'fork'``, ``'spawn'``,
``'forkserver'``. :exc:`ValueError` is raised if the specified
start method is not available. See :ref:`multiprocessing-start-methods`.
@ -1179,10 +1203,9 @@ Miscellaneous
Return the name of start method used for starting processes.
If the global start method has not been set and *allow_none* is
``False``, then the start method is set to the default and the name
is returned. If the start method has not been set and *allow_none* is
``True`` then ``None`` is returned.
If the global start method is not set and *allow_none* is ``False``, the global start
method is set to the default, and its name is returned. See
:ref:`global-start-method` for more details.
The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'``
or ``None``. See :ref:`multiprocessing-start-methods`.
@ -1409,6 +1432,9 @@ object -- see :ref:`multiprocessing-managers`.
A barrier object: a clone of :class:`threading.Barrier`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
.. versionadded:: 3.3
.. class:: BoundedSemaphore([value])
@ -1416,6 +1442,9 @@ object -- see :ref:`multiprocessing-managers`.
A bounded semaphore object: a close analog of
:class:`threading.BoundedSemaphore`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
A solitary difference from its close analog exists: its ``acquire`` method's
first argument is named *block*, as is consistent with :meth:`Lock.acquire`.
@ -1436,6 +1465,9 @@ object -- see :ref:`multiprocessing-managers`.
If *lock* is specified then it should be a :class:`Lock` or :class:`RLock`
object from :mod:`multiprocessing`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
.. versionchanged:: 3.3
The :meth:`~threading.Condition.wait_for` method was added.
@ -1443,6 +1475,8 @@ object -- see :ref:`multiprocessing-managers`.
A clone of :class:`threading.Event`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
.. class:: Lock()
@ -1458,6 +1492,9 @@ object -- see :ref:`multiprocessing-managers`.
instance of ``multiprocessing.synchronize.Lock`` initialized with a
default context.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
:class:`Lock` supports the :term:`context manager` protocol and thus may be
used in :keyword:`with` statements.
@ -1515,6 +1552,9 @@ object -- see :ref:`multiprocessing-managers`.
instance of ``multiprocessing.synchronize.RLock`` initialized with a
default context.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
:class:`RLock` supports the :term:`context manager` protocol and thus may be
used in :keyword:`with` statements.
@ -1574,6 +1614,9 @@ object -- see :ref:`multiprocessing-managers`.
A semaphore object: a close analog of :class:`threading.Semaphore`.
Instantiating this class may set the global start method. See
:ref:`global-start-method` for more details.
A solitary difference from its close analog exists: its ``acquire`` method's
first argument is named *block*, as is consistent with :meth:`Lock.acquire`.
@ -1718,7 +1761,7 @@ processes.
attributes which allow one to use it to store and retrieve strings -- see
documentation for :mod:`ctypes`.
.. function:: Array(typecode_or_type, size_or_initializer, *, lock=True)
.. function:: Array(typecode_or_type, size_or_initializer, *, lock=True, ctx=None)
The same as :func:`RawArray` except that depending on the value of *lock* a
process-safe synchronization wrapper may be returned instead of a raw ctypes
@ -1732,9 +1775,13 @@ processes.
automatically protected by a lock, so it will not necessarily be
"process-safe".
Note that *lock* is a keyword-only argument.
*ctx* is a context object, or ``None`` (use the current context). If ``None``,
calling this may set the global start method. See
:ref:`global-start-method` for more details.
.. function:: Value(typecode_or_type, *args, lock=True)
Note that *lock* and *ctx* are keyword-only parameters.
.. function:: Value(typecode_or_type, *args, lock=True, ctx=None)
The same as :func:`RawValue` except that depending on the value of *lock* a
process-safe synchronization wrapper may be returned instead of a raw ctypes
@ -1747,19 +1794,27 @@ processes.
automatically protected by a lock, so it will not necessarily be
"process-safe".
Note that *lock* is a keyword-only argument.
*ctx* is a context object, or ``None`` (use the current context). If ``None``,
calling this may set the global start method. See
:ref:`global-start-method` for more details.
Note that *lock* and *ctx* are keyword-only parameters.
.. function:: copy(obj)
Return a ctypes object allocated from shared memory which is a copy of the
ctypes object *obj*.
.. function:: synchronized(obj[, lock])
.. function:: synchronized(obj, lock=None, ctx=None)
Return a process-safe wrapper object for a ctypes object which uses *lock* to
synchronize access. If *lock* is ``None`` (the default) then a
:class:`multiprocessing.RLock` object is created automatically.
*ctx* is a context object, or ``None`` (use the current context). If ``None``,
calling this may set the global start method. See
:ref:`global-start-method` for more details.
A synchronized wrapper will have two methods in addition to those of the
object it wraps: :meth:`get_obj` returns the wrapped object and
:meth:`get_lock` returns the lock object used for synchronization.
@ -1877,8 +1932,9 @@ their parent process exits. The manager classes are defined in the
*serializer* must be ``'pickle'`` (use :mod:`pickle` serialization) or
``'xmlrpclib'`` (use :mod:`xmlrpc.client` serialization).
*ctx* is a context object, or ``None`` (use the current context). See the
:func:`get_context` function.
*ctx* is a context object, or ``None`` (use the current context). If ``None``,
calling this may set the global start method. See
:ref:`global-start-method` for more details.
*shutdown_timeout* is a timeout in seconds used to wait until the process
used by the manager completes in the :meth:`shutdown` method. If the
@ -2371,7 +2427,9 @@ with the :class:`Pool` class.
the worker processes. Usually a pool is created using the
function :func:`multiprocessing.Pool` or the :meth:`Pool` method
of a context object. In both cases *context* is set
appropriately.
appropriately. If ``None``, calling this function will have the side effect
of setting the current global start method if it has not been set already.
See the :func:`get_context` function.
Note that the methods of the pool object should only be called by
the process which created the pool.

View file

@ -57,8 +57,9 @@ the :mod:`glob` module.)
.. function:: abspath(path)
Return a normalized absolutized version of the pathname *path*. On most
platforms, this is equivalent to calling the function :func:`normpath` as
follows: ``normpath(join(os.getcwd(), path))``.
platforms, this is equivalent to calling ``normpath(join(os.getcwd(), path))``.
.. seealso:: :func:`os.path.join` and :func:`os.path.normpath`.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
@ -243,6 +244,8 @@ the :mod:`glob` module.)
begins with a slash, on Windows that it begins with two (back)slashes, or a
drive letter, colon, and (back)slash together.
.. seealso:: :func:`abspath`
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
@ -357,14 +360,28 @@ the :mod:`glob` module.)
concatenation of *path* and all members of *\*paths*, with exactly one
directory separator following each non-empty part, except the last. That is,
the result will only end in a separator if the last part is either empty or
ends in a separator. If a segment is an absolute path (which on Windows
requires both a drive and a root), then all previous segments are ignored and
joining continues from the absolute path segment.
ends in a separator.
If a segment is an absolute path (which on Windows requires both a drive and
a root), then all previous segments are ignored and joining continues from the
absolute path segment. On Linux, for example::
>>> os.path.join('/home/foo', 'bar')
'/home/foo/bar'
>>> os.path.join('/home/foo', '/home/bar')
'/home/bar'
On Windows, the drive is not reset when a rooted path segment (e.g.,
``r'\foo'``) is encountered. If a segment is on a different drive or is an
absolute path, all previous segments are ignored and the drive is reset. Note
that since there is a current directory for each drive,
absolute path, all previous segments are ignored and the drive is reset. For
example::
>>> os.path.join('c:\\', 'foo')
'c:\\foo'
>>> os.path.join('c:\\foo', 'd:\\bar')
'd:\\bar'
Note that since there is a current directory for each drive,
``os.path.join("c:", "foo")`` represents a path relative to the current
directory on drive :file:`C:` (:file:`c:foo`), not :file:`c:\\foo`.
@ -527,8 +544,8 @@ the :mod:`glob` module.)
*path* is empty, both *head* and *tail* are empty. Trailing slashes are
stripped from *head* unless it is the root (one or more slashes only). In
all cases, ``join(head, tail)`` returns a path to the same location as *path*
(but the strings may differ). Also see the functions :func:`dirname` and
:func:`basename`.
(but the strings may differ). Also see the functions :func:`join`,
:func:`dirname` and :func:`basename`.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

View file

@ -191,6 +191,11 @@ production systems. The target process requires no modification and need not
be restarted. The profiler attaches, collects samples for the specified
duration, then detaches and produces output.
::
python -m profiling.sampling attach --live 12345
python -m profiling.sampling attach --flamegraph -d 30 -o profile.html 12345
On most systems, attaching to another process requires appropriate permissions.
See :ref:`profiling-permissions` for platform-specific requirements.
@ -290,21 +295,23 @@ The default configuration works well for most use cases:
:widths: 25 75
* - Option
- Default behavior
* - ``--interval`` / ``-i``
- Default
* - Default for ``--interval`` / ``-i``
- 100 µs between samples (~10,000 samples/sec)
* - ``--duration`` / ``-d``
- Profile for 10 seconds
* - ``--all-threads`` / ``-a``
- Sample main thread only
* - ``--native``
* - Default for ``--duration`` / ``-d``
- 10 seconds
* - Default for ``--all-threads`` / ``-a``
- Main thread only
* - Default for ``--native``
- No ``<native>`` frames (C code time attributed to caller)
* - ``--no-gc``
- Include ``<GC>`` frames when garbage collection is active
* - ``--mode``
* - Default for ``--no-gc``
- ``<GC>`` frames included when garbage collection is active
* - Default for ``--mode``
- Wall-clock mode (all samples recorded)
* - ``--realtime-stats``
- No live statistics display during profiling
* - Default for ``--realtime-stats``
- Disabled
* - Default for ``--subprocesses``
- Disabled
Sampling interval and duration
@ -401,12 +408,12 @@ and the base instruction.
Opcode information appears in several output formats:
- **Live mode**: An opcode panel shows instruction-level statistics for the
selected function, accessible via keyboard navigation
- **Flame graphs**: Nodes display opcode information when available, helping
identify which instructions consume the most time
- **Flame graphs**: Hovering over a frame displays a tooltip with a bytecode
instruction breakdown, showing which opcodes consumed time in that function
- **Heatmap**: Expandable bytecode panels per source line show instruction
breakdown with specialization percentages
- **Live mode**: An opcode panel shows instruction-level statistics for the
selected function, accessible via keyboard navigation
- **Gecko format**: Opcode transitions are emitted as interval markers in the
Firefox Profiler timeline
@ -437,6 +444,78 @@ working correctly and that sufficient samples are being collected. See
:ref:`sampling-efficiency` for details on interpreting these metrics.
Subprocess profiling
--------------------
The :option:`--subprocesses` option enables automatic profiling of subprocesses
spawned by the target::
python -m profiling.sampling run --subprocesses script.py
python -m profiling.sampling attach --subprocesses 12345
When enabled, the profiler monitors the target process for child process
creation. When a new Python child process is detected, a separate profiler
instance is automatically spawned to profile it. This is useful for
applications that use :mod:`multiprocessing`, :mod:`subprocess`,
:mod:`concurrent.futures` with :class:`~concurrent.futures.ProcessPoolExecutor`,
or other process spawning mechanisms.
.. code-block:: python
:caption: worker_pool.py
from concurrent.futures import ProcessPoolExecutor
import math
def compute_factorial(n):
total = 0
for i in range(50):
total += math.factorial(n)
return total
if __name__ == "__main__":
numbers = [5000 + i * 100 for i in range(50)]
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(compute_factorial, numbers))
print(f"Computed {len(results)} factorials")
::
python -m profiling.sampling run --subprocesses --flamegraph worker_pool.py
This produces separate flame graphs for the main process and each worker
process: ``flamegraph_<main_pid>.html``, ``flamegraph_<worker1_pid>.html``,
and so on.
Each subprocess receives its own output file. The filename is derived from
the specified output path (or the default) with the subprocess's process ID
appended:
- If you specify ``-o profile.html``, subprocesses produce ``profile_12345.html``,
``profile_12346.html``, and so on
- With default output, subprocesses produce files like ``flamegraph_12345.html``
or directories like ``heatmap_12345``
- For pstats format (which defaults to stdout), subprocesses produce files like
``profile_12345.pstats``
The subprocess profilers inherit most sampling options from the parent (interval,
duration, thread selection, native frames, GC frames, async-aware mode, and
output format). All Python descendant processes are profiled recursively,
including grandchildren and further descendants.
Subprocess detection works by periodically scanning for new descendants of
the target process and checking whether each new process is a Python process
by probing the process memory for Python runtime structures. Non-Python
subprocesses (such as shell commands or external tools) are ignored.
There is a limit of 100 concurrent subprocess profilers to prevent resource
exhaustion in programs that spawn many processes. If this limit is reached,
additional subprocesses are not profiled and a warning is printed.
The :option:`--subprocesses` option is incompatible with :option:`--live` mode
because live mode uses an interactive terminal interface that cannot
accommodate multiple concurrent profiler displays.
.. _sampling-efficiency:
Sampling efficiency
@ -470,9 +549,10 @@ which you can use to judge whether the data is sufficient for your analysis.
Profiling modes
===============
The sampling profiler supports three modes that control which samples are
The sampling profiler supports four modes that control which samples are
recorded. The mode determines what the profile measures: total elapsed time,
CPU execution time, or time spent holding the global interpreter lock.
CPU execution time, time spent holding the global interpreter lock, or
exception handling.
Wall-clock mode
@ -528,6 +608,25 @@ I/O-bound or waiting. The function spends most of its time waiting for network,
disk, locks, or sleep. CPU optimization won't help here; consider async I/O,
connection pooling, or reducing wait time instead.
.. code-block:: python
import time
def do_sleep():
time.sleep(2)
def do_compute():
sum(i**2 for i in range(1000000))
if __name__ == "__main__":
do_sleep()
do_compute()
::
python -m profiling.sampling run --mode=wall script.py # do_sleep ~98%, do_compute ~1%
python -m profiling.sampling run --mode=cpu script.py # do_sleep absent, do_compute dominates
GIL mode
--------
@ -552,6 +651,90 @@ GIL?" and "why are my other threads starving?" It can also be useful in
single-threaded programs to distinguish Python execution time from time spent
in C extensions or I/O.
.. code-block:: python
import hashlib
def hash_work():
# C extension - releases GIL during computation
for _ in range(200):
hashlib.sha256(b"data" * 250000).hexdigest()
def python_work():
# Pure Python - holds GIL during computation
for _ in range(3):
sum(i**2 for i in range(1000000))
if __name__ == "__main__":
hash_work()
python_work()
::
python -m profiling.sampling run --mode=cpu script.py # hash_work ~42%, python_work ~38%
python -m profiling.sampling run --mode=gil script.py # hash_work ~5%, python_work ~60%
Exception mode
--------------
Exception mode (``--mode=exception``) records samples only when a thread has
an active exception::
python -m profiling.sampling run --mode=exception script.py
Samples are recorded in two situations: when an exception is being propagated
up the call stack (after ``raise`` but before being caught), or when code is
executing inside an ``except`` block where exception information is still
present in the thread state.
The following example illustrates which code regions are captured:
.. code-block:: python
def example():
try:
raise ValueError("error") # Captured: exception being raised
except ValueError:
process_error() # Captured: inside except block
finally:
cleanup() # NOT captured: exception already handled
def example_propagating():
try:
try:
raise ValueError("error")
finally:
cleanup() # Captured: exception propagating through
except ValueError:
pass
def example_no_exception():
try:
do_work()
finally:
cleanup() # NOT captured: no exception involved
Note that ``finally`` blocks are only captured when an exception is actively
propagating through them. Once an ``except`` block finishes executing, Python
clears the exception information before running any subsequent ``finally``
block. Similarly, ``finally`` blocks that run during normal execution (when no
exception was raised) are not captured because no exception state is present.
This mode is useful for understanding where your program spends time handling
errors. Exception handling can be a significant source of overhead in code
that uses exceptions for flow control (such as ``StopIteration`` in iterators)
or in applications that process many error conditions (such as network servers
handling connection failures).
Exception mode helps answer questions like "how much time is spent handling
exceptions?" and "which exception handlers are the most expensive?" It can
reveal hidden performance costs in code that catches and processes many
exceptions, even when those exceptions are handled gracefully. For example,
if a parsing library uses exceptions internally to signal format errors, this
mode will capture time spent in those handlers even if the calling code never
sees the exceptions.
Output formats
==============
@ -570,6 +753,14 @@ deterministic profilers generate. This is the default output format::
python -m profiling.sampling run script.py
python -m profiling.sampling run --pstats script.py
.. figure:: tachyon-pstats.png
:alt: Tachyon pstats terminal output
:align: center
:width: 100%
The pstats format displays profiling results in a color-coded table showing
function hotspots, sample counts, and timing estimates.
Output appears on stdout by default::
Profile Stats (Mode: wall):
@ -671,6 +862,19 @@ an interactive flame graph visualization::
python -m profiling.sampling run --flamegraph script.py
python -m profiling.sampling run --flamegraph -o profile.html script.py
.. figure:: tachyon-flamegraph.png
:alt: Tachyon interactive flame graph
:align: center
:width: 100%
The flame graph visualization shows call stacks as nested rectangles, with
width proportional to time spent. The sidebar displays runtime statistics,
GIL metrics, and hotspot functions.
.. only:: html
`Try the interactive example <../_static/tachyon-example-flamegraph.html>`__!
If no output file is specified, the profiler generates a filename based on
the process ID (for example, ``flamegraph.12345.html``).
@ -741,6 +945,33 @@ Firefox Profiler timeline:
For this reason, the :option:`--mode` option is not available with Gecko format;
all relevant data is captured automatically.
.. figure:: tachyon-gecko-calltree.png
:alt: Firefox Profiler Call Tree view
:align: center
:width: 100%
The Call Tree view shows the complete call hierarchy with sample counts
and percentages. The sidebar displays detailed statistics for the
selected function including running time and sample distribution.
.. figure:: tachyon-gecko-flamegraph.png
:alt: Firefox Profiler Flame Graph view
:align: center
:width: 100%
The Flame Graph visualization shows call stacks as nested rectangles.
Functions names are visible in the call hierarchy.
.. figure:: tachyon-gecko-opcodes.png
:alt: Firefox Profiler Marker Chart with opcodes
:align: center
:width: 100%
The Marker Chart displays interval markers including CPU state, GIL
status, and opcodes. With ``--opcodes`` enabled, bytecode instructions
like ``BINARY_OP_ADD_FLOAT``, ``CALL_PY_EXACT_ARGS``, and
``CALL_LIST_APPEND`` appear as markers showing execution over time.
Heatmap format
--------------
@ -751,6 +982,15 @@ showing sample counts at the source line level::
python -m profiling.sampling run --heatmap script.py
python -m profiling.sampling run --heatmap -o my_heatmap script.py
.. figure:: tachyon-heatmap.png
:alt: Tachyon heatmap visualization
:align: center
:width: 100%
The heatmap overlays sample counts directly on your source code. Lines are
color-coded from cool (few samples) to hot (many samples). Navigation
buttons (▲▼) let you jump between callers and callees.
Unlike other formats that produce a single file, heatmap output creates a
directory containing HTML files for each profiled source file. If no output
path is specified, the directory is named ``heatmap_PID``.
@ -777,6 +1017,22 @@ The heatmap interface provides several interactive features:
- **Dark/light theme**: toggle with preference saved across sessions
- **Line linking**: click line numbers to create shareable URLs
When opcode-level profiling is enabled with :option:`--opcodes`, each hot line
can be expanded to show which bytecode instructions consumed time:
.. figure:: tachyon-heatmap-with-opcodes.png
:alt: Heatmap with expanded bytecode panel
:align: center
:width: 100%
Expanding a hot line reveals the bytecode instructions executed, including
specialized variants. The panel shows sample counts per instruction and the
overall specialization percentage for the line.
.. only:: html
`Try the interactive example <../_static/tachyon-example-heatmap.html>`__!
Heatmaps are especially useful when you know which file contains a performance
issue but need to identify the specific lines. Many developers prefer this
format because it maps directly to their source code, making it easy to read
@ -794,6 +1050,14 @@ data, similar to the ``top`` command for system processes::
python -m profiling.sampling run --live script.py
python -m profiling.sampling attach --live 12345
.. figure:: tachyon-live-mode-2.gif
:alt: Tachyon live mode showing all threads
:align: center
:width: 100%
Live mode displays real-time profiling statistics, showing combined
data from multiple threads in a multi-threaded application.
The display updates continuously as new samples arrive, showing the current
hottest functions. This mode requires the :mod:`curses` module, which is
available on Unix-like systems but not on Windows. The terminal must be at
@ -809,6 +1073,14 @@ main table, showing instruction-level statistics for the currently selected
function. This panel displays which bytecode instructions are executing most
frequently, including specialized variants and their base opcodes.
.. figure:: tachyon-live-mode-1.gif
:alt: Tachyon live mode with opcode panel
:align: center
:width: 100%
Live mode with ``--opcodes`` enabled shows an opcode panel with a bytecode
instruction breakdown for the selected function.
Keyboard commands
-----------------
@ -890,6 +1162,25 @@ stack often shows event loop internals rather than the logical flow of your
coroutines. Async-aware mode addresses this by tracking which task is running
and presenting stacks that reflect the ``await`` chain.
.. code-block:: python
import asyncio
async def fetch(url):
await asyncio.sleep(0.1)
return url
async def main():
for _ in range(50):
await asyncio.gather(fetch("a"), fetch("b"), fetch("c"))
if __name__ == "__main__":
asyncio.run(main())
::
python -m profiling.sampling run --async-aware --flamegraph -o out.html script.py
.. note::
Async-aware profiling requires the target process to have the :mod:`asyncio`
@ -1000,14 +1291,20 @@ Sampling options
Compatible with ``--live``, ``--flamegraph``, ``--heatmap``, and ``--gecko``
formats only.
.. option:: --subprocesses
Also profile subprocesses. Each subprocess gets its own profiler
instance and output file. Incompatible with ``--live``.
Mode options
------------
.. option:: --mode <mode>
Sampling mode: ``wall`` (default), ``cpu``, or ``gil``.
The ``cpu`` and ``gil`` modes are incompatible with ``--async-aware``.
Sampling mode: ``wall`` (default), ``cpu``, ``gil``, or ``exception``.
The ``cpu``, ``gil``, and ``exception`` modes are incompatible with
``--async-aware``.
.. option:: --async-mode <mode>

View file

@ -252,7 +252,7 @@ Startup hooks
function has been set. This function only exists if Python was compiled
for a version of the library that supports it.
.. versionadded:: next
.. versionadded:: 3.15
.. _readline-completion:

View file

@ -50,10 +50,10 @@ The :mod:`runpy` module provides two functions:
overridden by :func:`run_module`.
The special global variables ``__name__``, ``__spec__``, ``__file__``,
``__cached__``, ``__loader__`` and ``__package__`` are set in the globals
dictionary before the module code is executed. (Note that this is a
minimal set of variables - other variables may be set implicitly as an
interpreter implementation detail.)
``__loader__`` and ``__package__`` are set in the globals dictionary before
the module code is executed. (Note that this is a minimal set of variables -
other variables may be set implicitly as an interpreter implementation
detail.)
``__name__`` is set to *run_name* if this optional argument is not
:const:`None`, to ``mod_name + '.__main__'`` if the named module is a
@ -63,7 +63,7 @@ The :mod:`runpy` module provides two functions:
module (that is, ``__spec__.name`` will always be *mod_name* or
``mod_name + '.__main__'``, never *run_name*).
``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` are
``__file__``, ``__loader__`` and ``__package__`` are
:ref:`set as normal <import-mod-attrs>` based on the module spec.
If the argument *alter_sys* is supplied and evaluates to :const:`True`,
@ -98,6 +98,9 @@ The :mod:`runpy` module provides two functions:
``__package__`` are deprecated. See
:class:`~importlib.machinery.ModuleSpec` for alternatives.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. function:: run_path(path_name, init_globals=None, run_name=None)
.. index::
@ -125,23 +128,23 @@ The :mod:`runpy` module provides two functions:
overridden by :func:`run_path`.
The special global variables ``__name__``, ``__spec__``, ``__file__``,
``__cached__``, ``__loader__`` and ``__package__`` are set in the globals
dictionary before the module code is executed. (Note that this is a
minimal set of variables - other variables may be set implicitly as an
interpreter implementation detail.)
``__loader__`` and ``__package__`` are set in the globals dictionary before
the module code is executed. (Note that this is a minimal set of variables -
other variables may be set implicitly as an interpreter implementation
detail.)
``__name__`` is set to *run_name* if this optional argument is not
:const:`None` and to ``'<run_path>'`` otherwise.
If *file_path* directly references a script file (whether as source
or as precompiled byte code), then ``__file__`` will be set to
*file_path*, and ``__spec__``, ``__cached__``, ``__loader__`` and
*file_path*, and ``__spec__``, ``__loader__`` and
``__package__`` will all be set to :const:`None`.
If *file_path* is a reference to a valid :data:`sys.path` entry, then
``__spec__`` will be set appropriately for the imported :mod:`__main__`
module (that is, ``__spec__.name`` will always be ``__main__``).
``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` will be
``__file__``, ``__loader__`` and ``__package__`` will be
:ref:`set as normal <import-mod-attrs>` based on the module spec.
A number of alterations are also made to the :mod:`sys` module. Firstly,
@ -173,6 +176,9 @@ The :mod:`runpy` module provides two functions:
The setting of ``__cached__``, ``__loader__``, and
``__package__`` are deprecated.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. seealso::
:pep:`338` -- Executing modules as scripts

View file

@ -458,9 +458,11 @@ An :class:`SMTP` instance has the following methods:
Send mail. The required arguments are an :rfc:`822` from-address string, a list
of :rfc:`822` to-address strings (a bare string will be treated as a list with 1
address), and a message string. The caller may pass a list of ESMTP options
(such as ``8bitmime``) to be used in ``MAIL FROM`` commands as *mail_options*.
(such as ``"8bitmime"``) to be used in ``MAIL FROM`` commands as *mail_options*.
ESMTP options (such as ``DSN`` commands) that should be used with all ``RCPT``
commands can be passed as *rcpt_options*. (If you need to use different ESMTP
commands can be passed as *rcpt_options*. Each option should be passed as a string
containing the full text of the option, including any potential key
(for instance, ``"NOTIFY=SUCCESS,FAILURE"``). (If you need to use different ESMTP
options to different recipients you have to use the low-level methods such as
:meth:`!mail`, :meth:`!rcpt` and :meth:`!data` to send the message.)

View file

@ -482,7 +482,7 @@ The AF_* and SOCK_* constants are now :class:`AddressFamily` and
.. versionchanged:: 3.14
Added support for ``TCP_QUICKACK`` on Windows platforms when available.
.. versionchanged:: next
.. versionchanged:: 3.15
``IPV6_HDRINCL`` was added.

View file

@ -164,7 +164,7 @@ This table summarizes the comparison operations:
pair: object; numeric
pair: objects; comparing
Objects of different types, except different numeric types, never compare equal.
Unless stated otherwise, objects of different types never compare equal.
The ``==`` operator is always defined but for some object types (for example,
class objects) is equivalent to :keyword:`is`. The ``<``, ``<=``, ``>`` and ``>=``
operators are only defined where they make sense; for example, they raise a
@ -2258,6 +2258,21 @@ expression support in the :mod:`re` module).
that have the Unicode numeric value property, e.g. U+2155,
VULGAR FRACTION ONE FIFTH. Formally, numeric characters are those with the property
value Numeric_Type=Digit, Numeric_Type=Decimal or Numeric_Type=Numeric.
For example:
.. doctest::
>>> '0123456789'.isnumeric()
True
>>> '٠١٢٣٤٥٦٧٨٩'.isnumeric() # Arabic-indic digit zero to nine
True
>>> '⅕'.isnumeric() # Vulgar fraction one fifth
True
>>> '²'.isdecimal(), '²'.isdigit(), '²'.isnumeric()
(False, True, True)
See also :meth:`isdecimal` and :meth:`isdigit`. Numeric characters are
a superset of decimal numbers.
.. method:: str.isprintable()
@ -2349,6 +2364,19 @@ expression support in the :mod:`re` module).
done using the specified *fillchar* (default is an ASCII space). The
original string is returned if *width* is less than or equal to ``len(s)``.
For example:
.. doctest::
>>> 'Python'.ljust(10)
'Python '
>>> 'Python'.ljust(10, '.')
'Python....'
>>> 'Monty Python'.ljust(10, '.')
'Monty Python'
See also :meth:`rjust`.
.. method:: str.lower()
@ -5175,9 +5203,6 @@ 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.
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,
@ -5563,9 +5588,11 @@ before the statement body is executed and exited when the statement ends:
Returning a true value from this method will cause the :keyword:`with` statement
to suppress the exception and continue execution with the statement immediately
following the :keyword:`!with` statement. Otherwise the exception continues
propagating after this method has finished executing. Exceptions that occur
during execution of this method will replace any exception that occurred in the
body of the :keyword:`!with` statement.
propagating after this method has finished executing.
If this method raises an exception while handling an earlier exception from the
:keyword:`with` block, the new exception is raised, and the original exception
is stored in its :attr:`~BaseException.__context__` attribute.
The exception passed in should never be reraised explicitly - instead, this
method should return a false value to indicate that the method completed

View file

@ -546,6 +546,9 @@ The available presentation types for :class:`float` and
| | :class:`float`, and shows all coefficient digits |
| | for :class:`~decimal.Decimal`. If ``p=0``, the decimal |
| | point is omitted unless the ``#`` option is used. |
| | |
| | For :class:`float`, the exponent always contains at |
| | least two digits, and is zero if the value is zero. |
+---------+----------------------------------------------------------+
| ``'E'`` | Scientific notation. Same as ``'e'`` except it uses |
| | an upper case 'E' as the separator character. |

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View file

@ -2869,8 +2869,8 @@ ABCs and Protocols for working with I/O
---------------------------------------
.. class:: IO[AnyStr]
TextIO[AnyStr]
BinaryIO[AnyStr]
TextIO
BinaryIO
Generic class ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])``
and ``BinaryIO(IO[bytes])``

View file

@ -388,7 +388,7 @@ type of the target ``e`` is consistently :exc:`BaseExceptionGroup`::
... except* BlockingIOError as e:
... print(repr(e))
...
ExceptionGroup('', (BlockingIOError()))
ExceptionGroup('', (BlockingIOError(),))
:keyword:`break`, :keyword:`continue` and :keyword:`return`
cannot appear in an :keyword:`!except*` clause.

View file

@ -895,7 +895,6 @@ Attribute assignment updates the module's namespace dictionary, e.g.,
single: __loader__ (module attribute)
single: __path__ (module attribute)
single: __file__ (module attribute)
single: __cached__ (module attribute)
single: __doc__ (module attribute)
single: __annotations__ (module attribute)
single: __annotate__ (module attribute)
@ -1044,43 +1043,28 @@ this approach.
instead of :attr:`!module.__path__`.
.. attribute:: module.__file__
.. attribute:: module.__cached__
:attr:`!__file__` and :attr:`!__cached__` are both optional attributes that
:attr:`!__file__` is an optional attribute that
may or may not be set. Both attributes should be a :class:`str` when they
are available.
:attr:`!__file__` indicates the pathname of the file from which the module
was loaded (if loaded from a file), or the pathname of the shared library
file for extension modules loaded dynamically from a shared library.
It might be missing for certain types of modules, such as C modules that are
statically linked into the interpreter, and the
An optional attribute, :attr:`!__file__` indicates the pathname of the file
from which the module was loaded (if loaded from a file), or the pathname of
the shared library file for extension modules loaded dynamically from a
shared library. It might be missing for certain types of modules, such as C
modules that are statically linked into the interpreter, and the
:ref:`import system <importsystem>` may opt to leave it unset if it
has no semantic meaning (for example, a module loaded from a database).
If :attr:`!__file__` is set then the :attr:`!__cached__` attribute might
also be set, which is the path to any compiled version of
the code (for example, a byte-compiled file). The file does not need to exist
to set this attribute; the path can simply point to where the
compiled file *would* exist (see :pep:`3147`).
Note that :attr:`!__cached__` may be set even if :attr:`!__file__` is not
set. However, that scenario is quite atypical. Ultimately, the
:term:`loader` is what makes use of the module spec provided by the
:term:`finder` (from which :attr:`!__file__` and :attr:`!__cached__` are
derived). So if a loader can load from a cached module but otherwise does
not load from a file, that atypical scenario may be appropriate.
It is **strongly** recommended that you use
:attr:`module.__spec__.cached <importlib.machinery.ModuleSpec.cached>`
instead of :attr:`!module.__cached__`.
.. deprecated-removed:: 3.13 3.15
Setting :attr:`!__cached__` on a module while failing to set
Setting ``__cached__`` on a module while failing to set
:attr:`!__spec__.cached` is deprecated. In Python 3.15,
:attr:`!__cached__` will cease to be set or taken into consideration by
``__cached__`` will cease to be set or taken into consideration by
the import system or standard library.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
Other writable attributes on module objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -2656,7 +2640,7 @@ Notes on using *__slots__*:
of the iterator's values. However, the *__slots__* attribute will be an empty
iterator.
.. versionchanged:: next
.. versionchanged:: 3.15
Allowed defining the *__dict__* and *__weakref__* *__slots__* for any class.

View file

@ -1227,7 +1227,7 @@ Whitespace is significant in these situations:
string contents.
* In ``fstring_replacement_field``, if ``f_debug_specifier`` is present,
all whitespace after the opening brace until the ``f_debug_specifier``,
as well as whitespace immediatelly following ``f_debug_specifier``,
as well as whitespace immediately following ``f_debug_specifier``,
is retained as part of the expression.
.. impl-detail::

View file

@ -8,6 +8,12 @@
rel="nofollow">{{ _('Show source') }}
</a>
</li>
{% if language != "en" %}
<li>
<a href="https://github.com/python/python-docs-{{ language }}/blob/{{ version }}/{{ pagename }}.po?plain=1"
rel="nofollow">{{ _('Show translation source') }}</a>
</li>
{% endif %}
</ul>
</div>
{%- endif %}

View file

@ -1039,31 +1039,28 @@ blank, visually separating the summary from the rest of the description. The
following lines should be one or more paragraphs describing the object's calling
conventions, its side effects, etc.
The Python parser does not strip indentation from multi-line string literals in
Python, so tools that process documentation have to strip indentation if
desired. This is done using the following convention. The first non-blank line
*after* the first line of the string determines the amount of indentation for
the entire documentation string. (We can't use the first line since it is
generally adjacent to the string's opening quotes so its indentation is not
apparent in the string literal.) Whitespace "equivalent" to this indentation is
then stripped from the start of all lines of the string. Lines that are
indented less should not occur, but if they occur all their leading whitespace
should be stripped. Equivalence of whitespace should be tested after expansion
of tabs (to 8 spaces, normally).
The Python parser strips indentation from multi-line string literals when they
serve as module, class, or function docstrings.
Here is an example of a multi-line docstring::
>>> def my_function():
... """Do nothing, but document it.
...
... No, really, it doesn't do anything.
... No, really, it doesn't do anything:
...
... >>> my_function()
... >>>
... """
... pass
...
>>> print(my_function.__doc__)
Do nothing, but document it.
No, really, it doesn't do anything.
No, really, it doesn't do anything:
>>> my_function()
>>>
.. _tut-annotations:

View file

@ -344,7 +344,7 @@ General Options
"_tkinter": "Install the python-tk package to use tkinter",
}
.. versionadded:: next
.. versionadded:: 3.15
.. option:: --enable-pystats

View file

@ -1337,7 +1337,7 @@ Deprecated
it was :exc:`ImportWarning`).
(Contributed by Brett Cannon in :gh:`65961`.)
* Setting :attr:`~module.__package__` or :attr:`~module.__cached__` on a
* Setting :attr:`~module.__package__` or ``__cached__`` on a
module is deprecated, and will cease to be set or taken into consideration by
the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.)

View file

@ -73,6 +73,7 @@ Summary -- Release highlights
<whatsnew315-utf8-default>`
* :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object
<whatsnew315-pep782>`
* :ref:`The JIT compiler has been significantly upgraded <whatsnew315-jit>`
* :ref:`Improved error messages <whatsnew315-improved-error-messages>`
@ -146,6 +147,8 @@ Key features include:
and blocking. Use this to identify CPU-bound bottlenecks and optimize computational work.
* **GIL-holding time** (``--mode gil``): Measures time spent holding Python's Global Interpreter
Lock. Use this to identify which threads dominate GIL usage in multi-threaded applications.
* **Exception handling time** (``--mode exception``): Captures samples only from threads with
an active exception. Use this to analyze exception handling overhead.
* **Thread-aware profiling**: Option to profile all threads (``-a``) or just the main thread,
essential for understanding multi-threaded application behavior.
@ -175,6 +178,10 @@ Key features include:
(``--async-aware``). See which coroutines are consuming time, with options to show only
running tasks or all tasks including those waiting.
* **Opcode-level profiling**: Gather bytecode opcode information for instruction-level
profiling (``--opcodes``). Shows which bytecode instructions are executing, including
specializations from the adaptive interpreter.
See :mod:`profiling.sampling` for the complete documentation, including all
available output formats, profiling modes, and configuration options.
@ -417,6 +424,10 @@ argparse
default to ``True``. This enables suggestions for mistyped arguments by default.
(Contributed by Jakob Schluse in :gh:`140450`.)
* Added backtick markup support in description and epilog text to highlight
inline code when color output is enabled.
(Contributed by Savannah Ostrowski in :gh:`142390`.)
calendar
--------
@ -581,6 +592,11 @@ mmap
not be duplicated.
(Contributed by Serhiy Storchaka in :gh:`78502`.)
* Added the :meth:`mmap.mmap.set_name` method
to annotate an anonymous memory mapping
if Linux kernel supports :manpage:`PR_SET_VMA_ANON_NAME <PR_SET_VMA(2const)>` (Linux 5.17 or newer).
(Contributed by Donghee Na in :gh:`142419`.)
os
--
@ -840,6 +856,91 @@ csv
(Contributed by Maurycy Pawłowski-Wieroński in :gh:`137628`.)
.. _whatsnew315-jit:
Upgraded JIT compiler
=====================
Results from the `pyperformance <https://github.com/python/pyperformance>`__
benchmark suite report
`3-4% <https://github.com/facebookexperimental/free-threading-benchmarking/blob/main/results/bm-20251214-3.15.0a2%2B-6cddf04-JIT/bm-20251214-vultr-x86_64-python-6cddf04344a1e8ca9df5-3.15.0a2%2B-6cddf04-vs-base.svg>`__
geometric mean performance improvement for the JIT over the standard CPython
interpreter built with all optimizations enabled. The speedups for JIT
builds versus no JIT builds range from roughly 20% slowdown to over
100% speedup (ignoring the ``unpack_sequence`` microbenchmark) on
x86-64 Linux and AArch64 macOS systems.
.. attention::
These results are not yet final.
The major upgrades to the JIT are:
* LLVM 21 build-time dependency
* New tracing frontend
* Basic register allocation in the JIT
* More JIT optimizations
* Better machine code generation
.. rubric:: LLVM 21 build-time dependency
The JIT compiler now uses LLVM 21 for build-time stencil generation. As
always, LLVM is only needed when building CPython with the JIT enabled;
end users running Python do not need LLVM installed. Instructions for
installing LLVM can be found in the `JIT compiler documentation
<https://github.com/python/cpython/blob/main/Tools/jit/README.md>`__
for all supported platforms.
(Contributed by Savannah Ostrowski in :gh:`140973`.)
.. rubric:: A new tracing frontend
The JIT compiler now supports significantly more bytecode operations and
control flow than in Python 3.14, enabling speedups on a wider variety of
code. For example, simple Python object creation is now understood by the
3.15 JIT compiler. Overloaded operations and generators are also partially
supported. This was made possible by an overhauled JIT tracing frontend
that records actual execution paths through code, rather than estimating
them as the previous implementation did.
(Contributed by Ken Jin in :gh:`139109`. Support for Windows added by
Mark Shannon in :gh:`141703`.)
.. rubric:: Basic register allocation in the JIT
A basic form of register allocation has been added to the JIT compiler's
optimizer. This allows the JIT compiler to avoid certain stack operations
altogether and instead operate on registers. This allows the JIT to produce
more efficient traces by avoiding reads and writes to memory.
(Contributed by Mark Shannon in :gh:`135379`.)
.. rubric:: More JIT optimizations
More `constant-propagation <https://en.wikipedia.org/wiki/Constant_folding>`__
is now performed. This means when the JIT compiler detects that certain user
code results in constants, the code can be simplified by the JIT.
(Contributed by Ken Jin and Savannah Ostrowski in :gh:`132732`.)
The JIT avoids :term:`reference count`\ s where possible. This generally
reduces the cost of most operations in Python.
(Contributed by Ken Jin, Donghee Na, Zheao Li, Savannah Ostrowski,
Noam Cohen, Tomas Roun, PuQing in :gh:`134584`.)
.. rubric:: Better machine code generation
The JIT compiler's machine code generator now produces better machine code
for x86-64 and AArch64 macOS and Linux targets. In general, users should
experience lower memory usage for generated machine code and more efficient
machine code versus the old JIT.
(Contributed by Brandt Bucher in :gh:`136528` and :gh:`136528`.
Implementation for AArch64 contributed by Mark Shannon in :gh:`139855`.
Additional optimizations for AArch64 contributed by Mark Shannon and
Diego Russo in :gh:`140683` and :gh:`142305`.)
Removed
=======
@ -1008,14 +1109,16 @@ New deprecations
* ``__version__``
* The ``__version__`` attribute has been deprecated in these standard library
modules and will be removed in Python 3.20.
Use :py:data:`sys.version_info` instead.
* The ``__version__``, ``version`` and ``VERSION`` attributes have been
deprecated in these standard library modules and will be removed in
Python 3.20. Use :py:data:`sys.version_info` instead.
- :mod:`argparse`
- :mod:`csv`
- :mod:`ctypes`
- :mod:`!ctypes.macholib`
- :mod:`decimal` (use :data:`decimal.SPEC_VERSION` instead)
- :mod:`http.server`
- :mod:`imaplib`
- :mod:`ipaddress`
- :mod:`json`
@ -1028,6 +1131,10 @@ New deprecations
- :mod:`tabnanny`
- :mod:`tkinter.font`
- :mod:`tkinter.ttk`
- :mod:`wsgiref.simple_server`
- :mod:`xml.etree.ElementTree`
- :mod:`!xml.sax.expatreader`
- :mod:`xml.sax.handler`
- :mod:`zlib`
(Contributed by Hugo van Kemenade and Stan Ulbrych in :gh:`76007`.)
@ -1204,6 +1311,13 @@ Deprecated C APIs
use the :c:type:`PyBytesWriter` API instead.
(Contributed by Victor Stinner in :gh:`129813`.)
* :c:func:`!_PyObject_CallMethodId`, :c:func:`!_PyObject_GetAttrId` and
:c:func:`!_PyUnicode_FromId` are deprecated since 3.15 and will be removed in
3.20. Instead, use :c:func:`PyUnicode_InternFromString()` and cache the result in
the module state, then call :c:func:`PyObject_CallMethod` or
:c:func:`PyObject_GetAttr`.
(Contributed by Victor Stinner in :gh:`141049`.)
* Deprecate :c:member:`~PyComplexObject.cval` field of the
:c:type:`PyComplexObject` type.
Use :c:func:`PyComplex_AsCComplex` and :c:func:`PyComplex_FromCComplex`

View file

@ -312,7 +312,7 @@ cluttering source directories, the *pyc* files are now collected in a
Aside from the filenames and target directories, the new scheme has a few
aspects that are visible to the programmer:
* Imported modules now have a :attr:`~module.__cached__` attribute which stores
* Imported modules now have a ``__cached__`` attribute which stores
the name of the actual file that was imported:
>>> import collections

View file

@ -1251,8 +1251,7 @@ invalid_expression:
# !(NAME STRING) is not matched so we don't show this error with some invalid string prefixes like: kf"dsfsdf"
# Soft keywords need to also be ignored because they can be parsed as NAME NAME
| !(NAME STRING | SOFT_KEYWORD) a=disjunction b=expression_without_invalid {
_PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL :
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") }
_PyPegen_raise_error_for_missing_comma(p, a, b) }
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
| a=disjunction 'if' b=disjunction 'else' !expression {
RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("expected expression after 'else', but statement is given") }

View file

@ -6,7 +6,7 @@
/* Like PyObject_CallMethod(), but expect a _Py_Identifier*
as the method name. */
PyAPI_FUNC(PyObject*) _PyObject_CallMethodId(
Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyObject_CallMethodId(
PyObject *obj,
_Py_Identifier *name,
const char *format, ...);

View file

@ -300,7 +300,7 @@ PyAPI_FUNC(void) PyUnstable_Object_Dump(PyObject *);
// Alias for backward compatibility
#define _PyObject_Dump PyUnstable_Object_Dump
PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
PyAPI_FUNC(void) PyObject_CallFinalizer(PyObject *);

View file

@ -591,6 +591,17 @@ static inline void _Py_atomic_fence_release(void);
// --- aliases ---------------------------------------------------------------
// Compilers don't really support "consume" semantics, so we fake it. Use
// "acquire" with TSan to support false positives. Use "relaxed" otherwise,
// because CPUs on all platforms we support respect address dependencies without
// extra barriers.
// See 2.6.7 in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf
#if defined(_Py_THREAD_SANITIZER)
# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_acquire
#else
# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_relaxed
#endif
#if SIZEOF_LONG == 8
# define _Py_atomic_load_ulong(p) \
_Py_atomic_load_uint64((uint64_t *)p)

View file

@ -778,4 +778,4 @@ static inline int Py_UNICODE_ISALNUM(Py_UCS4 ch) {
// Return an interned Unicode object for an Identifier; may fail if there is no
// memory.
PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*);
Py_DEPRECATED(3.15) PyAPI_FUNC(PyObject*) _PyUnicode_FromId(_Py_Identifier*);

View file

@ -377,8 +377,6 @@ _Py_eval_breaker_bit_is_set(PyThreadState *tstate, uintptr_t bit)
void _Py_set_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit);
void _Py_unset_eval_breaker_bit_all(PyInterpreterState *interp, uintptr_t bit);
PyAPI_FUNC(_PyStackRef) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyStackRef right, double value);
#ifndef Py_SUPPORTS_REMOTE_DEBUG
#if defined(__APPLE__)
#include <TargetConditionals.h>

View file

@ -55,5 +55,8 @@ struct _pycontexttokenobject {
// Export for '_testcapi' shared extension
PyAPI_FUNC(PyObject*) _PyContext_NewHamtForTests(void);
PyAPI_FUNC(int) _PyContext_Enter(PyThreadState *ts, PyObject *octx);
PyAPI_FUNC(int) _PyContext_Exit(PyThreadState *ts, PyObject *octx);
#endif /* !Py_INTERNAL_CONTEXT_H */

View file

@ -110,8 +110,15 @@ typedef struct _Py_DebugOffsets {
uint64_t status;
uint64_t holds_gil;
uint64_t gil_requested;
uint64_t current_exception;
uint64_t exc_state;
} thread_state;
// Exception stack item offset
struct {
uint64_t exc_value;
} err_stackitem;
// InterpreterFrame offset;
struct _interpreter_frame {
uint64_t size;
@ -282,6 +289,11 @@ typedef struct _Py_DebugOffsets {
.status = offsetof(PyThreadState, _status), \
.holds_gil = offsetof(PyThreadState, holds_gil), \
.gil_requested = offsetof(PyThreadState, gil_requested), \
.current_exception = offsetof(PyThreadState, current_exception), \
.exc_state = offsetof(PyThreadState, exc_state), \
}, \
.err_stackitem = { \
.exc_value = offsetof(_PyErr_StackItem, exc_value), \
}, \
.interpreter_frame = { \
.size = sizeof(_PyInterpreterFrame), \

View file

@ -1994,6 +1994,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readline));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(readonly));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(real));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(recursive));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(reducer_override));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(registry));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(rel_tol));

View file

@ -717,6 +717,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(readline)
STRUCT_FOR_ID(readonly)
STRUCT_FOR_ID(real)
STRUCT_FOR_ID(recursive)
STRUCT_FOR_ID(reducer_override)
STRUCT_FOR_ID(registry)
STRUCT_FOR_ID(rel_tol)

View file

@ -17,25 +17,27 @@ extern "C" {
#endif
#if defined(HAVE_PR_SET_VMA_ANON_NAME) && defined(__linux__)
static inline void
static inline int
_PyAnnotateMemoryMap(void *addr, size_t size, const char *name)
{
#ifndef Py_DEBUG
if (!_Py_GetConfig()->dev_mode) {
return;
return 0;
}
#endif
// The name length cannot exceed 80 (including the '\0').
assert(strlen(name) < 80);
int old_errno = errno;
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name);
/* Ignore errno from prctl */
/* See: https://bugzilla.redhat.com/show_bug.cgi?id=2302746 */
errno = old_errno;
int res = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)addr, size, name);
if (res < 0) {
return -1;
}
return 0;
}
#else
static inline void
static inline int
_PyAnnotateMemoryMap(void *Py_UNUSED(addr), size_t Py_UNUSED(size), const char *Py_UNUSED(name))
{
return 0;
}
#endif

View file

@ -496,6 +496,9 @@ static inline void Py_DECREF_MORTAL_SPECIALIZED(PyObject *op, destructor destruc
#define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF_MORTAL_SPECIALIZED(_PyObject_CAST(op), destruct)
#endif
#else // Py_GIL_DISABLED
# define Py_DECREF_MORTAL(op) Py_DECREF(op)
# define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF(op)
#endif
/* Inline functions trading binary compatibility for speed:
@ -1045,6 +1048,8 @@ static inline Py_ALWAYS_INLINE void _Py_INCREF_MORTAL(PyObject *op)
}
#endif
}
#else
# define _Py_INCREF_MORTAL(op) Py_INCREF(op)
#endif
/* Utility for the tp_traverse slot of mutable heap types that have no other

View file

@ -1079,12 +1079,12 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[267];
#ifdef NEED_OPCODE_METADATA
const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[BINARY_OP] = { true, INSTR_FMT_IBC0000, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
[BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
@ -1092,7 +1092,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[BINARY_OP_SUBSCR_LIST_SLICE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_TUPLE_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG },
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
[BINARY_SLICE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BUILD_INTERPOLATION] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1111,7 +1111,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_FUNCTION_EX] = { true, INSTR_FMT_IX, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_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 },
@ -1121,7 +1121,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[CALL_KW_NON_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_KW_PY] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_LEN] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1129,8 +1129,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[CHECK_EG_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CHECK_EXC_MATCH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
@ -1329,21 +1329,21 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];
const struct opcode_macro_expansion
_PyOpcode_macro_expansion[256] = {
[BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 } } },
[BINARY_OP_ADD_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_UNICODE] = { .nuops = 5, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } },
[BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_STR_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_TUPLE_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_TUPLE, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_TUPLE_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBTRACT_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBTRACT_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBTRACT_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_SLICE] = { .nuops = 1, .uops = { { _BINARY_SLICE, OPARG_SIMPLE, 0 } } },
[BUILD_INTERPOLATION] = { .nuops = 1, .uops = { { _BUILD_INTERPOLATION, OPARG_SIMPLE, 0 } } },
[BUILD_LIST] = { .nuops = 1, .uops = { { _BUILD_LIST, OPARG_SIMPLE, 0 } } },
@ -1359,15 +1359,15 @@ _PyOpcode_macro_expansion[256] = {
[CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_O] = { .nuops = 2, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 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 = 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_AT_END, OPARG_REPLACED, 3 } } },
[CALL_KW_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_LEN] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 } } },
[CALL_LIST_APPEND] = { .nuops = 4, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } },
[CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[CALL_LIST_APPEND] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
@ -1375,14 +1375,14 @@ _PyOpcode_macro_expansion[256] = {
[CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_PY_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_PY_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_STR_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_TUPLE_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_STR_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_TUPLE_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_TYPE_1] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TYPE_1, OPARG_SIMPLE, 3 }, { _CALL_TYPE_1, OPARG_SIMPLE, 3 } } },
[CHECK_EG_MATCH] = { .nuops = 1, .uops = { { _CHECK_EG_MATCH, OPARG_SIMPLE, 0 } } },
[CHECK_EXC_MATCH] = { .nuops = 1, .uops = { { _CHECK_EXC_MATCH, OPARG_SIMPLE, 0 } } },
[COMPARE_OP] = { .nuops = 1, .uops = { { _COMPARE_OP, OPARG_SIMPLE, 0 } } },
[COMPARE_OP_FLOAT] = { .nuops = 3, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_FLOAT, OPARG_SIMPLE, 1 } } },
[COMPARE_OP_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_INT, OPARG_SIMPLE, 1 } } },
[COMPARE_OP_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _COMPARE_OP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 } } },
[COMPARE_OP_STR] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _COMPARE_OP_STR, OPARG_SIMPLE, 1 } } },
[CONTAINS_OP] = { .nuops = 1, .uops = { { _CONTAINS_OP, OPARG_SIMPLE, 0 } } },
[CONTAINS_OP_DICT] = { .nuops = 2, .uops = { { _GUARD_TOS_DICT, OPARG_SIMPLE, 0 }, { _CONTAINS_OP_DICT, OPARG_SIMPLE, 1 } } },
@ -1425,7 +1425,7 @@ _PyOpcode_macro_expansion[256] = {
[LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, OPARG_SIMPLE, 8 } } },
[LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 5, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
@ -1482,9 +1482,9 @@ _PyOpcode_macro_expansion[256] = {
[SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { _SET_FUNCTION_ATTRIBUTE, OPARG_SIMPLE, 0 } } },
[SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, OPARG_SIMPLE, 0 } } },
[STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, OPARG_SIMPLE, 3 } } },
[STORE_ATTR_INSTANCE_VALUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 } } },
[STORE_ATTR_SLOT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 } } },
[STORE_ATTR_WITH_HINT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 } } },
[STORE_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, OPARG_SIMPLE, 0 } } },
[STORE_FAST] = { .nuops = 1, .uops = { { _STORE_FAST, OPARG_SIMPLE, 0 } } },
[STORE_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _STORE_FAST, OPARG_TOP, 0 }, { _LOAD_FAST, OPARG_BOTTOM, 0 } } },
@ -1493,8 +1493,8 @@ _PyOpcode_macro_expansion[256] = {
[STORE_NAME] = { .nuops = 1, .uops = { { _STORE_NAME, OPARG_SIMPLE, 0 } } },
[STORE_SLICE] = { .nuops = 1, .uops = { { _STORE_SLICE, OPARG_SIMPLE, 0 } } },
[STORE_SUBSCR] = { .nuops = 1, .uops = { { _STORE_SUBSCR, OPARG_SIMPLE, 0 } } },
[STORE_SUBSCR_DICT] = { .nuops = 2, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 } } },
[STORE_SUBSCR_LIST_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 } } },
[STORE_SUBSCR_DICT] = { .nuops = 3, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_DICT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } },
[STORE_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } },
[SWAP] = { .nuops = 1, .uops = { { _SWAP, OPARG_SIMPLE, 0 } } },
[TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, OPARG_SIMPLE, 2 } } },
[TO_BOOL_ALWAYS_TRUE] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 } } },

View file

@ -31,6 +31,8 @@ extern "C" {
_Py_atomic_store_ptr(&value, new_value)
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) \
_Py_atomic_load_ptr_acquire(&value)
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) \
_Py_atomic_load_ptr_consume(&value)
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \
_Py_atomic_load_uintptr_acquire(&value)
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) \
@ -55,6 +57,8 @@ extern "C" {
_Py_atomic_store_uintptr_release(&value, new_value)
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
_Py_atomic_store_ssize_relaxed(&value, new_value)
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \
_Py_atomic_store_ssize_release(&value, new_value)
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) \
_Py_atomic_store_uint8_relaxed(&value, new_value)
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) \
@ -125,6 +129,7 @@ extern "C" {
#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) value
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) value
#define FT_ATOMIC_LOAD_UINT8(value) value
@ -137,6 +142,7 @@ extern "C" {
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value

View file

@ -1992,6 +1992,7 @@ extern "C" {
INIT_ID(readline), \
INIT_ID(readonly), \
INIT_ID(real), \
INIT_ID(recursive), \
INIT_ID(reducer_override), \
INIT_ID(registry), \
INIT_ID(rel_tol), \

View file

@ -452,184 +452,6 @@ PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref)
return (_PyStackRef){ .bits = ref.bits + (1 << Py_TAGGED_SHIFT) };
}
#define PyStackRef_IsDeferredOrTaggedInt(ref) (((ref).bits & Py_TAG_REFCNT) != 0)
#ifdef Py_GIL_DISABLED
#define Py_TAG_DEFERRED Py_TAG_REFCNT
#define Py_TAG_PTR ((uintptr_t)0)
static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
#define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits)
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED })
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED })
#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_DEFERRED })
// Checks that mask out the deferred bit in the free threading build.
#define PyStackRef_IsNone(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_None)
#define PyStackRef_IsTrue(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_True)
#define PyStackRef_IsFalse(ref) (PyStackRef_AsPyObjectBorrow(ref) == Py_False)
#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref))
static inline PyObject *
PyStackRef_AsPyObjectBorrow(_PyStackRef stackref)
{
assert(!PyStackRef_IsTaggedInt(stackref));
PyObject *cleared = ((PyObject *)((stackref).bits & (~Py_TAG_BITS)));
return cleared;
}
#define PyStackRef_IsDeferred(ref) (((ref).bits & Py_TAG_BITS) == Py_TAG_DEFERRED)
static inline PyObject *
PyStackRef_AsPyObjectSteal(_PyStackRef stackref)
{
assert(!PyStackRef_IsNull(stackref));
if (PyStackRef_IsDeferred(stackref)) {
return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref));
}
return PyStackRef_AsPyObjectBorrow(stackref);
}
static inline _PyStackRef
_PyStackRef_FromPyObjectSteal(PyObject *obj)
{
assert(obj != NULL);
// Make sure we don't take an already tagged value.
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
return (_PyStackRef){ .bits = (uintptr_t)obj };
}
# define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj))
static inline bool
PyStackRef_IsHeapSafe(_PyStackRef stackref)
{
if (PyStackRef_IsDeferred(stackref)) {
PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref);
return obj == NULL || _Py_IsImmortal(obj) || _PyObject_HasDeferredRefcount(obj);
}
return true;
}
static inline _PyStackRef
PyStackRef_MakeHeapSafe(_PyStackRef stackref)
{
if (PyStackRef_IsHeapSafe(stackref)) {
return stackref;
}
PyObject *obj = PyStackRef_AsPyObjectBorrow(stackref);
return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR };
}
static inline _PyStackRef
PyStackRef_FromPyObjectStealMortal(PyObject *obj)
{
assert(obj != NULL);
assert(!_Py_IsImmortal(obj));
// Make sure we don't take an already tagged value.
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
return (_PyStackRef){ .bits = (uintptr_t)obj };
}
static inline _PyStackRef
PyStackRef_FromPyObjectNew(PyObject *obj)
{
// Make sure we don't take an already tagged value.
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
assert(obj != NULL);
if (_PyObject_HasDeferredRefcount(obj)) {
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED };
}
else {
return (_PyStackRef){ .bits = (uintptr_t)(Py_NewRef(obj)) | Py_TAG_PTR };
}
}
#define PyStackRef_FromPyObjectNew(obj) PyStackRef_FromPyObjectNew(_PyObject_CAST(obj))
static inline _PyStackRef
PyStackRef_FromPyObjectBorrow(PyObject *obj)
{
// Make sure we don't take an already tagged value.
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
assert(obj != NULL);
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_DEFERRED };
}
#define PyStackRef_FromPyObjectBorrow(obj) PyStackRef_FromPyObjectBorrow(_PyObject_CAST(obj))
#define PyStackRef_CLOSE(REF) \
do { \
_PyStackRef _close_tmp = (REF); \
assert(!PyStackRef_IsNull(_close_tmp)); \
if (!PyStackRef_IsDeferredOrTaggedInt(_close_tmp)) { \
Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \
} \
} while (0)
static inline void
PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct)
{
(void)destruct;
PyStackRef_CLOSE(ref);
}
static inline int
PyStackRef_RefcountOnObject(_PyStackRef ref)
{
return (ref.bits & Py_TAG_REFCNT) == 0;
}
static inline _PyStackRef
PyStackRef_DUP(_PyStackRef stackref)
{
assert(!PyStackRef_IsNull(stackref));
if (PyStackRef_IsDeferredOrTaggedInt(stackref)) {
return stackref;
}
Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref));
return stackref;
}
static inline _PyStackRef
PyStackRef_Borrow(_PyStackRef stackref)
{
return (_PyStackRef){ .bits = stackref.bits | Py_TAG_DEFERRED };
}
// Convert a possibly deferred reference to a strong reference.
static inline _PyStackRef
PyStackRef_AsStrongReference(_PyStackRef stackref)
{
return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref));
}
#define PyStackRef_XCLOSE(stackref) \
do { \
_PyStackRef _tmp = (stackref); \
if (!PyStackRef_IsNull(_tmp)) { \
PyStackRef_CLOSE(_tmp); \
} \
} while (0);
#define PyStackRef_CLEAR(op) \
do { \
_PyStackRef *_tmp_op_ptr = &(op); \
_PyStackRef _tmp_old_op = (*_tmp_op_ptr); \
if (!PyStackRef_IsNull(_tmp_old_op)) { \
*_tmp_op_ptr = PyStackRef_NULL; \
PyStackRef_CLOSE(_tmp_old_op); \
} \
} while (0)
#define PyStackRef_FromPyObjectNewMortal PyStackRef_FromPyObjectNew
#else // Py_GIL_DISABLED
// With GIL
/* References to immortal objects always have their tag bit set to Py_TAG_REFCNT
* as they can (must) have their reclamation deferred */
@ -648,13 +470,24 @@ static const _PyStackRef PyStackRef_NULL = { .bits = PyStackRef_NULL_BITS };
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT })
#define PyStackRef_None ((_PyStackRef){.bits = ((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT })
#ifdef Py_GIL_DISABLED
// Checks that mask out the deferred bit in the free threading build.
#define PyStackRef_IsNone(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_NoneStruct)
#define PyStackRef_IsTrue(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_TrueStruct)
#define PyStackRef_IsFalse(REF) (((REF).bits & ~Py_TAG_REFCNT) == (uintptr_t)&_Py_FalseStruct)
#else
#define PyStackRef_IsTrue(REF) ((REF).bits == (((uintptr_t)&_Py_TrueStruct) | Py_TAG_REFCNT))
#define PyStackRef_IsFalse(REF) ((REF).bits == (((uintptr_t)&_Py_FalseStruct) | Py_TAG_REFCNT))
#define PyStackRef_IsNone(REF) ((REF).bits == (((uintptr_t)&_Py_NoneStruct) | Py_TAG_REFCNT))
#endif
#ifdef Py_DEBUG
#define PyStackRef_IsNullOrInt(stackref) (PyStackRef_IsNull(stackref) || PyStackRef_IsTaggedInt(stackref))
static inline void PyStackRef_CheckValid(_PyStackRef ref) {
#if defined(Py_DEBUG) && !defined(Py_GIL_DISABLED)
static inline void
PyStackRef_CheckValid(_PyStackRef ref)
{
assert(ref.bits != 0);
int tag = ref.bits & Py_TAG_BITS;
PyObject *obj = BITS_TO_PTR_MASKED(ref);
@ -705,6 +538,8 @@ PyStackRef_Borrow(_PyStackRef ref)
static inline PyObject *
PyStackRef_AsPyObjectSteal(_PyStackRef ref)
{
assert(!PyStackRef_IsNull(ref));
assert(!PyStackRef_IsTaggedInt(ref));
if (PyStackRef_RefcountOnObject(ref)) {
return BITS_TO_PTR(ref);
}
@ -717,14 +552,18 @@ static inline _PyStackRef
PyStackRef_FromPyObjectSteal(PyObject *obj)
{
assert(obj != NULL);
#if SIZEOF_VOID_P > 4
unsigned int tag = obj->ob_flags & Py_TAG_REFCNT;
#ifdef Py_GIL_DISABLED
return (_PyStackRef){ .bits = (uintptr_t)obj };
#else
# if SIZEOF_VOID_P > 4
unsigned int tag = obj->ob_flags & Py_TAG_REFCNT;
# else
unsigned int tag = _Py_IsImmortal(obj) ? Py_TAG_REFCNT : 0;
#endif
# endif
_PyStackRef ref = ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag});
PyStackRef_CheckValid(ref);
return ref;
#endif
}
static inline _PyStackRef
@ -732,7 +571,7 @@ PyStackRef_FromPyObjectStealMortal(PyObject *obj)
{
assert(obj != NULL);
assert(!_Py_IsImmortal(obj));
_PyStackRef ref = ((_PyStackRef){.bits = ((uintptr_t)(obj)) });
_PyStackRef ref = (_PyStackRef){ .bits = (uintptr_t)obj };
PyStackRef_CheckValid(ref);
return ref;
}
@ -741,9 +580,15 @@ static inline _PyStackRef
_PyStackRef_FromPyObjectNew(PyObject *obj)
{
assert(obj != NULL);
if (_Py_IsImmortal(obj)) {
return (_PyStackRef){ .bits = ((uintptr_t)obj) | Py_TAG_REFCNT};
#ifdef Py_GIL_DISABLED
if (_PyObject_HasDeferredRefcount(obj)) {
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT };
}
#else
if (_Py_IsImmortal(obj)) {
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT };
}
#endif
_Py_INCREF_MORTAL(obj);
_PyStackRef ref = (_PyStackRef){ .bits = (uintptr_t)obj };
PyStackRef_CheckValid(ref);
@ -766,6 +611,7 @@ _PyStackRef_FromPyObjectNewMortal(PyObject *obj)
static inline _PyStackRef
PyStackRef_FromPyObjectBorrow(PyObject *obj)
{
assert(obj != NULL);
return (_PyStackRef){ .bits = (uintptr_t)obj | Py_TAG_REFCNT};
}
@ -788,7 +634,15 @@ PyStackRef_DUP(_PyStackRef ref)
static inline bool
PyStackRef_IsHeapSafe(_PyStackRef ref)
{
return (ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT || ref.bits == PyStackRef_NULL_BITS || _Py_IsImmortal(BITS_TO_PTR_MASKED(ref));
#ifdef Py_GIL_DISABLED
if ((ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT) {
return true;
}
PyObject *obj = BITS_TO_PTR_MASKED(ref);
return obj == NULL || _PyObject_HasDeferredRefcount(obj);
#else
return (ref.bits & Py_TAG_BITS) != Py_TAG_REFCNT || ref.bits == PyStackRef_NULL_BITS || _Py_IsImmortal(BITS_TO_PTR_MASKED(ref));
#endif
}
static inline _PyStackRef
@ -804,6 +658,13 @@ PyStackRef_MakeHeapSafe(_PyStackRef ref)
return ref;
}
// Convert a possibly deferred reference to a strong reference.
static inline _PyStackRef
PyStackRef_AsStrongReference(_PyStackRef stackref)
{
return PyStackRef_FromPyObjectSteal(PyStackRef_AsPyObjectSteal(stackref));
}
#ifdef _WIN32
#define PyStackRef_CLOSE(REF) \
do { \
@ -821,12 +682,6 @@ PyStackRef_CLOSE(_PyStackRef ref)
}
#endif
static inline bool
PyStackRef_IsNullOrInt(_PyStackRef ref)
{
return PyStackRef_IsNull(ref) || PyStackRef_IsTaggedInt(ref);
}
static inline void
PyStackRef_CLOSE_SPECIALIZED(_PyStackRef ref, destructor destruct)
{
@ -859,8 +714,6 @@ PyStackRef_XCLOSE(_PyStackRef ref)
} while (0)
#endif // Py_GIL_DISABLED
// Note: this is a macro because MSVC (Windows) has trouble inlining it.
#define PyStackRef_Is(a, b) (((a).bits & (~Py_TAG_REFCNT)) == ((b).bits & (~Py_TAG_REFCNT)))
@ -945,7 +798,7 @@ static inline int
_Py_TryIncrefCompareStackRef(PyObject **src, PyObject *op, _PyStackRef *out)
{
if (_PyObject_HasDeferredRefcount(op)) {
*out = (_PyStackRef){ .bits = (uintptr_t)op | Py_TAG_DEFERRED };
*out = (_PyStackRef){ .bits = (uintptr_t)op | Py_TAG_REFCNT };
return 1;
}
if (_Py_TryIncrefCompare(src, op)) {

View file

@ -2648,6 +2648,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(recursive);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(reducer_override);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -24,10 +24,10 @@
#define PY_MINOR_VERSION 15
#define PY_MICRO_VERSION 0
#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA
#define PY_RELEASE_SERIAL 2
#define PY_RELEASE_SERIAL 3
/* Version as a string */
#define PY_VERSION "3.15.0a2+"
#define PY_VERSION "3.15.0a3+"
/*--end constants--*/

View file

@ -11,6 +11,11 @@ it is not, please report that through the
[issue tracker](https://github.com/python/cpython/issues).
General Resources
---
- [Source Code Structure](structure.md)
Compiling Python Source Code
---
@ -29,8 +34,6 @@ Runtime Objects
- [Frames](frames.md)
- [String Interning](string_interning.md)
Program Execution
---
@ -48,6 +51,14 @@ Program Execution
- [Stack protection](stack_protection.md)
Built-in Types
---
- [String Interning](string_interning.md)
- [List sort algorithm](../Objects/listsort.txt)
<!-- (kept at the original location outside this directory) -->
Modules
---

View file

@ -226,10 +226,11 @@ Up through 3.10, the call stack was implemented as a singly-linked list of
heap allocation for the stack frame.
Since 3.11, frames are no longer fully-fledged objects. Instead, a leaner internal
`_PyInterpreterFrame` structure is used, which is allocated using a custom allocator
function (`_PyThreadState_BumpFramePointer()`), which allocates and initializes a
frame structure. Usually a frame allocation is just a pointer bump, which improves
memory locality.
`_PyInterpreterFrame` structure is used. Most frames are allocated contiguously in a
per-thread stack (see `_PyThreadState_PushFrame` in [Python/pystate.c](../Python/pystate.c)),
which improves memory locality and reduces overhead.
If the current `datastack_chunk` has enough space (`_PyThreadState_HasStackSpace`)
then the lightweight `_PyFrame_PushUnchecked` can be used instead of `_PyThreadState_PushFrame`.
Sometimes an actual `PyFrameObject` is needed, such as when Python code calls
`sys._getframe()` or an extension module calls

View file

@ -64,7 +64,6 @@ these values. Type checks use `PyStackRef_IsTaggedInt` and `PyStackRef_LongCheck
## Free threading considerations
With `Py_GIL_DISABLED`, `Py_TAG_DEFERRED` is an alias for `Py_TAG_REFCNT`.
Objects that support deferred reference counting can be pushed to the evaluation
stack and stored in local variables without directly incrementing the reference
count because they are only freed during cyclic garbage collection. This avoids

40
InternalDocs/structure.md Normal file
View file

@ -0,0 +1,40 @@
# CPython source code
This section gives an overview of CPython's code structure and provides
a summary of file locations for modules and built-ins.
## Source code layout
For a Python module, the typical layout is:
* `Lib/<module>.py`
* `Modules/_<module>.c` (if there's also a C accelerator module)
* `Lib/test/test_<module>.py`
* `Doc/library/<module>.rst`
For an extension module, the typical layout is:
* `Modules/<module>module.c`
* `Lib/test/test_<module>.py`
* `Doc/library/<module>.rst`
For builtin types, the typical layout is:
* `Objects/<builtin>object.c`
* `Lib/test/test_<builtin>.py`
* [`Doc/library/stdtypes.rst`](../Doc/library/stdtypes.rst)
For builtin functions, the typical layout is:
* [`Python/bltinmodule.c`](../Python/bltinmodule.c)
* [`Lib/test/test_builtin.py`](../Lib/test/test_builtin.py)
* [`Doc/library/functions.rst`](../Doc/library/functions.rst)
Some exceptions to these layouts are:
* built-in type `int` is at [`Objects/longobject.c`](../Objects/longobject.c)
* built-in type `str` is at [`Objects/unicodeobject.c`](../Objects/unicodeobject.c)
* built-in module `sys` is at [`Python/sysmodule.c`](../Python/sysmodule.c)
* built-in module `marshal` is at [`Python/marshal.c`](../Python/marshal.c)
* Windows-only module `winreg` is at [`PC/winreg.c`](../PC/winreg.c)

View file

@ -169,7 +169,7 @@ class Argparse(ThemeSection):
label: str = ANSIColors.BOLD_YELLOW
action: str = ANSIColors.BOLD_GREEN
default: str = ANSIColors.GREY
default_value: str = ANSIColors.YELLOW
interpolated_value: str = ANSIColors.YELLOW
reset: str = ANSIColors.RESET
error: str = ANSIColors.BOLD_MAGENTA
warning: str = ANSIColors.BOLD_YELLOW

View file

@ -517,7 +517,27 @@ class HelpFormatter(object):
text = text % dict(prog=self._prog)
text_width = max(self._width - self._current_indent, 11)
indent = ' ' * self._current_indent
return self._fill_text(text, text_width, indent) + '\n\n'
text = self._fill_text(text, text_width, indent)
text = self._apply_text_markup(text)
return text + '\n\n'
def _apply_text_markup(self, text):
"""Apply color markup to text.
Supported markup:
`...` - inline code (rendered with prog_extra color)
When colors are disabled, backticks are preserved as-is.
"""
t = self._theme
if not t.reset:
return text
text = _re.sub(
r'`([^`]+)`',
rf'{t.prog_extra}\1{t.reset}',
text,
)
return text
def _format_action(self, action):
# determine the required width and the entry label
@ -668,6 +688,10 @@ class HelpFormatter(object):
params[name] = value.__name__
if params.get('choices') is not None:
params['choices'] = ', '.join(map(str, params['choices']))
# Before interpolating, wrap the values with color codes
t = self._theme
for name, value in params.items():
params[name] = f"{t.interpolated_value}{value}{t.reset}"
return help_string % params
def _iter_indented_subactions(self, action):
@ -749,8 +773,8 @@ class ArgumentDefaultsHelpFormatter(HelpFormatter):
default_str = _(" (default: %(default)s)")
prefix, suffix = default_str.split("%(default)s")
help += (
f" {t.default}{prefix.lstrip()}"
f"{t.default_value}%(default)s"
f" {t.default}{prefix.lstrip()}{t.reset}"
f"%(default)s"
f"{t.default}{suffix}{t.reset}"
)
return help

View file

@ -240,4 +240,5 @@ if __name__ == '__main__':
break
console.write('exiting asyncio REPL...\n')
loop.close()
sys.exit(return_code)

View file

@ -5,12 +5,9 @@ import sys as _sys
import sysconfig as _sysconfig
import types as _types
__version__ = "1.1.0"
from _ctypes import Union, Structure, Array
from _ctypes import _Pointer
from _ctypes import CFuncPtr as _CFuncPtr
from _ctypes import __version__ as _ctypes_version
from _ctypes import RTLD_LOCAL, RTLD_GLOBAL
from _ctypes import ArgumentError
from _ctypes import SIZEOF_TIME_T
@ -18,9 +15,6 @@ from _ctypes import CField
from struct import calcsize as _calcsize
if __version__ != _ctypes_version:
raise Exception("Version number mismatch", __version__, _ctypes_version)
if _os.name == "nt":
from _ctypes import COMError, CopyComPointer, FormatError
@ -673,3 +667,12 @@ else:
raise SystemError(f"Unexpected sizeof(time_t): {SIZEOF_TIME_T=}")
_reset_cache()
def __getattr__(name):
if name == "__version__":
from warnings import _deprecated
_deprecated("__version__", remove=(3, 20))
return "1.1.0" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

View file

@ -878,6 +878,12 @@ class MessageID(MsgID):
class InvalidMessageID(MessageID):
token_type = 'invalid-message-id'
class MessageIDList(TokenList):
token_type = 'message-id-list'
@property
def message_ids(self):
return [x for x in self if x.token_type=='msg-id']
class Header(TokenList):
token_type = 'header'
@ -2175,6 +2181,32 @@ def parse_message_id(value):
return message_id
def parse_message_ids(value):
"""in-reply-to = "In-Reply-To:" 1*msg-id CRLF
references = "References:" 1*msg-id CRLF
"""
message_id_list = MessageIDList()
while value:
if value[0] == ',':
# message id list separated with commas - this is invalid,
# but happens rather frequently in the wild
message_id_list.defects.append(
errors.InvalidHeaderDefect("comma in msg-id list"))
message_id_list.append(
WhiteSpaceTerminal(' ', 'invalid-comma-replacement'))
value = value[1:]
continue
try:
token, value = get_msg_id(value)
message_id_list.append(token)
except errors.HeaderParseError as ex:
token = get_unstructured(value)
message_id_list.append(InvalidMessageID(token))
message_id_list.defects.append(
errors.InvalidHeaderDefect("Invalid msg-id: {!r}".format(ex)))
break
return message_id_list
#
# XXX: As I begin to add additional header parsers, I'm realizing we probably
# have two level of parser routines: the get_XXX methods that get a token in

View file

@ -534,6 +534,18 @@ class MessageIDHeader:
kwds['defects'].extend(parse_tree.all_defects)
class ReferencesHeader:
max_count = 1
value_parser = staticmethod(parser.parse_message_ids)
@classmethod
def parse(cls, value, kwds):
kwds['parse_tree'] = parse_tree = cls.value_parser(value)
kwds['decoded'] = str(parse_tree)
kwds['defects'].extend(parse_tree.all_defects)
# The header factory #
_default_header_map = {
@ -557,6 +569,8 @@ _default_header_map = {
'content-disposition': ContentDispositionHeader,
'content-transfer-encoding': ContentTransferEncodingHeader,
'message-id': MessageIDHeader,
'in-reply-to': ReferencesHeader,
'references': ReferencesHeader,
}
class HeaderRegistry:

View file

@ -171,6 +171,7 @@ class HMAC:
# Call __new__ directly to avoid the expensive __init__.
other = self.__class__.__new__(self.__class__)
other.digest_size = self.digest_size
other.block_size = self.block_size
if self._hmac:
other._hmac = self._hmac.copy()
other._inner = other._outer = None

View file

@ -61,8 +61,6 @@ XXX To do:
# (Actually, the latter is only true if you know the server configuration
# at the time the request was made!)
__version__ = "0.6"
__all__ = [
"HTTPServer", "ThreadingHTTPServer",
"HTTPSServer", "ThreadingHTTPSServer",
@ -280,7 +278,7 @@ class BaseHTTPRequestHandler(socketserver.StreamRequestHandler):
# The server software version. You may want to override this.
# The format is multiple whitespace-separated strings,
# where each string is of the form name[/version].
server_version = "BaseHTTP/" + __version__
server_version = "BaseHTTP"
error_message_format = DEFAULT_ERROR_MESSAGE
error_content_type = DEFAULT_ERROR_CONTENT_TYPE
@ -690,7 +688,7 @@ class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
"""
server_version = "SimpleHTTP/" + __version__
server_version = "SimpleHTTP"
index_pages = ("index.html", "index.htm")
extensions_map = _encodings_map_default = {
'.gz': 'application/gzip',
@ -1080,5 +1078,14 @@ def _main(args=None):
)
def __getattr__(name):
if name == "__version__":
from warnings import _deprecated
_deprecated("__version__", remove=(3, 20))
return "0.6" # Do not change
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
if __name__ == '__main__':
_main()

View file

@ -97,6 +97,11 @@ def reload(module):
The module must have been successfully imported before.
"""
# If a LazyModule has not yet been materialized, reload is a no-op.
if importlib_util := sys.modules.get('importlib.util'):
if lazy_module_type := getattr(importlib_util, '_LazyModule', None):
if isinstance(module, lazy_module_type):
return module
try:
name = module.__spec__.name
except AttributeError:

View file

@ -565,8 +565,7 @@ class ModuleSpec:
`has_location` indicates that a spec's "origin" reflects a location.
When this is True, `__file__` attribute of the module is set.
`cached` is the location of the cached bytecode file, if any. It
corresponds to the `__cached__` attribute.
`cached` is the location of the cached bytecode file, if any.
`submodule_search_locations` is the sequence of path entries to
search when importing submodules. If set, is_package should be
@ -699,10 +698,6 @@ def _spec_from_module(module, loader=None, origin=None):
origin = getattr(loader, '_ORIGIN', None)
if not origin and location is not None:
origin = location
try:
cached = module.__cached__
except AttributeError:
cached = None
try:
submodule_search_locations = list(module.__path__)
except AttributeError:
@ -710,7 +705,7 @@ def _spec_from_module(module, loader=None, origin=None):
spec = ModuleSpec(name, loader, origin=origin)
spec._set_fileattr = False if location is None else (origin == location)
spec.cached = cached
spec.cached = None
spec.submodule_search_locations = submodule_search_locations
return spec
@ -770,7 +765,7 @@ def _init_module_attrs(spec, module, *, override=False):
module.__path__ = spec.submodule_search_locations
except AttributeError:
pass
# __file__/__cached__
# __file__
if spec.has_location:
if override or getattr(module, '__file__', None) is None:
try:
@ -778,12 +773,6 @@ def _init_module_attrs(spec, module, *, override=False):
except AttributeError:
pass
if override or getattr(module, '__cached__', None) is None:
if spec.cached is not None:
try:
module.__cached__ = spec.cached
except AttributeError:
pass
return module

View file

@ -236,7 +236,7 @@ BYTECODE_SUFFIXES = ['.pyc']
# Deprecated.
DEBUG_BYTECODE_SUFFIXES = OPTIMIZED_BYTECODE_SUFFIXES = BYTECODE_SUFFIXES
def cache_from_source(path, debug_override=None, *, optimization=None):
def cache_from_source(path, *, optimization=None):
"""Given the path to a .py file, return the path to its .pyc file.
The .py file does not need to exist; this simply returns the path to the
@ -247,20 +247,9 @@ def cache_from_source(path, debug_override=None, *, optimization=None):
of the argument is taken and verified to be alphanumeric (else ValueError
is raised).
The debug_override parameter is deprecated. If debug_override is not None,
a True value is the same as setting 'optimization' to the empty string
while a False value is equivalent to setting 'optimization' to '1'.
If sys.implementation.cache_tag is None then NotImplementedError is raised.
"""
if debug_override is not None:
_warnings.warn('the debug_override parameter is deprecated; use '
"'optimization' instead", DeprecationWarning)
if optimization is not None:
message = 'debug_override or optimization must be set to None'
raise TypeError(message)
optimization = '' if debug_override else 1
path = _os.fspath(path)
head, tail = _path_split(path)
base, sep, rest = tail.rpartition('.')
@ -1514,7 +1503,6 @@ def _fix_up_module(ns, name, pathname, cpathname=None):
ns['__spec__'] = spec
ns['__loader__'] = loader
ns['__file__'] = pathname
ns['__cached__'] = cpathname
except Exception:
# Not important enough to report.
pass

View file

@ -3407,20 +3407,20 @@ def _main():
sys.exit(1)
if args.details:
print('Target: {}'.format(target))
print('Origin: {}'.format(getsourcefile(module)))
print('Cached: {}'.format(module.__cached__))
print(f'Target: {target}')
print(f'Origin: {getsourcefile(module)}')
print(f'Cached: {module.__spec__.cached}')
if obj is module:
print('Loader: {}'.format(repr(module.__loader__)))
print(f'Loader: {module.__loader__!r}')
if hasattr(module, '__path__'):
print('Submodule search path: {}'.format(module.__path__))
print(f'Submodule search path: {module.__path__}')
else:
try:
__, lineno = findsource(obj)
except Exception:
pass
else:
print('Line: {}'.format(lineno))
print(f'Line: {lineno}')
print()
else:

View file

@ -214,7 +214,7 @@ def format_string(f, val, grouping=False, monetary=False):
Grouping is applied if the third parameter is true.
Conversion uses monetary thousands separator and grouping strings if
forth parameter monetary is true."""
fourth parameter monetary is true."""
global _percent_re
if _percent_re is None:
import re

View file

@ -607,7 +607,6 @@ def main():
'__file__': spec.origin,
'__name__': spec.name,
'__package__': None,
'__cached__': None,
}
try:
runctx(code, globs, None, options.outfile, options.sort)

View file

@ -46,6 +46,7 @@ system restrictions or missing privileges.
"""
from .cli import main
from .errors import SamplingUnknownProcessError, SamplingModuleNotFoundError, SamplingScriptNotFoundError
def handle_permission_error():
"""Handle PermissionError by displaying appropriate error message."""
@ -64,3 +65,9 @@ if __name__ == '__main__':
main()
except PermissionError:
handle_permission_error()
except SamplingUnknownProcessError as err:
print(f"Tachyon cannot find the process: {err}", file=sys.stderr)
sys.exit(1)
except (SamplingModuleNotFoundError, SamplingScriptNotFoundError) as err:
print(f"Tachyon cannot find the target: {err}", file=sys.stderr)
sys.exit(1)

Some files were not shown because too many files have changed in this diff Show more