diff options
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r-- | Python/sysmodule.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 6d2cc96..e38a200 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -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", |