diff options
Diffstat (limited to 'Python/_warnings.c')
| -rw-r--r-- | Python/_warnings.c | 245 | 
1 files changed, 165 insertions, 80 deletions
| diff --git a/Python/_warnings.c b/Python/_warnings.c index f33e477..6013d7d 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -13,6 +13,8 @@ static PyObject *_filters;  /* List */  static PyObject *_once_registry;  /* Dict */  static PyObject *_default_action; /* String */ +_Py_IDENTIFIER(argv); +_Py_IDENTIFIER(stderr);  static int  check_matched(PyObject *obj, PyObject *arg) @@ -99,7 +101,7 @@ get_default_action(void)  /* The item is a borrowed reference. */ -static const char * +static PyObject*  get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,             PyObject *module, PyObject **item)  { @@ -144,21 +146,28 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,          ln_obj = PyTuple_GET_ITEM(tmp_item, 4);          good_msg = check_matched(msg, text); +        if (good_msg == -1) +            return NULL; +          good_mod = check_matched(mod, module); +        if (good_mod == -1) +            return NULL; +          is_subclass = PyObject_IsSubclass(category, cat); +        if (is_subclass == -1) +            return NULL; +          ln = PyLong_AsSsize_t(ln_obj); -        if (good_msg == -1 || good_mod == -1 || is_subclass == -1 || -            (ln == -1 && PyErr_Occurred())) +        if (ln == -1 && PyErr_Occurred())              return NULL;          if (good_msg && is_subclass && good_mod && (ln == 0 || lineno == ln)) -            return _PyUnicode_AsString(action); +            return action;      }      action = get_default_action(); -    if (action != NULL) { -        return _PyUnicode_AsString(action); -    } +    if (action != NULL) +        return action;      PyErr_SetString(PyExc_ValueError,                      MODULE_NAME ".defaultaction not found"); @@ -192,23 +201,26 @@ static PyObject *  normalize_module(PyObject *filename)  {      PyObject *module; -    const char *mod_str; +    int kind; +    void *data;      Py_ssize_t len; -    int rc = PyObject_IsTrue(filename); -    if (rc == -1) -        return NULL; -    else if (rc == 0) -        return PyUnicode_FromString("<unknown>"); - -    mod_str = _PyUnicode_AsString(filename); -    if (mod_str == NULL) -        return NULL;      len = PyUnicode_GetLength(filename);      if (len < 0)          return NULL; + +    if (len == 0) +        return PyUnicode_FromString("<unknown>"); + +    kind = PyUnicode_KIND(filename); +    data = PyUnicode_DATA(filename); + +    /* if filename.endswith(".py"): */      if (len >= 3 && -        strncmp(mod_str + (len - 3), ".py", 3) == 0) { +        PyUnicode_READ(kind, data, len-3) == '.' && +        PyUnicode_READ(kind, data, len-2) == 'p' && +        PyUnicode_READ(kind, data, len-1) == 'y') +    {          module = PyUnicode_Substring(filename, 0, len-3);      }      else { @@ -253,39 +265,63 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject      name = _PyObject_GetAttrId(category, &PyId___name__);      if (name == NULL)  /* XXX Can an object lack a '__name__' attribute? */ -        return; +        goto error; -    f_stderr = PySys_GetObject("stderr"); +    f_stderr = _PySys_GetObjectId(&PyId_stderr);      if (f_stderr == NULL) {          fprintf(stderr, "lost sys.stderr\n"); -        Py_DECREF(name); -        return; +        goto error;      }      /* Print "filename:lineno: category: text\n" */ -    PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW); -    PyFile_WriteString(lineno_str, f_stderr); -    PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW); -    PyFile_WriteString(": ", f_stderr); -    PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW); -    PyFile_WriteString("\n", f_stderr); -    Py_XDECREF(name); +    if (PyFile_WriteObject(filename, f_stderr, Py_PRINT_RAW) < 0) +        goto error; +    if (PyFile_WriteString(lineno_str, f_stderr) < 0) +        goto error; +    if (PyFile_WriteObject(name, f_stderr, Py_PRINT_RAW) < 0) +        goto error; +    if (PyFile_WriteString(": ", f_stderr) < 0) +        goto error; +    if (PyFile_WriteObject(text, f_stderr, Py_PRINT_RAW) < 0) +        goto error; +    if (PyFile_WriteString("\n", f_stderr) < 0) +        goto error; +    Py_CLEAR(name);      /* Print "  source_line\n" */      if (sourceline) { -        char *source_line_str = _PyUnicode_AsString(sourceline); -        if (source_line_str == NULL) -                return; -        while (*source_line_str == ' ' || *source_line_str == '\t' || -                *source_line_str == '\014') -            source_line_str++; - -        PyFile_WriteString(source_line_str, f_stderr); +        int kind; +        void *data; +        Py_ssize_t i, len; +        Py_UCS4 ch; +        PyObject *truncated; + +        if (PyUnicode_READY(sourceline) < 1) +            goto error; + +        kind = PyUnicode_KIND(sourceline); +        data = PyUnicode_DATA(sourceline); +        len = PyUnicode_GET_LENGTH(sourceline); +        for (i=0; i<len; i++) { +            ch = PyUnicode_READ(kind, data, i); +            if (ch != ' ' && ch != '\t' && ch != '\014') +                break; +        } + +        truncated = PyUnicode_Substring(sourceline, i, len); +        if (truncated == NULL) +            goto error; + +        PyFile_WriteObject(sourceline, f_stderr, Py_PRINT_RAW); +        Py_DECREF(truncated);          PyFile_WriteString("\n", f_stderr);      } -    else -        if (_Py_DisplaySourceLine(f_stderr, filename, lineno, 2) < 0) -                return; +    else { +        _Py_DisplaySourceLine(f_stderr, filename, lineno, 2); +    } + +error: +    Py_XDECREF(name);      PyErr_Clear();  } @@ -296,9 +332,16 @@ warn_explicit(PyObject *category, PyObject *message,  {      PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;      PyObject *item = Py_None; -    const char *action; +    PyObject *action;      int rc; +    /* module can be None if a warning is emitted late during Python shutdown. +       In this case, the Python warnings module was probably unloaded, filters +       are no more available to choose as action. It is safer to ignore the +       warning and do nothing. */ +    if (module == Py_None) +        Py_RETURN_NONE; +      if (registry && !PyDict_Check(registry) && (registry != Py_None)) {          PyErr_SetString(PyExc_TypeError, "'registry' must be a dict");          return NULL; @@ -354,7 +397,7 @@ warn_explicit(PyObject *category, PyObject *message,      if (action == NULL)          goto cleanup; -    if (strcmp(action, "error") == 0) { +    if (PyUnicode_CompareWithASCIIString(action, "error") == 0) {          PyErr_SetObject(category, message);          goto cleanup;      } @@ -362,13 +405,13 @@ warn_explicit(PyObject *category, PyObject *message,      /* Store in the registry that we've been here, *except* when the action         is "always". */      rc = 0; -    if (strcmp(action, "always") != 0) { +    if (PyUnicode_CompareWithASCIIString(action, "always") != 0) {          if (registry != NULL && registry != Py_None &&                  PyDict_SetItem(registry, key, Py_True) < 0)              goto cleanup; -        else if (strcmp(action, "ignore") == 0) +        else if (PyUnicode_CompareWithASCIIString(action, "ignore") == 0)              goto return_none; -        else if (strcmp(action, "once") == 0) { +        else if (PyUnicode_CompareWithASCIIString(action, "once") == 0) {              if (registry == NULL || registry == Py_None) {                  registry = get_once_registry();                  if (registry == NULL) @@ -377,24 +420,15 @@ warn_explicit(PyObject *category, PyObject *message,              /* _once_registry[(text, category)] = 1 */              rc = update_registry(registry, text, category, 0);          } -        else if (strcmp(action, "module") == 0) { +        else if (PyUnicode_CompareWithASCIIString(action, "module") == 0) {              /* registry[(text, category, 0)] = 1 */              if (registry != NULL && registry != Py_None)                  rc = update_registry(registry, text, category, 0);          } -        else if (strcmp(action, "default") != 0) { -            PyObject *to_str = PyObject_Str(item); -            const char *err_str = "???"; - -            if (to_str != NULL) { -                err_str = _PyUnicode_AsString(to_str); -                if (err_str == NULL) -                        goto cleanup; -            } +        else if (PyUnicode_CompareWithASCIIString(action, "default") != 0) {              PyErr_Format(PyExc_RuntimeError, -                        "Unrecognized action (%s) in warnings.filters:\n %s", -                        action, err_str); -            Py_XDECREF(to_str); +                        "Unrecognized action (%R) in warnings.filters:\n %R", +                        action, item);              goto cleanup;          }      } @@ -528,13 +562,12 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,              Py_INCREF(*filename);      }      else { -        const char *module_str = _PyUnicode_AsString(*module);          *filename = NULL; -        if (module_str == NULL) -                goto handle_error; -        if (strcmp(module_str, "__main__") == 0) { -            PyObject *argv = PySys_GetObject("argv"); -            if (argv != NULL && PyList_Size(argv) > 0) { +        if (*module != Py_None && PyUnicode_CompareWithASCIIString(*module, "__main__") == 0) { +            PyObject *argv = _PySys_GetObjectId(&PyId_argv); +            /* PyList_Check() is needed because sys.argv is set to None during +               Python finalization */ +            if (argv != NULL && PyList_Check(argv) && PyList_Size(argv) > 0) {                  int is_true;                  *filename = PyList_GetItem(argv, 0);                  Py_INCREF(*filename); @@ -554,8 +587,8 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,              else {                  /* embedded interpreters don't have sys.argv, see bug #839151 */                  *filename = PyUnicode_FromString("__main__"); -                    if (*filename == NULL) -                        goto handle_error; +                if (*filename == NULL) +                    goto handle_error;              }          }          if (*filename == NULL) { @@ -649,7 +682,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)      PyObject *registry = NULL;      PyObject *module_globals = NULL; -    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOi|OOO:warn_explicit", +    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOO:warn_explicit",                  kwd_list, &message, &category, &filename, &lineno, &module,                  ®istry, &module_globals))          return NULL; @@ -707,14 +740,14 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)          /* Handle the warning. */          returned = warn_explicit(category, message, filename, lineno, module, -                            registry, source_line); +                                 registry, source_line);          Py_DECREF(source_list);          return returned;      }   standard_call:      return warn_explicit(category, message, filename, lineno, module, -                                registry, NULL); +                         registry, NULL);  } @@ -786,11 +819,26 @@ PyErr_Warn(PyObject *category, char *text)  /* Warning with explicit origin */  int +PyErr_WarnExplicitObject(PyObject *category, PyObject *message, +                         PyObject *filename, int lineno, +                         PyObject *module, PyObject *registry) +{ +    PyObject *res; +    if (category == NULL) +        category = PyExc_RuntimeWarning; +    res = warn_explicit(category, message, filename, lineno, +                        module, registry, NULL); +    if (res == NULL) +        return -1; +    Py_DECREF(res); +    return 0; +} + +int  PyErr_WarnExplicit(PyObject *category, const char *text,                     const char *filename_str, int lineno,                     const char *module_str, PyObject *registry)  { -    PyObject *res;      PyObject *message = PyUnicode_FromString(text);      PyObject *filename = PyUnicode_DecodeFSDefault(filename_str);      PyObject *module = NULL; @@ -800,18 +848,12 @@ PyErr_WarnExplicit(PyObject *category, const char *text,          goto exit;      if (module_str != NULL) {          module = PyUnicode_FromString(module_str); -            if (module == NULL) -                goto exit; +        if (module == NULL) +            goto exit;      } -    if (category == NULL) -        category = PyExc_RuntimeWarning; -    res = warn_explicit(category, message, filename, lineno, module, registry, -                        NULL); -    if (res == NULL) -        goto exit; -    Py_DECREF(res); -    ret = 0; +    ret = PyErr_WarnExplicitObject(category, message, filename, lineno, +                                   module, registry);   exit:      Py_XDECREF(message); @@ -820,6 +862,49 @@ PyErr_WarnExplicit(PyObject *category, const char *text,      return ret;  } +int +PyErr_WarnExplicitFormat(PyObject *category, +                         const char *filename_str, int lineno, +                         const char *module_str, PyObject *registry, +                         const char *format, ...) +{ +    PyObject *message; +    PyObject *module = NULL; +    PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); +    int ret = -1; +    va_list vargs; + +    if (filename == NULL) +        goto exit; +    if (module_str != NULL) { +        module = PyUnicode_FromString(module_str); +        if (module == NULL) +            goto exit; +    } + +#ifdef HAVE_STDARG_PROTOTYPES +    va_start(vargs, format); +#else +    va_start(vargs); +#endif +    message = PyUnicode_FromFormatV(format, vargs); +    if (message != NULL) { +        PyObject *res; +        res = warn_explicit(category, message, filename, lineno, +                            module, registry, NULL); +        Py_DECREF(message); +        if (res != NULL) { +            Py_DECREF(res); +            ret = 0; +        } +    } +    va_end(vargs); +exit: +    Py_XDECREF(module); +    Py_XDECREF(filename); +    return ret; +} +  PyDoc_STRVAR(warn_doc,  "Issue a warning, or maybe ignore it or raise an exception."); | 
