mirror of
https://github.com/python/cpython.git
synced 2025-08-23 10:16:01 +00:00
PEP 553 built-in breakpoint() function (bpo-31353) (#3355)
Implement PEP 553, built-in breakpoint() with support from sys.breakpointhook(), along with documentation and tests. Closes bpo-31353
This commit is contained in:
parent
4d07189788
commit
36c1d1f1e5
9 changed files with 324 additions and 23 deletions
|
@ -96,6 +96,81 @@ PySys_SetObject(const char *name, PyObject *v)
|
|||
return PyDict_SetItemString(sd, name, v);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
sys_breakpointhook(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *keywords)
|
||||
{
|
||||
assert(!PyErr_Occurred());
|
||||
char *envar = Py_GETENV("PYTHONBREAKPOINT");
|
||||
|
||||
if (envar == NULL || strlen(envar) == 0) {
|
||||
envar = "pdb.set_trace";
|
||||
}
|
||||
else if (!strcmp(envar, "0")) {
|
||||
/* The breakpoint is explicitly no-op'd. */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
char *last_dot = strrchr(envar, '.');
|
||||
char *attrname = NULL;
|
||||
PyObject *modulepath = NULL;
|
||||
|
||||
if (last_dot == NULL) {
|
||||
/* The breakpoint is a built-in, e.g. PYTHONBREAKPOINT=int */
|
||||
modulepath = PyUnicode_FromString("builtins");
|
||||
attrname = envar;
|
||||
}
|
||||
else {
|
||||
/* Split on the last dot; */
|
||||
modulepath = PyUnicode_FromStringAndSize(envar, last_dot - envar);
|
||||
attrname = last_dot + 1;
|
||||
}
|
||||
if (modulepath == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *fromlist = Py_BuildValue("(s)", attrname);
|
||||
if (fromlist == NULL) {
|
||||
Py_DECREF(modulepath);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *module = PyImport_ImportModuleLevelObject(
|
||||
modulepath, NULL, NULL, fromlist, 0);
|
||||
Py_DECREF(modulepath);
|
||||
Py_DECREF(fromlist);
|
||||
|
||||
if (module == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *hook = PyObject_GetAttrString(module, attrname);
|
||||
Py_DECREF(module);
|
||||
|
||||
if (hook == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *retval = _PyObject_FastCallKeywords(hook, args, nargs, keywords);
|
||||
Py_DECREF(hook);
|
||||
return retval;
|
||||
|
||||
error:
|
||||
/* If any of the imports went wrong, then warn and ignore. */
|
||||
PyErr_Clear();
|
||||
int status = PyErr_WarnFormat(
|
||||
PyExc_RuntimeWarning, 0,
|
||||
"Ignoring unimportable $PYTHONBREAKPOINT: \"%s\"", envar);
|
||||
if (status < 0) {
|
||||
/* Printing the warning raised an exception. */
|
||||
return NULL;
|
||||
}
|
||||
/* The warning was (probably) issued. */
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(breakpointhook_doc,
|
||||
"breakpointhook(*args, **kws)\n"
|
||||
"\n"
|
||||
"This hook function is called by built-in breakpoint().\n"
|
||||
);
|
||||
|
||||
/* Write repr(o) to sys.stdout using sys.stdout.encoding and 'backslashreplace'
|
||||
error handler. If sys.stdout has a buffer attribute, use
|
||||
sys.stdout.buffer.write(encoded), otherwise redecode the string and use
|
||||
|
@ -1365,6 +1440,8 @@ sys_getandroidapilevel(PyObject *self)
|
|||
|
||||
static PyMethodDef sys_methods[] = {
|
||||
/* Might as well keep this in alphabetic order */
|
||||
{"breakpointhook", (PyCFunction)sys_breakpointhook,
|
||||
METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc},
|
||||
{"callstats", (PyCFunction)sys_callstats, METH_NOARGS,
|
||||
callstats_doc},
|
||||
{"_clear_type_cache", sys_clear_type_cache, METH_NOARGS,
|
||||
|
@ -1977,6 +2054,9 @@ _PySys_BeginInit(void)
|
|||
PyDict_GetItemString(sysdict, "displayhook"));
|
||||
SET_SYS_FROM_STRING_BORROW("__excepthook__",
|
||||
PyDict_GetItemString(sysdict, "excepthook"));
|
||||
SET_SYS_FROM_STRING_BORROW(
|
||||
"__breakpointhook__",
|
||||
PyDict_GetItemString(sysdict, "breakpointhook"));
|
||||
SET_SYS_FROM_STRING("version",
|
||||
PyUnicode_FromString(Py_GetVersion()));
|
||||
SET_SYS_FROM_STRING("hexversion",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue