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 6d2cc96b5e..e38a200c00 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", | 
