summaryrefslogtreecommitdiffstats
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r--Python/sysmodule.c80
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",