On ResourceWarning, log traceback where the object was allocated
Issue #26567: * Add a new function PyErr_ResourceWarning() function to pass the destroyed object * Add a source attribute to warnings.WarningMessage * Add warnings._showwarnmsg() which uses tracemalloc to get the traceback where source object was allocated.
This commit is contained in:
parent
1231a4615f
commit
914cde89d4
|
@ -334,6 +334,14 @@ an error value).
|
||||||
.. versionadded:: 3.2
|
.. versionadded:: 3.2
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level, const char *format, ...)
|
||||||
|
|
||||||
|
Function similar to :c:func:`PyErr_WarnFormat`, but *category* is
|
||||||
|
:exc:`ResourceWarning` and pass *source* to :func:`warnings.WarningMessage`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.6
|
||||||
|
|
||||||
|
|
||||||
Querying the error indicator
|
Querying the error indicator
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
|
|
@ -319,7 +319,7 @@ Available Functions
|
||||||
of the warning message).
|
of the warning message).
|
||||||
|
|
||||||
|
|
||||||
.. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None)
|
.. function:: warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)
|
||||||
|
|
||||||
This is a low-level interface to the functionality of :func:`warn`, passing in
|
This is a low-level interface to the functionality of :func:`warn`, passing in
|
||||||
explicitly the message, category, filename and line number, and optionally the
|
explicitly the message, category, filename and line number, and optionally the
|
||||||
|
@ -335,6 +335,12 @@ Available Functions
|
||||||
source for modules found in zipfiles or other non-filesystem import
|
source for modules found in zipfiles or other non-filesystem import
|
||||||
sources).
|
sources).
|
||||||
|
|
||||||
|
*source*, if supplied, is the destroyed object which emitted a
|
||||||
|
:exc:`ResourceWarning`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.6
|
||||||
|
Add the *source* parameter.
|
||||||
|
|
||||||
|
|
||||||
.. function:: showwarning(message, category, filename, lineno, file=None, line=None)
|
.. function:: showwarning(message, category, filename, lineno, file=None, line=None)
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,40 @@ urllib.robotparser
|
||||||
(Contributed by Nikolay Bogoychev in :issue:`16099`.)
|
(Contributed by Nikolay Bogoychev in :issue:`16099`.)
|
||||||
|
|
||||||
|
|
||||||
|
warnings
|
||||||
|
--------
|
||||||
|
|
||||||
|
A new optional *source* parameter has been added to the
|
||||||
|
:func:`warnings.warn_explicit` function: the destroyed object which emitted a
|
||||||
|
:exc:`ResourceWarning`. A *source* attribute has also been added to
|
||||||
|
:class:`warnings.WarningMessage` (contributed by Victor Stinner in
|
||||||
|
:issue:`26568` and :issue:`26567`).
|
||||||
|
|
||||||
|
When a :exc:`ResourceWarning` warning is logged, the :mod:`tracemalloc` is now
|
||||||
|
used to try to retrieve the traceback where the detroyed object was allocated.
|
||||||
|
|
||||||
|
Example with the script ``example.py``::
|
||||||
|
|
||||||
|
def func():
|
||||||
|
f = open(__file__)
|
||||||
|
f = None
|
||||||
|
|
||||||
|
func()
|
||||||
|
|
||||||
|
Output of the command ``python3.6 -Wd -X tracemalloc=5 example.py``::
|
||||||
|
|
||||||
|
example.py:3: ResourceWarning: unclosed file <...>
|
||||||
|
f = None
|
||||||
|
Object allocated at (most recent call first):
|
||||||
|
File "example.py", lineno 2
|
||||||
|
f = open(__file__)
|
||||||
|
File "example.py", lineno 5
|
||||||
|
func()
|
||||||
|
|
||||||
|
The "Object allocated at" traceback is new and only displayed if
|
||||||
|
:mod:`tracemalloc` is tracing Python memory allocations.
|
||||||
|
|
||||||
|
|
||||||
zipfile
|
zipfile
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,13 @@ PyAPI_FUNC(int) PyErr_WarnFormat(
|
||||||
Py_ssize_t stack_level,
|
Py_ssize_t stack_level,
|
||||||
const char *format, /* ASCII-encoded string */
|
const char *format, /* ASCII-encoded string */
|
||||||
...);
|
...);
|
||||||
|
|
||||||
|
/* Emit a ResourceWarning warning */
|
||||||
|
PyAPI_FUNC(int) PyErr_ResourceWarning(
|
||||||
|
PyObject *source,
|
||||||
|
Py_ssize_t stack_level,
|
||||||
|
const char *format, /* ASCII-encoded string */
|
||||||
|
...);
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
PyAPI_FUNC(int) PyErr_WarnExplicitObject(
|
PyAPI_FUNC(int) PyErr_WarnExplicitObject(
|
||||||
PyObject *category,
|
PyObject *category,
|
||||||
|
|
|
@ -2,7 +2,10 @@ from contextlib import contextmanager
|
||||||
import linecache
|
import linecache
|
||||||
import os
|
import os
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support.script_helper import assert_python_ok, assert_python_failure
|
from test.support.script_helper import assert_python_ok, assert_python_failure
|
||||||
|
@ -763,12 +766,39 @@ class WarningsDisplayTests(BaseTest):
|
||||||
file_object, expected_file_line)
|
file_object, expected_file_line)
|
||||||
self.assertEqual(expect, file_object.getvalue())
|
self.assertEqual(expect, file_object.getvalue())
|
||||||
|
|
||||||
|
|
||||||
class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
|
class CWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
|
||||||
module = c_warnings
|
module = c_warnings
|
||||||
|
|
||||||
class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
|
class PyWarningsDisplayTests(WarningsDisplayTests, unittest.TestCase):
|
||||||
module = py_warnings
|
module = py_warnings
|
||||||
|
|
||||||
|
def test_tracemalloc(self):
|
||||||
|
with tempfile.NamedTemporaryFile("w", suffix=".py") as tmpfile:
|
||||||
|
tmpfile.write(textwrap.dedent("""
|
||||||
|
def func():
|
||||||
|
f = open(__file__)
|
||||||
|
# Emit ResourceWarning
|
||||||
|
f = None
|
||||||
|
|
||||||
|
func()
|
||||||
|
"""))
|
||||||
|
tmpfile.flush()
|
||||||
|
fname = tmpfile.name
|
||||||
|
res = assert_python_ok('-Wd', '-X', 'tracemalloc=2', fname)
|
||||||
|
stderr = res.err.decode('ascii', 'replace')
|
||||||
|
stderr = re.sub('<.*>', '<...>', stderr)
|
||||||
|
expected = textwrap.dedent(f'''
|
||||||
|
{fname}:5: ResourceWarning: unclosed file <...>
|
||||||
|
f = None
|
||||||
|
Object allocated at (most recent call first):
|
||||||
|
File "{fname}", lineno 3
|
||||||
|
f = open(__file__)
|
||||||
|
File "{fname}", lineno 7
|
||||||
|
func()
|
||||||
|
''').strip()
|
||||||
|
self.assertEqual(stderr, expected)
|
||||||
|
|
||||||
|
|
||||||
class CatchWarningTests(BaseTest):
|
class CatchWarningTests(BaseTest):
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["warn", "warn_explicit", "showwarning",
|
__all__ = ["warn", "warn_explicit", "showwarning",
|
||||||
"formatwarning", "filterwarnings", "simplefilter",
|
"formatwarning", "filterwarnings", "simplefilter",
|
||||||
"resetwarnings", "catch_warnings"]
|
"resetwarnings", "catch_warnings"]
|
||||||
|
@ -66,6 +67,18 @@ def _formatwarnmsg(msg):
|
||||||
if line:
|
if line:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
s += " %s\n" % line
|
s += " %s\n" % line
|
||||||
|
if msg.source is not None:
|
||||||
|
import tracemalloc
|
||||||
|
tb = tracemalloc.get_object_traceback(msg.source)
|
||||||
|
if tb is not None:
|
||||||
|
s += 'Object allocated at (most recent call first):\n'
|
||||||
|
for frame in tb:
|
||||||
|
s += (' File "%s", lineno %s\n'
|
||||||
|
% (frame.filename, frame.lineno))
|
||||||
|
line = linecache.getline(frame.filename, frame.lineno)
|
||||||
|
if line:
|
||||||
|
line = line.strip()
|
||||||
|
s += ' %s\n' % line
|
||||||
return s
|
return s
|
||||||
|
|
||||||
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
|
def filterwarnings(action, message="", category=Warning, module="", lineno=0,
|
||||||
|
@ -267,7 +280,8 @@ def warn(message, category=None, stacklevel=1):
|
||||||
globals)
|
globals)
|
||||||
|
|
||||||
def warn_explicit(message, category, filename, lineno,
|
def warn_explicit(message, category, filename, lineno,
|
||||||
module=None, registry=None, module_globals=None):
|
module=None, registry=None, module_globals=None,
|
||||||
|
source=None):
|
||||||
lineno = int(lineno)
|
lineno = int(lineno)
|
||||||
if module is None:
|
if module is None:
|
||||||
module = filename or "<unknown>"
|
module = filename or "<unknown>"
|
||||||
|
@ -333,17 +347,17 @@ def warn_explicit(message, category, filename, lineno,
|
||||||
"Unrecognized action (%r) in warnings.filters:\n %s" %
|
"Unrecognized action (%r) in warnings.filters:\n %s" %
|
||||||
(action, item))
|
(action, item))
|
||||||
# Print message and context
|
# Print message and context
|
||||||
msg = WarningMessage(message, category, filename, lineno)
|
msg = WarningMessage(message, category, filename, lineno, source)
|
||||||
_showwarnmsg(msg)
|
_showwarnmsg(msg)
|
||||||
|
|
||||||
|
|
||||||
class WarningMessage(object):
|
class WarningMessage(object):
|
||||||
|
|
||||||
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
|
_WARNING_DETAILS = ("message", "category", "filename", "lineno", "file",
|
||||||
"line")
|
"line", "source")
|
||||||
|
|
||||||
def __init__(self, message, category, filename, lineno, file=None,
|
def __init__(self, message, category, filename, lineno, file=None,
|
||||||
line=None):
|
line=None, source=None):
|
||||||
local_values = locals()
|
local_values = locals()
|
||||||
for attr in self._WARNING_DETAILS:
|
for attr in self._WARNING_DETAILS:
|
||||||
setattr(self, attr, local_values[attr])
|
setattr(self, attr, local_values[attr])
|
||||||
|
|
|
@ -226,6 +226,11 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #26567: Add a new function :c:func:`PyErr_ResourceWarning` function to
|
||||||
|
pass the destroyed object. Add a *source* attribute to
|
||||||
|
:class:`warnings.WarningMessage`. Add warnings._showwarnmsg() which uses
|
||||||
|
tracemalloc to get the traceback where source object was allocated.
|
||||||
|
|
||||||
- Issue #26313: ssl.py _load_windows_store_certs fails if windows cert store
|
- Issue #26313: ssl.py _load_windows_store_certs fails if windows cert store
|
||||||
is empty. Patch by Baji.
|
is empty. Patch by Baji.
|
||||||
|
|
||||||
|
|
|
@ -92,8 +92,7 @@ fileio_dealloc_warn(fileio *self, PyObject *source)
|
||||||
if (self->fd >= 0 && self->closefd) {
|
if (self->fd >= 0 && self->closefd) {
|
||||||
PyObject *exc, *val, *tb;
|
PyObject *exc, *val, *tb;
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
PyErr_Fetch(&exc, &val, &tb);
|
||||||
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
|
if (PyErr_ResourceWarning(source, 1, "unclosed file %R", source)) {
|
||||||
"unclosed file %R", source)) {
|
|
||||||
/* Spurious errors can appear at shutdown */
|
/* Spurious errors can appear at shutdown */
|
||||||
if (PyErr_ExceptionMatches(PyExc_Warning))
|
if (PyErr_ExceptionMatches(PyExc_Warning))
|
||||||
PyErr_WriteUnraisable((PyObject *) self);
|
PyErr_WriteUnraisable((PyObject *) self);
|
||||||
|
|
|
@ -12111,8 +12111,8 @@ ScandirIterator_dealloc(ScandirIterator *iterator)
|
||||||
*/
|
*/
|
||||||
++Py_REFCNT(iterator);
|
++Py_REFCNT(iterator);
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
PyErr_Fetch(&exc, &val, &tb);
|
||||||
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
|
if (PyErr_ResourceWarning((PyObject *)iterator, 1,
|
||||||
"unclosed scandir iterator %R", iterator)) {
|
"unclosed scandir iterator %R", iterator)) {
|
||||||
/* Spurious errors can appear at shutdown */
|
/* Spurious errors can appear at shutdown */
|
||||||
if (PyErr_ExceptionMatches(PyExc_Warning))
|
if (PyErr_ExceptionMatches(PyExc_Warning))
|
||||||
PyErr_WriteUnraisable((PyObject *) iterator);
|
PyErr_WriteUnraisable((PyObject *) iterator);
|
||||||
|
|
|
@ -4170,8 +4170,7 @@ sock_dealloc(PySocketSockObject *s)
|
||||||
Py_ssize_t old_refcount = Py_REFCNT(s);
|
Py_ssize_t old_refcount = Py_REFCNT(s);
|
||||||
++Py_REFCNT(s);
|
++Py_REFCNT(s);
|
||||||
PyErr_Fetch(&exc, &val, &tb);
|
PyErr_Fetch(&exc, &val, &tb);
|
||||||
if (PyErr_WarnFormat(PyExc_ResourceWarning, 1,
|
if (PyErr_ResourceWarning(s, 1, "unclosed %R", s))
|
||||||
"unclosed %R", s))
|
|
||||||
/* Spurious errors can appear at shutdown */
|
/* Spurious errors can appear at shutdown */
|
||||||
if (PyErr_ExceptionMatches(PyExc_Warning))
|
if (PyErr_ExceptionMatches(PyExc_Warning))
|
||||||
PyErr_WriteUnraisable((PyObject *) s);
|
PyErr_WriteUnraisable((PyObject *) s);
|
||||||
|
|
|
@ -287,8 +287,8 @@ update_registry(PyObject *registry, PyObject *text, PyObject *category,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
|
show_warning(PyObject *filename, int lineno, PyObject *text,
|
||||||
*category, PyObject *sourceline)
|
PyObject *category, PyObject *sourceline)
|
||||||
{
|
{
|
||||||
PyObject *f_stderr;
|
PyObject *f_stderr;
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
|
@ -362,7 +362,7 @@ error:
|
||||||
static int
|
static int
|
||||||
call_show_warning(PyObject *category, PyObject *text, PyObject *message,
|
call_show_warning(PyObject *category, PyObject *text, PyObject *message,
|
||||||
PyObject *filename, int lineno, PyObject *lineno_obj,
|
PyObject *filename, int lineno, PyObject *lineno_obj,
|
||||||
PyObject *sourceline)
|
PyObject *sourceline, PyObject *source)
|
||||||
{
|
{
|
||||||
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
|
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category,
|
msg = PyObject_CallFunctionObjArgs(warnmsg_cls, message, category,
|
||||||
filename, lineno_obj,
|
filename, lineno_obj, Py_None, Py_None, source,
|
||||||
NULL);
|
NULL);
|
||||||
Py_DECREF(warnmsg_cls);
|
Py_DECREF(warnmsg_cls);
|
||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
|
@ -412,7 +412,8 @@ error:
|
||||||
static PyObject *
|
static PyObject *
|
||||||
warn_explicit(PyObject *category, PyObject *message,
|
warn_explicit(PyObject *category, PyObject *message,
|
||||||
PyObject *filename, int lineno,
|
PyObject *filename, int lineno,
|
||||||
PyObject *module, PyObject *registry, PyObject *sourceline)
|
PyObject *module, PyObject *registry, PyObject *sourceline,
|
||||||
|
PyObject *source)
|
||||||
{
|
{
|
||||||
PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
|
PyObject *key = NULL, *text = NULL, *result = NULL, *lineno_obj = NULL;
|
||||||
PyObject *item = NULL;
|
PyObject *item = NULL;
|
||||||
|
@ -521,7 +522,7 @@ warn_explicit(PyObject *category, PyObject *message,
|
||||||
goto return_none;
|
goto return_none;
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (call_show_warning(category, text, message, filename, lineno,
|
if (call_show_warning(category, text, message, filename, lineno,
|
||||||
lineno_obj, sourceline) < 0)
|
lineno_obj, sourceline, source) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
else /* if (rc == -1) */
|
else /* if (rc == -1) */
|
||||||
|
@ -766,7 +767,8 @@ get_category(PyObject *message, PyObject *category)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level)
|
do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level,
|
||||||
|
PyObject *source)
|
||||||
{
|
{
|
||||||
PyObject *filename, *module, *registry, *res;
|
PyObject *filename, *module, *registry, *res;
|
||||||
int lineno;
|
int lineno;
|
||||||
|
@ -775,7 +777,7 @@ do_warn(PyObject *message, PyObject *category, Py_ssize_t stack_level)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
res = warn_explicit(category, message, filename, lineno, module, registry,
|
res = warn_explicit(category, message, filename, lineno, module, registry,
|
||||||
NULL);
|
NULL, source);
|
||||||
Py_DECREF(filename);
|
Py_DECREF(filename);
|
||||||
Py_DECREF(registry);
|
Py_DECREF(registry);
|
||||||
Py_DECREF(module);
|
Py_DECREF(module);
|
||||||
|
@ -796,14 +798,15 @@ warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
category = get_category(message, category);
|
category = get_category(message, category);
|
||||||
if (category == NULL)
|
if (category == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
return do_warn(message, category, stack_level);
|
return do_warn(message, category, stack_level, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
|
warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
static char *kwd_list[] = {"message", "category", "filename", "lineno",
|
static char *kwd_list[] = {"message", "category", "filename", "lineno",
|
||||||
"module", "registry", "module_globals", 0};
|
"module", "registry", "module_globals",
|
||||||
|
"source", 0};
|
||||||
PyObject *message;
|
PyObject *message;
|
||||||
PyObject *category;
|
PyObject *category;
|
||||||
PyObject *filename;
|
PyObject *filename;
|
||||||
|
@ -811,10 +814,11 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
PyObject *module = NULL;
|
PyObject *module = NULL;
|
||||||
PyObject *registry = NULL;
|
PyObject *registry = NULL;
|
||||||
PyObject *module_globals = NULL;
|
PyObject *module_globals = NULL;
|
||||||
|
PyObject *sourceobj = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOO:warn_explicit",
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOOO:warn_explicit",
|
||||||
kwd_list, &message, &category, &filename, &lineno, &module,
|
kwd_list, &message, &category, &filename, &lineno, &module,
|
||||||
®istry, &module_globals))
|
®istry, &module_globals, &sourceobj))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (module_globals) {
|
if (module_globals) {
|
||||||
|
@ -870,14 +874,14 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
|
|
||||||
/* Handle the warning. */
|
/* Handle the warning. */
|
||||||
returned = warn_explicit(category, message, filename, lineno, module,
|
returned = warn_explicit(category, message, filename, lineno, module,
|
||||||
registry, source_line);
|
registry, source_line, sourceobj);
|
||||||
Py_DECREF(source_list);
|
Py_DECREF(source_list);
|
||||||
return returned;
|
return returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
standard_call:
|
standard_call:
|
||||||
return warn_explicit(category, message, filename, lineno, module,
|
return warn_explicit(category, message, filename, lineno, module,
|
||||||
registry, NULL);
|
registry, NULL, sourceobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -892,14 +896,14 @@ warnings_filters_mutated(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
warn_unicode(PyObject *category, PyObject *message,
|
warn_unicode(PyObject *category, PyObject *message,
|
||||||
Py_ssize_t stack_level)
|
Py_ssize_t stack_level, PyObject *source)
|
||||||
{
|
{
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
|
|
||||||
if (category == NULL)
|
if (category == NULL)
|
||||||
category = PyExc_RuntimeWarning;
|
category = PyExc_RuntimeWarning;
|
||||||
|
|
||||||
res = do_warn(message, category, stack_level);
|
res = do_warn(message, category, stack_level, source);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
|
@ -907,12 +911,28 @@ warn_unicode(PyObject *category, PyObject *message,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_PyErr_WarnFormatV(PyObject *source,
|
||||||
|
PyObject *category, Py_ssize_t stack_level,
|
||||||
|
const char *format, va_list vargs)
|
||||||
|
{
|
||||||
|
PyObject *message;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
message = PyUnicode_FromFormatV(format, vargs);
|
||||||
|
if (message == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
res = warn_unicode(category, message, stack_level, source);
|
||||||
|
Py_DECREF(message);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level,
|
PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level,
|
||||||
const char *format, ...)
|
const char *format, ...)
|
||||||
{
|
{
|
||||||
int ret;
|
int res;
|
||||||
PyObject *message;
|
|
||||||
va_list vargs;
|
va_list vargs;
|
||||||
|
|
||||||
#ifdef HAVE_STDARG_PROTOTYPES
|
#ifdef HAVE_STDARG_PROTOTYPES
|
||||||
|
@ -920,17 +940,30 @@ PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level,
|
||||||
#else
|
#else
|
||||||
va_start(vargs);
|
va_start(vargs);
|
||||||
#endif
|
#endif
|
||||||
message = PyUnicode_FromFormatV(format, vargs);
|
res = _PyErr_WarnFormatV(NULL, category, stack_level, format, vargs);
|
||||||
if (message != NULL) {
|
|
||||||
ret = warn_unicode(category, message, stack_level);
|
|
||||||
Py_DECREF(message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = -1;
|
|
||||||
va_end(vargs);
|
va_end(vargs);
|
||||||
return ret;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyErr_ResourceWarning(PyObject *source, Py_ssize_t stack_level,
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
va_list vargs;
|
||||||
|
|
||||||
|
#ifdef HAVE_STDARG_PROTOTYPES
|
||||||
|
va_start(vargs, format);
|
||||||
|
#else
|
||||||
|
va_start(vargs);
|
||||||
|
#endif
|
||||||
|
res = _PyErr_WarnFormatV(source, PyExc_ResourceWarning,
|
||||||
|
stack_level, format, vargs);
|
||||||
|
va_end(vargs);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
|
PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
|
||||||
{
|
{
|
||||||
|
@ -938,7 +971,7 @@ PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
|
||||||
PyObject *message = PyUnicode_FromString(text);
|
PyObject *message = PyUnicode_FromString(text);
|
||||||
if (message == NULL)
|
if (message == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
ret = warn_unicode(category, message, stack_level);
|
ret = warn_unicode(category, message, stack_level, NULL);
|
||||||
Py_DECREF(message);
|
Py_DECREF(message);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -964,7 +997,7 @@ PyErr_WarnExplicitObject(PyObject *category, PyObject *message,
|
||||||
if (category == NULL)
|
if (category == NULL)
|
||||||
category = PyExc_RuntimeWarning;
|
category = PyExc_RuntimeWarning;
|
||||||
res = warn_explicit(category, message, filename, lineno,
|
res = warn_explicit(category, message, filename, lineno,
|
||||||
module, registry, NULL);
|
module, registry, NULL, NULL);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
|
@ -1028,7 +1061,7 @@ PyErr_WarnExplicitFormat(PyObject *category,
|
||||||
if (message != NULL) {
|
if (message != NULL) {
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
res = warn_explicit(category, message, filename, lineno,
|
res = warn_explicit(category, message, filename, lineno,
|
||||||
module, registry, NULL);
|
module, registry, NULL, NULL);
|
||||||
Py_DECREF(message);
|
Py_DECREF(message);
|
||||||
if (res != NULL) {
|
if (res != NULL) {
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
|
|
Loading…
Reference in New Issue