Implement the frame evaluation API aspect of PEP 523.
This commit is contained in:
parent
625cb379f7
commit
3cebf93872
|
@ -97,6 +97,34 @@ Windows improvements:
|
||||||
New Features
|
New Features
|
||||||
============
|
============
|
||||||
|
|
||||||
|
.. _pep-523:
|
||||||
|
|
||||||
|
PEP 523: Adding a frame evaluation API to CPython
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
While Python provides extensive support to customize how code
|
||||||
|
executes, one place it has not done so is in the evaluation of frame
|
||||||
|
objects. If you wanted some way to intercept frame evaluation in
|
||||||
|
Python there really wasn't any way without directly manipulating
|
||||||
|
function pointers for defined functions.
|
||||||
|
|
||||||
|
:pep:`523` changes this by providing an API to make frame
|
||||||
|
evaluation pluggable at the C level. This will allow for tools such
|
||||||
|
as debuggers and JITs to intercept frame evaluation before the
|
||||||
|
execution of Python code begins. This enables the use of alternative
|
||||||
|
evaluation implementations for Python code, tracking frame
|
||||||
|
evaluation, etc.
|
||||||
|
|
||||||
|
This API is not part of the limited C API and is marked as private to
|
||||||
|
signal that usage of this API is expected to be limited and only
|
||||||
|
applicable to very select, low-level use-cases.
|
||||||
|
|
||||||
|
.. seealso::
|
||||||
|
|
||||||
|
:pep:`523` - Adding a frame evaluation API to CPython
|
||||||
|
PEP written by Brett Cannon and Dino Viehland.
|
||||||
|
|
||||||
|
|
||||||
.. _pep-519:
|
.. _pep-519:
|
||||||
|
|
||||||
PEP 519: Adding a file system path protocol
|
PEP 519: Adding a file system path protocol
|
||||||
|
|
|
@ -119,6 +119,9 @@ PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *);
|
PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *);
|
||||||
PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
|
PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
|
||||||
PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
|
PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
|
||||||
|
#ifndef Py_LIMITED_API
|
||||||
|
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(struct _frame *f, int exc);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Interface for threads.
|
/* Interface for threads.
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,13 @@ extern "C" {
|
||||||
|
|
||||||
struct _ts; /* Forward */
|
struct _ts; /* Forward */
|
||||||
struct _is; /* Forward */
|
struct _is; /* Forward */
|
||||||
|
struct _frame; /* Forward declaration for PyFrameObject. */
|
||||||
|
|
||||||
#ifdef Py_LIMITED_API
|
#ifdef Py_LIMITED_API
|
||||||
typedef struct _is PyInterpreterState;
|
typedef struct _is PyInterpreterState;
|
||||||
#else
|
#else
|
||||||
|
typedef PyObject* (*_PyFrameEvalFunction)(struct _frame *, int);
|
||||||
|
|
||||||
typedef struct _is {
|
typedef struct _is {
|
||||||
|
|
||||||
struct _is *next;
|
struct _is *next;
|
||||||
|
@ -42,14 +45,14 @@ typedef struct _is {
|
||||||
|
|
||||||
PyObject *builtins_copy;
|
PyObject *builtins_copy;
|
||||||
PyObject *import_func;
|
PyObject *import_func;
|
||||||
|
/* Initialized to PyEval_EvalFrameDefault(). */
|
||||||
|
_PyFrameEvalFunction eval_frame;
|
||||||
} PyInterpreterState;
|
} PyInterpreterState;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* State unique per thread */
|
/* State unique per thread */
|
||||||
|
|
||||||
struct _frame; /* Avoid including frameobject.h */
|
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
/* Py_tracefunc return -1 when raising an exception, or 0 for success. */
|
/* Py_tracefunc return -1 when raising an exception, or 0 for success. */
|
||||||
typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);
|
typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);
|
||||||
|
|
|
@ -17,7 +17,9 @@ Core and Builtins
|
||||||
restriction: in beta 2, backslashes will only be disallowed inside
|
restriction: in beta 2, backslashes will only be disallowed inside
|
||||||
the braces (where the expressions are). This is a breaking change
|
the braces (where the expressions are). This is a breaking change
|
||||||
from the 3.6 alpha releases.
|
from the 3.6 alpha releases.
|
||||||
|
|
||||||
|
- Implement the frame evaluation part of PEP 523.
|
||||||
|
|
||||||
- Issue #27870: A left shift of zero by a large integer no longer attempts
|
- Issue #27870: A left shift of zero by a large integer no longer attempts
|
||||||
to allocate large amounts of memory.
|
to allocate large amounts of memory.
|
||||||
|
|
||||||
|
|
|
@ -796,6 +796,13 @@ PyEval_EvalFrame(PyFrameObject *f) {
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||||
|
{
|
||||||
|
PyThreadState *tstate = PyThreadState_GET();
|
||||||
|
return tstate->interp->eval_frame(f, throwflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
|
||||||
{
|
{
|
||||||
#ifdef DXPAIRS
|
#ifdef DXPAIRS
|
||||||
int lastopcode = 0;
|
int lastopcode = 0;
|
||||||
|
|
|
@ -91,6 +91,7 @@ PyInterpreterState_New(void)
|
||||||
interp->fscodec_initialized = 0;
|
interp->fscodec_initialized = 0;
|
||||||
interp->importlib = NULL;
|
interp->importlib = NULL;
|
||||||
interp->import_func = NULL;
|
interp->import_func = NULL;
|
||||||
|
interp->eval_frame = _PyEval_EvalFrameDefault;
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
#if HAVE_DECL_RTLD_NOW
|
#if HAVE_DECL_RTLD_NOW
|
||||||
interp->dlopenflags = RTLD_NOW;
|
interp->dlopenflags = RTLD_NOW;
|
||||||
|
|
Loading…
Reference in New Issue