mirror of https://github.com/python/cpython
gh-101101: Unstable C API tier (PEP 689) (GH-101102)
This commit is contained in:
parent
c41af812c9
commit
6b2d7c0ddb
|
@ -33,28 +33,47 @@ bound into a function.
|
||||||
|
|
||||||
Return the number of free variables in *co*.
|
Return the number of free variables in *co*.
|
||||||
|
|
||||||
.. c:function:: PyCodeObject* PyCode_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
|
.. c:function:: PyCodeObject* PyUnstable_Code_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
|
||||||
|
|
||||||
Return a new code object. If you need a dummy code object to create a frame,
|
Return a new code object. If you need a dummy code object to create a frame,
|
||||||
use :c:func:`PyCode_NewEmpty` instead. Calling :c:func:`PyCode_New` directly
|
use :c:func:`PyCode_NewEmpty` instead.
|
||||||
will bind you to a precise Python version since the definition of the bytecode
|
|
||||||
changes often. The many arguments of this function are inter-dependent in complex
|
Since the definition of the bytecode changes often, calling
|
||||||
|
:c:func:`PyCode_New` directly can bind you to a precise Python version.
|
||||||
|
|
||||||
|
The many arguments of this function are inter-dependent in complex
|
||||||
ways, meaning that subtle changes to values are likely to result in incorrect
|
ways, meaning that subtle changes to values are likely to result in incorrect
|
||||||
execution or VM crashes. Use this function only with extreme care.
|
execution or VM crashes. Use this function only with extreme care.
|
||||||
|
|
||||||
.. versionchanged:: 3.11
|
.. versionchanged:: 3.11
|
||||||
Added ``exceptiontable`` parameter.
|
Added ``exceptiontable`` parameter.
|
||||||
|
|
||||||
.. c:function:: PyCodeObject* PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
|
.. index:: single: PyCode_New
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Renamed from ``PyCode_New`` as part of :ref:`unstable-c-api`.
|
||||||
|
The old name is deprecated, but will remain available until the
|
||||||
|
signature changes again.
|
||||||
|
|
||||||
|
.. c:function:: PyCodeObject* PyUnstable_Code_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *linetable, PyObject *exceptiontable)
|
||||||
|
|
||||||
Similar to :c:func:`PyCode_New`, but with an extra "posonlyargcount" for positional-only arguments.
|
Similar to :c:func:`PyCode_New`, but with an extra "posonlyargcount" for positional-only arguments.
|
||||||
The same caveats that apply to ``PyCode_New`` also apply to this function.
|
The same caveats that apply to ``PyCode_New`` also apply to this function.
|
||||||
|
|
||||||
.. versionadded:: 3.8
|
.. index:: single: PyCode_NewWithPosOnlyArgs
|
||||||
|
|
||||||
|
.. versionadded:: 3.8 as ``PyCode_NewWithPosOnlyArgs``
|
||||||
|
|
||||||
.. versionchanged:: 3.11
|
.. versionchanged:: 3.11
|
||||||
Added ``exceptiontable`` parameter.
|
Added ``exceptiontable`` parameter.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Renamed to ``PyUnstable_Code_NewWithPosOnlyArgs``.
|
||||||
|
The old name is deprecated, but will remain available until the
|
||||||
|
signature changes again.
|
||||||
|
|
||||||
.. c:function:: PyCodeObject* PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
.. c:function:: PyCodeObject* PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
||||||
|
|
||||||
Return a new empty code object with the specified filename,
|
Return a new empty code object with the specified filename,
|
||||||
|
@ -165,3 +184,70 @@ bound into a function.
|
||||||
:c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``.
|
:c:func:`PyErr_WriteUnraisable`. Otherwise it should return ``0``.
|
||||||
|
|
||||||
.. versionadded:: 3.12
|
.. versionadded:: 3.12
|
||||||
|
|
||||||
|
|
||||||
|
Extra information
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
To support low-level extensions to frame evaluation, such as external
|
||||||
|
just-in-time compilers, it is possible to attach arbitrary extra data to
|
||||||
|
code objects.
|
||||||
|
|
||||||
|
These functions are part of the unstable C API tier:
|
||||||
|
this functionality is a CPython implementation detail, and the API
|
||||||
|
may change without deprecation warnings.
|
||||||
|
|
||||||
|
.. c:function:: Py_ssize_t PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
|
||||||
|
|
||||||
|
Return a new an opaque index value used to adding data to code objects.
|
||||||
|
|
||||||
|
You generally call this function once (per interpreter) and use the result
|
||||||
|
with ``PyCode_GetExtra`` and ``PyCode_SetExtra`` to manipulate
|
||||||
|
data on individual code objects.
|
||||||
|
|
||||||
|
If *free* is not ``NULL``: when a code object is deallocated,
|
||||||
|
*free* will be called on non-``NULL`` data stored under the new index.
|
||||||
|
Use :c:func:`Py_DecRef` when storing :c:type:`PyObject`.
|
||||||
|
|
||||||
|
.. index:: single: _PyEval_RequestCodeExtraIndex
|
||||||
|
|
||||||
|
.. versionadded:: 3.6 as ``_PyEval_RequestCodeExtraIndex``
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Renamed to ``PyUnstable_Eval_RequestCodeExtraIndex``.
|
||||||
|
The old private name is deprecated, but will be available until the API
|
||||||
|
changes.
|
||||||
|
|
||||||
|
.. c:function:: int PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
||||||
|
|
||||||
|
Set *extra* to the extra data stored under the given index.
|
||||||
|
Return 0 on success. Set an exception and return -1 on failure.
|
||||||
|
|
||||||
|
If no data was set under the index, set *extra* to ``NULL`` and return
|
||||||
|
0 without setting an exception.
|
||||||
|
|
||||||
|
.. index:: single: _PyCode_GetExtra
|
||||||
|
|
||||||
|
.. versionadded:: 3.6 as ``_PyCode_GetExtra``
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Renamed to ``PyUnstable_Code_GetExtra``.
|
||||||
|
The old private name is deprecated, but will be available until the API
|
||||||
|
changes.
|
||||||
|
|
||||||
|
.. c:function:: int PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
||||||
|
|
||||||
|
Set the extra data stored under the given index to *extra*.
|
||||||
|
Return 0 on success. Set an exception and return -1 on failure.
|
||||||
|
|
||||||
|
.. index:: single: _PyCode_SetExtra
|
||||||
|
|
||||||
|
.. versionadded:: 3.6 as ``_PyCode_SetExtra``
|
||||||
|
|
||||||
|
.. versionchanged:: 3.12
|
||||||
|
|
||||||
|
Renamed to ``PyUnstable_Code_SetExtra``.
|
||||||
|
The old private name is deprecated, but will be available until the API
|
||||||
|
changes.
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
C API Stability
|
C API Stability
|
||||||
***************
|
***************
|
||||||
|
|
||||||
Python's C API is covered by the Backwards Compatibility Policy, :pep:`387`.
|
Unless documented otherwise, Python's C API is covered by the Backwards
|
||||||
While the C API will change with every minor release (e.g. from 3.9 to 3.10),
|
Compatibility Policy, :pep:`387`.
|
||||||
most changes will be source-compatible, typically by only adding new API.
|
Most changes to it are source-compatible (typically by only adding new API).
|
||||||
Changing existing API or removing API is only done after a deprecation period
|
Changing existing API or removing API is only done after a deprecation period
|
||||||
or to fix serious issues.
|
or to fix serious issues.
|
||||||
|
|
||||||
|
@ -18,8 +18,38 @@ way; see :ref:`stable-abi-platform` below).
|
||||||
So, code compiled for Python 3.10.0 will work on 3.10.8 and vice versa,
|
So, code compiled for Python 3.10.0 will work on 3.10.8 and vice versa,
|
||||||
but will need to be compiled separately for 3.9.x and 3.10.x.
|
but will need to be compiled separately for 3.9.x and 3.10.x.
|
||||||
|
|
||||||
|
There are two tiers of C API with different stability exepectations:
|
||||||
|
|
||||||
|
- *Unstable API*, may change in minor versions without a deprecation period.
|
||||||
|
It is marked by the ``PyUnstable`` prefix in names.
|
||||||
|
- *Limited API*, is compatible across several minor releases.
|
||||||
|
When :c:macro:`Py_LIMITED_API` is defined, only this subset is exposed
|
||||||
|
from ``Python.h``.
|
||||||
|
|
||||||
|
These are discussed in more detail below.
|
||||||
|
|
||||||
Names prefixed by an underscore, such as ``_Py_InternalState``,
|
Names prefixed by an underscore, such as ``_Py_InternalState``,
|
||||||
are private API that can change without notice even in patch releases.
|
are private API that can change without notice even in patch releases.
|
||||||
|
If you need to use this API, consider reaching out to
|
||||||
|
`CPython developers <https://discuss.python.org/c/core-dev/c-api/30>`_
|
||||||
|
to discuss adding public API for your use case.
|
||||||
|
|
||||||
|
.. _unstable-c-api:
|
||||||
|
|
||||||
|
Unstable C API
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. index:: single: PyUnstable
|
||||||
|
|
||||||
|
Any API named with the ``PyUnstable`` prefix exposes CPython implementation
|
||||||
|
details, and may change in every minor release (e.g. from 3.9 to 3.10) without
|
||||||
|
any deprecation warnings.
|
||||||
|
However, it will not change in a bugfix release (e.g. from 3.10.0 to 3.10.1).
|
||||||
|
|
||||||
|
It is generally intended for specialized, low-level tools like debuggers.
|
||||||
|
|
||||||
|
Projects that use this API are expected to follow
|
||||||
|
CPython development and spend extra effort adjusting to changes.
|
||||||
|
|
||||||
|
|
||||||
Stable Application Binary Interface
|
Stable Application Binary Interface
|
||||||
|
|
|
@ -143,6 +143,22 @@ class Annotations:
|
||||||
' (Only some members are part of the stable ABI.)')
|
' (Only some members are part of the stable ABI.)')
|
||||||
node.insert(0, emph_node)
|
node.insert(0, emph_node)
|
||||||
|
|
||||||
|
# Unstable API annotation.
|
||||||
|
if name.startswith('PyUnstable'):
|
||||||
|
warn_node = nodes.admonition(
|
||||||
|
classes=['unstable-c-api', 'warning'])
|
||||||
|
message = 'This is '
|
||||||
|
emph_node = nodes.emphasis(message, message)
|
||||||
|
ref_node = addnodes.pending_xref(
|
||||||
|
'Unstable API', refdomain="std",
|
||||||
|
reftarget='unstable-c-api',
|
||||||
|
reftype='ref', refexplicit="False")
|
||||||
|
ref_node += nodes.Text('Unstable API')
|
||||||
|
emph_node += ref_node
|
||||||
|
emph_node += nodes.Text('. It may change without warning in minor releases.')
|
||||||
|
warn_node += emph_node
|
||||||
|
node.insert(0, warn_node)
|
||||||
|
|
||||||
# Return value annotation
|
# Return value annotation
|
||||||
if objtype != 'function':
|
if objtype != 'function':
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -810,6 +810,29 @@ C API Changes
|
||||||
New Features
|
New Features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
||||||
|
* :pep:`697`: Introduced the :ref:`Unstable C API tier <unstable-c-api>`,
|
||||||
|
intended for low-level tools like debuggers and JIT compilers.
|
||||||
|
This API may change in each minor release of CPython without deprecation
|
||||||
|
warnings.
|
||||||
|
Its contents are marked by the ``PyUnstable_`` prefix in names.
|
||||||
|
|
||||||
|
Code object constructors:
|
||||||
|
|
||||||
|
- ``PyUnstable_Code_New()`` (renamed from ``PyCode_New``)
|
||||||
|
- ``PyUnstable_Code_NewWithPosOnlyArgs()`` (renamed from ``PyCode_NewWithPosOnlyArgs``)
|
||||||
|
|
||||||
|
Extra storage for code objects (:pep:`523`):
|
||||||
|
|
||||||
|
- ``PyUnstable_Eval_RequestCodeExtraIndex()`` (renamed from ``_PyEval_RequestCodeExtraIndex``)
|
||||||
|
- ``PyUnstable_Code_GetExtra()`` (renamed from ``_PyCode_GetExtra``)
|
||||||
|
- ``PyUnstable_Code_SetExtra()`` (renamed from ``_PyCode_SetExtra``)
|
||||||
|
|
||||||
|
The original names will continue to be available until the respective
|
||||||
|
API changes.
|
||||||
|
|
||||||
|
(Contributed by Petr Viktorin in :gh:`101101`.)
|
||||||
|
|
||||||
* Added the new limited C API function :c:func:`PyType_FromMetaclass`,
|
* Added the new limited C API function :c:func:`PyType_FromMetaclass`,
|
||||||
which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using
|
which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using
|
||||||
an additional metaclass argument.
|
an additional metaclass argument.
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
The Python C API
|
The Python C API
|
||||||
================
|
================
|
||||||
|
|
||||||
The C API is divided into three sections:
|
The C API is divided into these sections:
|
||||||
|
|
||||||
1. ``Include/``: Limited API
|
1. ``Include/``: Limited API
|
||||||
2. ``Include/cpython/``: CPython implementation details
|
2. ``Include/cpython/``: CPython implementation details
|
||||||
3. ``Include/internal/``: The internal API
|
3. ``Include/cpython/``, names with the ``PyUnstable_`` prefix: API that can
|
||||||
|
change between minor releases
|
||||||
|
4. ``Include/internal/``, and any name with ``_`` prefix: The internal API
|
||||||
|
|
||||||
Information on changing the C API is available `in the developer guide`_
|
Information on changing the C API is available `in the developer guide`_
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,12 @@ PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _P
|
||||||
PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
|
PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
|
||||||
PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
|
PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
|
||||||
|
|
||||||
PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
|
PyAPI_FUNC(Py_ssize_t) PyUnstable_Eval_RequestCodeExtraIndex(freefunc);
|
||||||
|
// Old name -- remove when this API changes:
|
||||||
|
_Py_DEPRECATED_EXTERNALLY(3.12) static inline Py_ssize_t
|
||||||
|
_PyEval_RequestCodeExtraIndex(freefunc f) {
|
||||||
|
return PyUnstable_Eval_RequestCodeExtraIndex(f);
|
||||||
|
}
|
||||||
|
|
||||||
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
|
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
|
||||||
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
|
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
|
||||||
|
|
|
@ -178,19 +178,40 @@ static inline int PyCode_GetFirstFree(PyCodeObject *op) {
|
||||||
#define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive)
|
#define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive)
|
||||||
#define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))
|
#define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))
|
||||||
|
|
||||||
/* Public interface */
|
/* Unstable public interface */
|
||||||
PyAPI_FUNC(PyCodeObject *) PyCode_New(
|
PyAPI_FUNC(PyCodeObject *) PyUnstable_Code_New(
|
||||||
int, int, int, int, int, PyObject *, PyObject *,
|
int, int, int, int, int, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, PyObject *,
|
PyObject *, PyObject *, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, int, PyObject *,
|
PyObject *, PyObject *, PyObject *, int, PyObject *,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
|
|
||||||
PyAPI_FUNC(PyCodeObject *) PyCode_NewWithPosOnlyArgs(
|
PyAPI_FUNC(PyCodeObject *) PyUnstable_Code_NewWithPosOnlyArgs(
|
||||||
int, int, int, int, int, int, PyObject *, PyObject *,
|
int, int, int, int, int, int, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, PyObject *,
|
PyObject *, PyObject *, PyObject *, PyObject *,
|
||||||
PyObject *, PyObject *, PyObject *, int, PyObject *,
|
PyObject *, PyObject *, PyObject *, int, PyObject *,
|
||||||
PyObject *);
|
PyObject *);
|
||||||
/* same as struct above */
|
/* same as struct above */
|
||||||
|
// Old names -- remove when this API changes:
|
||||||
|
_Py_DEPRECATED_EXTERNALLY(3.12) static inline PyCodeObject *
|
||||||
|
PyCode_New(
|
||||||
|
int a, int b, int c, int d, int e, PyObject *f, PyObject *g,
|
||||||
|
PyObject *h, PyObject *i, PyObject *j, PyObject *k,
|
||||||
|
PyObject *l, PyObject *m, PyObject *n, int o, PyObject *p,
|
||||||
|
PyObject *q)
|
||||||
|
{
|
||||||
|
return PyUnstable_Code_New(
|
||||||
|
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q);
|
||||||
|
}
|
||||||
|
_Py_DEPRECATED_EXTERNALLY(3.12) static inline PyCodeObject *
|
||||||
|
PyCode_NewWithPosOnlyArgs(
|
||||||
|
int a, int poac, int b, int c, int d, int e, PyObject *f, PyObject *g,
|
||||||
|
PyObject *h, PyObject *i, PyObject *j, PyObject *k,
|
||||||
|
PyObject *l, PyObject *m, PyObject *n, int o, PyObject *p,
|
||||||
|
PyObject *q)
|
||||||
|
{
|
||||||
|
return PyUnstable_Code_NewWithPosOnlyArgs(
|
||||||
|
a, poac, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q);
|
||||||
|
}
|
||||||
|
|
||||||
/* Creates a new empty code object with the specified source location. */
|
/* Creates a new empty code object with the specified source location. */
|
||||||
PyAPI_FUNC(PyCodeObject *)
|
PyAPI_FUNC(PyCodeObject *)
|
||||||
|
@ -269,11 +290,21 @@ PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj);
|
||||||
PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
|
PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
|
||||||
PyObject *names, PyObject *lnotab);
|
PyObject *names, PyObject *lnotab);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyUnstable_Code_GetExtra(
|
||||||
PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index,
|
PyObject *code, Py_ssize_t index, void **extra);
|
||||||
void **extra);
|
PyAPI_FUNC(int) PyUnstable_Code_SetExtra(
|
||||||
PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
|
PyObject *code, Py_ssize_t index, void *extra);
|
||||||
void *extra);
|
// Old names -- remove when this API changes:
|
||||||
|
_Py_DEPRECATED_EXTERNALLY(3.12) static inline int
|
||||||
|
_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
||||||
|
{
|
||||||
|
return PyUnstable_Code_GetExtra(code, index, extra);
|
||||||
|
}
|
||||||
|
_Py_DEPRECATED_EXTERNALLY(3.12) static inline int
|
||||||
|
_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
||||||
|
{
|
||||||
|
return PyUnstable_Code_SetExtra(code, index, extra);
|
||||||
|
}
|
||||||
|
|
||||||
/* Equivalent to getattr(code, 'co_code') in Python.
|
/* Equivalent to getattr(code, 'co_code') in Python.
|
||||||
Returns a strong reference to a bytes object. */
|
Returns a strong reference to a bytes object. */
|
||||||
|
|
|
@ -323,6 +323,15 @@ extern "C" {
|
||||||
#define Py_DEPRECATED(VERSION_UNUSED)
|
#define Py_DEPRECATED(VERSION_UNUSED)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// _Py_DEPRECATED_EXTERNALLY(version)
|
||||||
|
// Deprecated outside CPython core.
|
||||||
|
#ifdef Py_BUILD_CORE
|
||||||
|
#define _Py_DEPRECATED_EXTERNALLY(VERSION_UNUSED)
|
||||||
|
#else
|
||||||
|
#define _Py_DEPRECATED_EXTERNALLY(version) Py_DEPRECATED(version)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define _Py_COMP_DIAG_PUSH _Pragma("clang diagnostic push")
|
#define _Py_COMP_DIAG_PUSH _Pragma("clang diagnostic push")
|
||||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
||||||
|
|
|
@ -752,15 +752,15 @@ if check_impl_detail(cpython=True) and ctypes is not None:
|
||||||
py = ctypes.pythonapi
|
py = ctypes.pythonapi
|
||||||
freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)
|
freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)
|
||||||
|
|
||||||
RequestCodeExtraIndex = py._PyEval_RequestCodeExtraIndex
|
RequestCodeExtraIndex = py.PyUnstable_Eval_RequestCodeExtraIndex
|
||||||
RequestCodeExtraIndex.argtypes = (freefunc,)
|
RequestCodeExtraIndex.argtypes = (freefunc,)
|
||||||
RequestCodeExtraIndex.restype = ctypes.c_ssize_t
|
RequestCodeExtraIndex.restype = ctypes.c_ssize_t
|
||||||
|
|
||||||
SetExtra = py._PyCode_SetExtra
|
SetExtra = py.PyUnstable_Code_SetExtra
|
||||||
SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp)
|
SetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t, ctypes.c_voidp)
|
||||||
SetExtra.restype = ctypes.c_int
|
SetExtra.restype = ctypes.c_int
|
||||||
|
|
||||||
GetExtra = py._PyCode_GetExtra
|
GetExtra = py.PyUnstable_Code_GetExtra
|
||||||
GetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t,
|
GetExtra.argtypes = (ctypes.py_object, ctypes.c_ssize_t,
|
||||||
ctypes.POINTER(ctypes.c_voidp))
|
ctypes.POINTER(ctypes.c_voidp))
|
||||||
GetExtra.restype = ctypes.c_int
|
GetExtra.restype = ctypes.c_int
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Introduced the *Unstable C API tier*, marking APi that is allowed to change
|
||||||
|
in minor releases without a deprecation period.
|
||||||
|
See :pep:`689` for details.
|
|
@ -169,7 +169,7 @@
|
||||||
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
|
||||||
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
|
||||||
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
|
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c
|
||||||
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c
|
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/unicode.c _testcapi/getargs.c _testcapi/pytime.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c
|
||||||
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
|
||||||
|
|
||||||
# Some testing modules MUST be built as shared libraries.
|
# Some testing modules MUST be built as shared libraries.
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
#include "parts.h"
|
||||||
|
|
||||||
|
static Py_ssize_t
|
||||||
|
get_code_extra_index(PyInterpreterState* interp) {
|
||||||
|
Py_ssize_t result = -1;
|
||||||
|
|
||||||
|
static const char *key = "_testcapi.frame_evaluation.code_index";
|
||||||
|
|
||||||
|
PyObject *interp_dict = PyInterpreterState_GetDict(interp); // borrowed
|
||||||
|
assert(interp_dict); // real users would handle missing dict... somehow
|
||||||
|
|
||||||
|
PyObject *index_obj = PyDict_GetItemString(interp_dict, key); // borrowed
|
||||||
|
Py_ssize_t index = 0;
|
||||||
|
if (!index_obj) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
index = PyUnstable_Eval_RequestCodeExtraIndex(NULL);
|
||||||
|
if (index < 0 || PyErr_Occurred()) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
index_obj = PyLong_FromSsize_t(index); // strong ref
|
||||||
|
if (!index_obj) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
int res = PyDict_SetItemString(interp_dict, key, index_obj);
|
||||||
|
Py_DECREF(index_obj);
|
||||||
|
if (res < 0) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = PyLong_AsSsize_t(index_obj);
|
||||||
|
if (index == -1 && PyErr_Occurred()) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = index;
|
||||||
|
finally:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_code_extra(PyObject* self, PyObject *Py_UNUSED(callable))
|
||||||
|
{
|
||||||
|
PyObject *result = NULL;
|
||||||
|
PyObject *test_module = NULL;
|
||||||
|
PyObject *test_func = NULL;
|
||||||
|
|
||||||
|
// Get or initialize interpreter-specific code object storage index
|
||||||
|
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||||
|
if (!interp) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Py_ssize_t code_extra_index = get_code_extra_index(interp);
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a function to test with
|
||||||
|
// This can be any Python function. Use `test.test_misc.testfunction`.
|
||||||
|
test_module = PyImport_ImportModule("test.test_capi.test_misc");
|
||||||
|
if (!test_module) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
test_func = PyObject_GetAttrString(test_module, "testfunction");
|
||||||
|
if (!test_func) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
PyObject *test_func_code = PyFunction_GetCode(test_func); // borrowed
|
||||||
|
if (!test_func_code) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the value is initially NULL
|
||||||
|
void *extra;
|
||||||
|
int res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
|
||||||
|
if (res < 0) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
assert (extra == NULL);
|
||||||
|
|
||||||
|
// Set another code extra value
|
||||||
|
res = PyUnstable_Code_SetExtra(test_func_code, code_extra_index, (void*)(uintptr_t)77);
|
||||||
|
if (res < 0) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
// Assert it was set correctly
|
||||||
|
res = PyUnstable_Code_GetExtra(test_func_code, code_extra_index, &extra);
|
||||||
|
if (res < 0) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
assert ((uintptr_t)extra == 77);
|
||||||
|
|
||||||
|
result = Py_NewRef(Py_None);
|
||||||
|
finally:
|
||||||
|
Py_XDECREF(test_module);
|
||||||
|
Py_XDECREF(test_func);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef TestMethods[] = {
|
||||||
|
{"test_code_extra", test_code_extra, METH_NOARGS},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
_PyTestCapi_Init_Code(PyObject *m) {
|
||||||
|
if (PyModule_AddFunctions(m, TestMethods) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -37,6 +37,7 @@ int _PyTestCapi_Init_Long(PyObject *module);
|
||||||
int _PyTestCapi_Init_Float(PyObject *module);
|
int _PyTestCapi_Init_Float(PyObject *module);
|
||||||
int _PyTestCapi_Init_Structmember(PyObject *module);
|
int _PyTestCapi_Init_Structmember(PyObject *module);
|
||||||
int _PyTestCapi_Init_Exceptions(PyObject *module);
|
int _PyTestCapi_Init_Exceptions(PyObject *module);
|
||||||
|
int _PyTestCapi_Init_Code(PyObject *module);
|
||||||
|
|
||||||
#ifdef LIMITED_API_AVAILABLE
|
#ifdef LIMITED_API_AVAILABLE
|
||||||
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
|
int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
|
||||||
|
|
|
@ -4083,6 +4083,9 @@ PyInit__testcapi(void)
|
||||||
if (_PyTestCapi_Init_Exceptions(m) < 0) {
|
if (_PyTestCapi_Init_Exceptions(m) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (_PyTestCapi_Init_Code(m) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef LIMITED_API_AVAILABLE
|
#ifndef LIMITED_API_AVAILABLE
|
||||||
PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);
|
PyModule_AddObjectRef(m, "LIMITED_API_AVAILABLE", Py_False);
|
||||||
|
|
|
@ -567,7 +567,8 @@ _PyCode_New(struct _PyCodeConstructor *con)
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
PyCodeObject *
|
PyCodeObject *
|
||||||
PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
|
PyUnstable_Code_NewWithPosOnlyArgs(
|
||||||
|
int argcount, int posonlyargcount, int kwonlyargcount,
|
||||||
int nlocals, int stacksize, int flags,
|
int nlocals, int stacksize, int flags,
|
||||||
PyObject *code, PyObject *consts, PyObject *names,
|
PyObject *code, PyObject *consts, PyObject *names,
|
||||||
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
||||||
|
@ -691,7 +692,7 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
PyCodeObject *
|
PyCodeObject *
|
||||||
PyCode_New(int argcount, int kwonlyargcount,
|
PyUnstable_Code_New(int argcount, int kwonlyargcount,
|
||||||
int nlocals, int stacksize, int flags,
|
int nlocals, int stacksize, int flags,
|
||||||
PyObject *code, PyObject *consts, PyObject *names,
|
PyObject *code, PyObject *consts, PyObject *names,
|
||||||
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
||||||
|
@ -1371,7 +1372,7 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
||||||
{
|
{
|
||||||
if (!PyCode_Check(code)) {
|
if (!PyCode_Check(code)) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
|
@ -1392,7 +1393,7 @@ _PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\long.c" />
|
<ClCompile Include="..\Modules\_testcapi\long.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\structmember.c" />
|
<ClCompile Include="..\Modules\_testcapi\structmember.c" />
|
||||||
<ClCompile Include="..\Modules\_testcapi\exceptions.c" />
|
<ClCompile Include="..\Modules\_testcapi\exceptions.c" />
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\code.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\PC\python_nt.rc" />
|
<ResourceCompile Include="..\PC\python_nt.rc" />
|
||||||
|
|
|
@ -54,6 +54,9 @@
|
||||||
<ClCompile Include="..\Modules\_testcapi\exceptions.c">
|
<ClCompile Include="..\Modules\_testcapi\exceptions.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\Modules\_testcapi\code.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="..\PC\python_nt.rc">
|
<ResourceCompile Include="..\PC\python_nt.rc">
|
||||||
|
|
|
@ -2988,7 +2988,7 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int oparg)
|
||||||
|
|
||||||
|
|
||||||
Py_ssize_t
|
Py_ssize_t
|
||||||
_PyEval_RequestCodeExtraIndex(freefunc free)
|
PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
|
||||||
{
|
{
|
||||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||||
Py_ssize_t new_index;
|
Py_ssize_t new_index;
|
||||||
|
|
Loading…
Reference in New Issue