mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
A more nuanced approach to Python warnings.
By default some Python warning messages would be written to standard error by the interpreter. To prevent these warnings from making a mess of the ELinks screen, all warnings were turned into exceptions so they could be caught and displayed through the usual report_scripting_error() mechanism. With Python 3.2, this approach backfires: A new class of ResourceWarnings that are filtered by default (and hence would *not* have been written to standard error) are now turned into exceptions, and these exceptions can't be caught because they're emitted from the interpreter's cleanup code. As a result, the uncaught exceptions would make a mess of the ELinks screen. The new solution is to replace Python's standard library function warnings.showwarning() with one that turns warning messages into exceptions. This means we'll wait until a warning would have been written to standard error before turning it into an exception, so other warnings that would never have reached that point because they're filtered will remain unseen. (The behavior of warning messages is described in the documentation for the "warnings" module from Python's standard library.)
This commit is contained in:
parent
91515990c8
commit
a229adb19a
@ -156,6 +156,72 @@ end:
|
||||
return found_hooks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Turn any warnings that aren't filtered into exceptions so they can be caught
|
||||
* and handled; otherwise they would be printed to stderr.
|
||||
*/
|
||||
|
||||
static char python_showwarnings_doc[] =
|
||||
PYTHON_DOCSTRING("showwarnings(message, category, filename, lineno, \
|
||||
file=None, line=None)\n\
|
||||
\n\
|
||||
Report a Python warning as an ELinks scripting error.\n\
|
||||
\n\
|
||||
Arguments:\n\
|
||||
\n\
|
||||
message -- An instance of the class Warning (or a subclass).\n\
|
||||
\n\
|
||||
All other arguments are ignored.\n");
|
||||
|
||||
static PyCFunction *
|
||||
python_showwarning(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyObject *warning;
|
||||
|
||||
if (!PyTuple_Check(args)) {
|
||||
PyErr_Format(PyExc_TypeError, "expected a tuple, got '%s'",
|
||||
args->ob_type->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
warning = PyTuple_GetItem(args, 0);
|
||||
if (warning) PyErr_SetObject((PyObject *) warning->ob_type, warning);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyMethodDef warning_methods[] = {
|
||||
{"showwarning", (PyCFunction) python_showwarning,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
python_showwarnings_doc},
|
||||
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
/* Replace the standard warnings.showwarning() function. */
|
||||
|
||||
static int
|
||||
replace_showwarning(void)
|
||||
{
|
||||
PyObject *warnings_module = NULL, *module_name = NULL, *module_dict;
|
||||
int result = -1;
|
||||
|
||||
warnings_module = PyImport_ImportModule("warnings");
|
||||
if (!warnings_module) goto end;
|
||||
module_name = PyString_FromString("warnings");
|
||||
if (!module_name) goto end;
|
||||
module_dict = PyModule_GetDict(warnings_module);
|
||||
if (!module_dict) goto end;
|
||||
|
||||
if (add_python_methods(module_dict, module_name, warning_methods) != 0)
|
||||
goto end;
|
||||
|
||||
result = 0;
|
||||
|
||||
end:
|
||||
Py_XDECREF(warnings_module);
|
||||
Py_XDECREF(module_name);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Module-level documentation for the Python interpreter's elinks module. */
|
||||
|
||||
static char module_doc[] =
|
||||
@ -191,21 +257,12 @@ init_python(struct module *module)
|
||||
|
||||
if (set_python_search_path() != 0) return;
|
||||
|
||||
/* Treat warnings as errors so they can be caught and handled;
|
||||
* otherwise they would be printed to stderr.
|
||||
*
|
||||
* NOTE: PySys_ResetWarnOptions() and PySys_AddWarnOption() have been
|
||||
* available and stable for many years but they're not officially
|
||||
* documented as part of Python's public API, so in theory these two
|
||||
* functions might no longer be available in some hypothetical future
|
||||
* version of Python. */
|
||||
PySys_ResetWarnOptions();
|
||||
PySys_AddWarnOption("error");
|
||||
|
||||
Py_Initialize();
|
||||
|
||||
if (!hooks_module_exists()) return;
|
||||
|
||||
if (replace_showwarning() != 0) goto python_error;
|
||||
|
||||
elinks_module = Py_InitModule3("elinks", NULL, module_doc);
|
||||
if (!elinks_module) goto python_error;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user