Merge branch 'main' into list-thread-safety-docs
2
.gitattributes
vendored
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
1
.github/workflows/build.yml
vendored
|
|
@ -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,
|
||||
|
|
|
|||
2
.github/workflows/mypy.yml
vendored
|
|
@ -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
|
|
@ -45,6 +45,7 @@ gmon.out
|
|||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.DS_Store
|
||||
.pixi/
|
||||
|
||||
*.exe
|
||||
|
||||
|
|
|
|||
3260
Doc/_static/tachyon-example-flamegraph.html
generated
Normal file
3804
Doc/_static/tachyon-example-heatmap.html
generated
Normal 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`.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`.)
|
||||
|
|
|
|||
174
Doc/glossary.rst
|
|
@ -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 "read–eval–print 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 hasn’t 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.
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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. |
|
||||
|
|
|
|||
BIN
Doc/library/tachyon-flamegraph.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
Doc/library/tachyon-gecko-calltree.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
Doc/library/tachyon-gecko-flamegraph.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
Doc/library/tachyon-gecko-opcodes.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
Doc/library/tachyon-heatmap-with-opcodes.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
Doc/library/tachyon-heatmap.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
Doc/library/tachyon-live-mode-1.gif
Normal file
|
After Width: | Height: | Size: 6.2 MiB |
BIN
Doc/library/tachyon-live-mode-2.gif
Normal file
|
After Width: | Height: | Size: 3.4 MiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 110 KiB |
BIN
Doc/library/tachyon-pstats.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
|
|
@ -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])``
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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 %}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ General Options
|
|||
"_tkinter": "Install the python-tk package to use tkinter",
|
||||
}
|
||||
|
||||
.. versionadded:: next
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. option:: --enable-pystats
|
||||
|
||||
|
|
|
|||
|
|
@ -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`.)
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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") }
|
||||
|
|
|
|||
|
|
@ -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, ...);
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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), \
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
54
Include/internal/pycore_opcode_metadata.h
generated
|
|
@ -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 } } },
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
1
Include/internal/pycore_runtime_init_generated.h
generated
|
|
@ -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), \
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
1991
Include/internal/pycore_uop_ids.h
generated
497
Include/internal/pycore_uop_metadata.h
generated
|
|
@ -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--*/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -240,4 +240,5 @@ if __name__ == '__main__':
|
|||
break
|
||||
|
||||
console.write('exiting asyncio REPL...\n')
|
||||
loop.close()
|
||||
sys.exit(return_code)
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||