mirror of
https://github.com/python/cpython.git
synced 2025-07-28 13:44:43 +00:00
Add a DeprecationWarning for when warnings.showwarning() is set to a function
that lacks support for the new 'line' argument.
This commit is contained in:
parent
9ae080ee5a
commit
8a232cc385
5 changed files with 90 additions and 16 deletions
|
@ -220,7 +220,8 @@ Available Functions
|
||||||
``warnings.showwarning``.
|
``warnings.showwarning``.
|
||||||
|
|
||||||
.. versionchanged:: 2.6
|
.. versionchanged:: 2.6
|
||||||
Added the *line* argument.
|
Added the *line* argument. Implementations that lack the new argument
|
||||||
|
will trigger a :exc:`DeprecationWarning`.
|
||||||
|
|
||||||
|
|
||||||
.. function:: formatwarning(message, category, filename, lineno[, line])
|
.. function:: formatwarning(message, category, filename, lineno[, line])
|
||||||
|
|
|
@ -461,6 +461,32 @@ class PyWarningsDisplayTests(BaseTest, WarningsDisplayTests):
|
||||||
module = py_warnings
|
module = py_warnings
|
||||||
|
|
||||||
|
|
||||||
|
class ShowwarningDeprecationTests(BaseTest):
|
||||||
|
|
||||||
|
"""Test the deprecation of the old warnings.showwarning() API works."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bad_showwarning(message, category, filename, lineno, file=None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_deprecation(self):
|
||||||
|
# message, category, filename, lineno[, file[, line]]
|
||||||
|
args = ("message", UserWarning, "file name", 42)
|
||||||
|
with test_support.catch_warning(self.module):
|
||||||
|
self.module.filterwarnings("error", category=DeprecationWarning)
|
||||||
|
self.module.showwarning = self.bad_showwarning
|
||||||
|
self.assertRaises(DeprecationWarning, self.module.warn_explicit,
|
||||||
|
*args)
|
||||||
|
|
||||||
|
class CShowwarningDeprecationTests(ShowwarningDeprecationTests):
|
||||||
|
module = c_warnings
|
||||||
|
|
||||||
|
|
||||||
|
class PyShowwarningDeprecationTests(ShowwarningDeprecationTests):
|
||||||
|
module = py_warnings
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
py_warnings.onceregistry.clear()
|
py_warnings.onceregistry.clear()
|
||||||
c_warnings.onceregistry.clear()
|
c_warnings.onceregistry.clear()
|
||||||
|
@ -471,6 +497,8 @@ def test_main():
|
||||||
CWCmdLineTests, PyWCmdLineTests,
|
CWCmdLineTests, PyWCmdLineTests,
|
||||||
_WarningsTests,
|
_WarningsTests,
|
||||||
CWarningsDisplayTests, PyWarningsDisplayTests,
|
CWarningsDisplayTests, PyWarningsDisplayTests,
|
||||||
|
CShowwarningDeprecationTests,
|
||||||
|
PyShowwarningDeprecationTests,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# Note: function level imports should *not* be used
|
# Note: function level imports should *not* be used
|
||||||
# in this module as it may cause import lock deadlock.
|
# in this module as it may cause import lock deadlock.
|
||||||
# See bug 683658.
|
# See bug 683658.
|
||||||
|
import inspect
|
||||||
import linecache
|
import linecache
|
||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
|
@ -21,7 +22,7 @@ def warnpy3k(message, category=None, stacklevel=1):
|
||||||
category = DeprecationWarning
|
category = DeprecationWarning
|
||||||
warn(message, category, stacklevel+1)
|
warn(message, category, stacklevel+1)
|
||||||
|
|
||||||
def showwarning(message, category, filename, lineno, file=None, line=None):
|
def _show_warning(message, category, filename, lineno, file=None, line=None):
|
||||||
"""Hook to write a warning to a file; replace if you like."""
|
"""Hook to write a warning to a file; replace if you like."""
|
||||||
if file is None:
|
if file is None:
|
||||||
file = sys.stderr
|
file = sys.stderr
|
||||||
|
@ -29,6 +30,9 @@ def showwarning(message, category, filename, lineno, file=None, line=None):
|
||||||
file.write(formatwarning(message, category, filename, lineno, line))
|
file.write(formatwarning(message, category, filename, lineno, line))
|
||||||
except IOError:
|
except IOError:
|
||||||
pass # the file (probably stderr) is invalid - this warning gets lost.
|
pass # the file (probably stderr) is invalid - this warning gets lost.
|
||||||
|
# Keep a worrking version around in case the deprecation of the old API is
|
||||||
|
# triggered.
|
||||||
|
showwarning = _show_warning
|
||||||
|
|
||||||
def formatwarning(message, category, filename, lineno, line=None):
|
def formatwarning(message, category, filename, lineno, line=None):
|
||||||
"""Function to format a warning the standard way."""
|
"""Function to format a warning the standard way."""
|
||||||
|
@ -259,6 +263,15 @@ 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
|
||||||
|
if inspect.isfunction(showwarning):
|
||||||
|
arg_spec = inspect.getargspec(showwarning)
|
||||||
|
if 'line' not in arg_spec.args:
|
||||||
|
showwarning_msg = ("functions overriding warnings.showwarning() "
|
||||||
|
"must support the 'line' argument")
|
||||||
|
if message == showwarning_msg:
|
||||||
|
_show_warning(message, category, filename, lineno)
|
||||||
|
else:
|
||||||
|
warn(showwarning_msg, DeprecationWarning)
|
||||||
showwarning(message, category, filename, lineno)
|
showwarning(message, category, filename, lineno)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,9 @@ Extension Modules
|
||||||
machinery in such places as the parser where use of pure Python code is not
|
machinery in such places as the parser where use of pure Python code is not
|
||||||
possible. Both the ``showarning()`` and ``formatwarning()`` gain an
|
possible. Both the ``showarning()`` and ``formatwarning()`` gain an
|
||||||
optional 'line' argument which is not called by default for
|
optional 'line' argument which is not called by default for
|
||||||
backwards-compatibility reasons.
|
backwards-compatibility reasons. Setting ``warnings.showwarning()`` to
|
||||||
|
an implementation that lacks support for the ``line`` argument will raise a
|
||||||
|
DeprecationWarning.
|
||||||
|
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -229,8 +229,8 @@ static void
|
||||||
show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
|
show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
|
||||||
*category, PyObject *sourceline)
|
*category, PyObject *sourceline)
|
||||||
{
|
{
|
||||||
PyObject *f_stderr;
|
PyObject *f_stderr;
|
||||||
PyObject *name;
|
PyObject *name;
|
||||||
char lineno_str[128];
|
char lineno_str[128];
|
||||||
|
|
||||||
PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
|
PyOS_snprintf(lineno_str, sizeof(lineno_str), ":%d: ", lineno);
|
||||||
|
@ -272,7 +272,7 @@ show_warning(PyObject *filename, int lineno, PyObject *text, PyObject
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
@ -347,12 +347,12 @@ warn_explicit(PyObject *category, PyObject *message,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
/* _once_registry[(text, category)] = 1 */
|
/* _once_registry[(text, category)] = 1 */
|
||||||
rc = update_registry(registry, text, category, 0);
|
rc = update_registry(registry, text, category, 0);
|
||||||
}
|
}
|
||||||
else if (strcmp(action, "module") == 0) {
|
else if (strcmp(action, "module") == 0) {
|
||||||
/* registry[(text, category, 0)] = 1 */
|
/* registry[(text, category, 0)] = 1 */
|
||||||
if (registry != NULL)
|
if (registry != NULL)
|
||||||
rc = update_registry(registry, text, category, 0);
|
rc = update_registry(registry, text, category, 0);
|
||||||
}
|
}
|
||||||
else if (strcmp(action, "default") != 0) {
|
else if (strcmp(action, "default") != 0) {
|
||||||
PyObject *to_str = PyObject_Str(item);
|
PyObject *to_str = PyObject_Str(item);
|
||||||
|
@ -378,15 +378,45 @@ warn_explicit(PyObject *category, PyObject *message,
|
||||||
show_warning(filename, lineno, text, category, sourceline);
|
show_warning(filename, lineno, text, category, sourceline);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyObject *res;
|
const char *msg = "functions overriding warnings.showwarning() "
|
||||||
|
"must support the 'line' argument";
|
||||||
res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
|
const char *text_char = PyString_AS_STRING(text);
|
||||||
|
|
||||||
|
if (strcmp(msg, text_char) == 0) {
|
||||||
|
/* Prevent infinite recursion by using built-in implementation
|
||||||
|
of showwarning(). */
|
||||||
|
show_warning(filename, lineno, text, category, sourceline);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyObject *check_fxn;
|
||||||
|
PyObject *defaults;
|
||||||
|
PyObject *res;
|
||||||
|
|
||||||
|
if (PyMethod_Check(show_fxn))
|
||||||
|
check_fxn = PyMethod_Function(show_fxn);
|
||||||
|
else if (PyFunction_Check(show_fxn))
|
||||||
|
check_fxn = show_fxn;
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"warnings.showwarning() must be set to a "
|
||||||
|
"function or method");
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults = PyFunction_GetDefaults(check_fxn);
|
||||||
|
/* A proper implementation of warnings.showwarning() should
|
||||||
|
have at least two default arguments. */
|
||||||
|
if ((defaults == NULL) || (PyTuple_Size(defaults) < 2)) {
|
||||||
|
if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
res = PyObject_CallFunctionObjArgs(show_fxn, message, category,
|
||||||
filename, lineno_obj,
|
filename, lineno_obj,
|
||||||
NULL);
|
NULL);
|
||||||
Py_DECREF(show_fxn);
|
Py_DECREF(show_fxn);
|
||||||
Py_XDECREF(res);
|
Py_XDECREF(res);
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* if (rc == -1) */
|
else /* if (rc == -1) */
|
||||||
|
@ -578,7 +608,7 @@ warnings_warn(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
PyObject *message, *category = NULL;
|
PyObject *message, *category = NULL;
|
||||||
Py_ssize_t stack_level = 1;
|
Py_ssize_t stack_level = 1;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|On:warn", kw_list,
|
||||||
&message, &category, &stack_level))
|
&message, &category, &stack_level))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue