|
|
|
@ -15,6 +15,134 @@ _Py_IDENTIFIER(default); |
|
|
|
_Py_IDENTIFIER(ignore); |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
typedef struct _warnings_runtime_state WarningsState; |
|
|
|
|
|
|
|
/* Forward declaration of the _warnings module definition. */ |
|
|
|
static struct PyModuleDef warningsmodule; |
|
|
|
|
|
|
|
/* Given a module object, get its per-module state. */ |
|
|
|
static WarningsState * |
|
|
|
_Warnings_GetState() |
|
|
|
{ |
|
|
|
PyThreadState *tstate = PyThreadState_GET(); |
|
|
|
if (tstate == NULL) { |
|
|
|
PyErr_SetString(PyExc_RuntimeError, |
|
|
|
"_Warnings_GetState: could not identify current interpreter"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
return &tstate->interp->warnings; |
|
|
|
} |
|
|
|
|
|
|
|
/* Clear the given warnings module state. */ |
|
|
|
static void |
|
|
|
_Warnings_ClearState(WarningsState *st) |
|
|
|
{ |
|
|
|
Py_CLEAR(st->filters); |
|
|
|
Py_CLEAR(st->once_registry); |
|
|
|
Py_CLEAR(st->default_action); |
|
|
|
} |
|
|
|
|
|
|
|
#ifndef Py_DEBUG |
|
|
|
static PyObject * |
|
|
|
create_filter(PyObject *category, _Py_Identifier *id, const char *modname) |
|
|
|
{ |
|
|
|
PyObject *modname_obj = NULL; |
|
|
|
PyObject *action_str = _PyUnicode_FromId(id); |
|
|
|
if (action_str == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* Default to "no module name" for initial filter set */ |
|
|
|
if (modname != NULL) { |
|
|
|
modname_obj = PyUnicode_InternFromString(modname); |
|
|
|
if (modname_obj == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} else { |
|
|
|
modname_obj = Py_None; |
|
|
|
} |
|
|
|
|
|
|
|
/* This assumes the line number is zero for now. */ |
|
|
|
return PyTuple_Pack(5, action_str, Py_None, |
|
|
|
category, modname_obj, _PyLong_Zero); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
static PyObject * |
|
|
|
init_filters(void) |
|
|
|
{ |
|
|
|
#ifdef Py_DEBUG |
|
|
|
/* Py_DEBUG builds show all warnings by default */ |
|
|
|
return PyList_New(0); |
|
|
|
#else |
|
|
|
/* Other builds ignore a number of warning categories by default */ |
|
|
|
PyObject *filters = PyList_New(5); |
|
|
|
if (filters == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
size_t pos = 0; /* Post-incremented in each use. */ |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_DeprecationWarning, &PyId_default, "__main__")); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_ImportWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL)); |
|
|
|
|
|
|
|
for (size_t x = 0; x < pos; x++) { |
|
|
|
if (PyList_GET_ITEM(filters, x) == NULL) { |
|
|
|
Py_DECREF(filters); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
return filters; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
/* Initialize the given warnings module state. */ |
|
|
|
static int |
|
|
|
_Warnings_InitState(WarningsState *st) |
|
|
|
{ |
|
|
|
if (st->filters == NULL) { |
|
|
|
st->filters = init_filters(); |
|
|
|
if (st->filters == NULL) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (st->once_registry == NULL) { |
|
|
|
st->once_registry = PyDict_New(); |
|
|
|
if (st->once_registry == NULL) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (st->default_action == NULL) { |
|
|
|
st->default_action = PyUnicode_FromString("default"); |
|
|
|
if (st->default_action == NULL) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
st->filters_version = 0; |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
error: |
|
|
|
_Warnings_ClearState(st); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************/ |
|
|
|
|
|
|
|
static int |
|
|
|
check_matched(PyObject *obj, PyObject *arg) |
|
|
|
{ |
|
|
|
@ -93,7 +221,7 @@ get_warnings_attr(_Py_Identifier *attr_id, int try_import) |
|
|
|
|
|
|
|
|
|
|
|
static PyObject * |
|
|
|
get_once_registry(void) |
|
|
|
get_once_registry(WarningsState *st) |
|
|
|
{ |
|
|
|
PyObject *registry; |
|
|
|
_Py_IDENTIFIER(onceregistry); |
|
|
|
@ -102,8 +230,8 @@ get_once_registry(void) |
|
|
|
if (registry == NULL) { |
|
|
|
if (PyErr_Occurred()) |
|
|
|
return NULL; |
|
|
|
assert(_PyRuntime.warnings.once_registry); |
|
|
|
return _PyRuntime.warnings.once_registry; |
|
|
|
assert(st->once_registry); |
|
|
|
return st->once_registry; |
|
|
|
} |
|
|
|
if (!PyDict_Check(registry)) { |
|
|
|
PyErr_Format(PyExc_TypeError, |
|
|
|
@ -113,13 +241,13 @@ get_once_registry(void) |
|
|
|
Py_DECREF(registry); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
Py_SETREF(_PyRuntime.warnings.once_registry, registry); |
|
|
|
Py_SETREF(st->once_registry, registry); |
|
|
|
return registry; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static PyObject * |
|
|
|
get_default_action(void) |
|
|
|
get_default_action(WarningsState *st) |
|
|
|
{ |
|
|
|
PyObject *default_action; |
|
|
|
_Py_IDENTIFIER(defaultaction); |
|
|
|
@ -129,8 +257,8 @@ get_default_action(void) |
|
|
|
if (PyErr_Occurred()) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
assert(_PyRuntime.warnings.default_action); |
|
|
|
return _PyRuntime.warnings.default_action; |
|
|
|
assert(st->default_action); |
|
|
|
return st->default_action; |
|
|
|
} |
|
|
|
if (!PyUnicode_Check(default_action)) { |
|
|
|
PyErr_Format(PyExc_TypeError, |
|
|
|
@ -140,7 +268,7 @@ get_default_action(void) |
|
|
|
Py_DECREF(default_action); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
Py_SETREF(_PyRuntime.warnings.default_action, default_action); |
|
|
|
Py_SETREF(st->default_action, default_action); |
|
|
|
return default_action; |
|
|
|
} |
|
|
|
|
|
|
|
@ -154,6 +282,10 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, |
|
|
|
Py_ssize_t i; |
|
|
|
PyObject *warnings_filters; |
|
|
|
_Py_IDENTIFIER(filters); |
|
|
|
WarningsState *st = _Warnings_GetState(); |
|
|
|
if (st == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
warnings_filters = get_warnings_attr(&PyId_filters, 0); |
|
|
|
if (warnings_filters == NULL) { |
|
|
|
@ -161,17 +293,17 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
else { |
|
|
|
Py_SETREF(_PyRuntime.warnings.filters, warnings_filters); |
|
|
|
Py_SETREF(st->filters, warnings_filters); |
|
|
|
} |
|
|
|
|
|
|
|
PyObject *filters = _PyRuntime.warnings.filters; |
|
|
|
PyObject *filters = st->filters; |
|
|
|
if (filters == NULL || !PyList_Check(filters)) { |
|
|
|
PyErr_SetString(PyExc_ValueError, |
|
|
|
MODULE_NAME ".filters must be a list"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* _PyRuntime.warnings.filters could change while we are iterating over it. */ |
|
|
|
/* WarningsState.filters could change while we are iterating over it. */ |
|
|
|
for (i = 0; i < PyList_GET_SIZE(filters); i++) { |
|
|
|
PyObject *tmp_item, *action, *msg, *cat, *mod, *ln_obj; |
|
|
|
Py_ssize_t ln; |
|
|
|
@ -232,7 +364,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno, |
|
|
|
Py_DECREF(tmp_item); |
|
|
|
} |
|
|
|
|
|
|
|
action = get_default_action(); |
|
|
|
action = get_default_action(st); |
|
|
|
if (action != NULL) { |
|
|
|
Py_INCREF(Py_None); |
|
|
|
*item = Py_None; |
|
|
|
@ -252,16 +384,20 @@ already_warned(PyObject *registry, PyObject *key, int should_set) |
|
|
|
if (key == NULL) |
|
|
|
return -1; |
|
|
|
|
|
|
|
WarningsState *st = _Warnings_GetState(); |
|
|
|
if (st == NULL) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
version_obj = _PyDict_GetItemIdWithError(registry, &PyId_version); |
|
|
|
if (version_obj == NULL |
|
|
|
|| !PyLong_CheckExact(version_obj) |
|
|
|
|| PyLong_AsLong(version_obj) != _PyRuntime.warnings.filters_version) |
|
|
|
|| PyLong_AsLong(version_obj) != st->filters_version) |
|
|
|
{ |
|
|
|
if (PyErr_Occurred()) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
PyDict_Clear(registry); |
|
|
|
version_obj = PyLong_FromLong(_PyRuntime.warnings.filters_version); |
|
|
|
version_obj = PyLong_FromLong(st->filters_version); |
|
|
|
if (version_obj == NULL) |
|
|
|
return -1; |
|
|
|
if (_PyDict_SetItemId(registry, &PyId_version, version_obj) < 0) { |
|
|
|
@ -567,11 +703,15 @@ warn_explicit(PyObject *category, PyObject *message, |
|
|
|
|
|
|
|
if (_PyUnicode_EqualToASCIIString(action, "once")) { |
|
|
|
if (registry == NULL || registry == Py_None) { |
|
|
|
registry = get_once_registry(); |
|
|
|
WarningsState *st = _Warnings_GetState(); |
|
|
|
if (st == NULL) { |
|
|
|
goto cleanup; |
|
|
|
} |
|
|
|
registry = get_once_registry(st); |
|
|
|
if (registry == NULL) |
|
|
|
goto cleanup; |
|
|
|
} |
|
|
|
/* _PyRuntime.warnings.once_registry[(text, category)] = 1 */ |
|
|
|
/* WarningsState.once_registry[(text, category)] = 1 */ |
|
|
|
rc = update_registry(registry, text, category, 0); |
|
|
|
} |
|
|
|
else if (_PyUnicode_EqualToASCIIString(action, "module")) { |
|
|
|
@ -925,7 +1065,11 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) |
|
|
|
static PyObject * |
|
|
|
warnings_filters_mutated(PyObject *self, PyObject *args) |
|
|
|
{ |
|
|
|
_PyRuntime.warnings.filters_version++; |
|
|
|
WarningsState *st = _Warnings_GetState(); |
|
|
|
if (st == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
st->filters_version++; |
|
|
|
Py_RETURN_NONE; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1175,78 +1319,16 @@ static PyMethodDef warnings_functions[] = { |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
#ifndef Py_DEBUG |
|
|
|
static PyObject * |
|
|
|
create_filter(PyObject *category, _Py_Identifier *id, const char *modname) |
|
|
|
{ |
|
|
|
PyObject *modname_obj = NULL; |
|
|
|
PyObject *action_str = _PyUnicode_FromId(id); |
|
|
|
if (action_str == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* Default to "no module name" for initial filter set */ |
|
|
|
if (modname != NULL) { |
|
|
|
modname_obj = PyUnicode_InternFromString(modname); |
|
|
|
if (modname_obj == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} else { |
|
|
|
modname_obj = Py_None; |
|
|
|
} |
|
|
|
|
|
|
|
/* This assumes the line number is zero for now. */ |
|
|
|
return PyTuple_Pack(5, action_str, Py_None, |
|
|
|
category, modname_obj, _PyLong_Zero); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
static PyObject * |
|
|
|
init_filters(void) |
|
|
|
{ |
|
|
|
#ifdef Py_DEBUG |
|
|
|
/* Py_DEBUG builds show all warnings by default */ |
|
|
|
return PyList_New(0); |
|
|
|
#else |
|
|
|
/* Other builds ignore a number of warning categories by default */ |
|
|
|
PyObject *filters = PyList_New(5); |
|
|
|
if (filters == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
size_t pos = 0; /* Post-incremented in each use. */ |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_DeprecationWarning, &PyId_default, "__main__")); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_DeprecationWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_PendingDeprecationWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_ImportWarning, &PyId_ignore, NULL)); |
|
|
|
PyList_SET_ITEM(filters, pos++, |
|
|
|
create_filter(PyExc_ResourceWarning, &PyId_ignore, NULL)); |
|
|
|
|
|
|
|
for (size_t x = 0; x < pos; x++) { |
|
|
|
if (PyList_GET_ITEM(filters, x) == NULL) { |
|
|
|
Py_DECREF(filters); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
return filters; |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
static struct PyModuleDef warningsmodule = { |
|
|
|
PyModuleDef_HEAD_INIT, |
|
|
|
MODULE_NAME, |
|
|
|
warnings__doc__, |
|
|
|
0, |
|
|
|
warnings_functions, |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
NULL |
|
|
|
MODULE_NAME, /* m_name */ |
|
|
|
warnings__doc__, /* m_doc */ |
|
|
|
0, /* m_size */ |
|
|
|
warnings_functions, /* m_methods */ |
|
|
|
NULL, /* m_reload */ |
|
|
|
NULL, /* m_traverse */ |
|
|
|
NULL, /* m_clear */ |
|
|
|
NULL /* m_free */ |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -1256,49 +1338,46 @@ _PyWarnings_Init(void) |
|
|
|
PyObject *m; |
|
|
|
|
|
|
|
m = PyModule_Create(&warningsmodule); |
|
|
|
if (m == NULL) |
|
|
|
if (m == NULL) { |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
struct _warnings_runtime_state *state = &_PyRuntime.warnings; |
|
|
|
if (state->filters == NULL) { |
|
|
|
state->filters = init_filters(); |
|
|
|
if (state->filters == NULL) |
|
|
|
return NULL; |
|
|
|
WarningsState *st = _Warnings_GetState(); |
|
|
|
if (st == NULL) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
if (_Warnings_InitState(st) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
Py_INCREF(state->filters); |
|
|
|
if (PyModule_AddObject(m, "filters", state->filters) < 0) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (state->once_registry == NULL) { |
|
|
|
state->once_registry = PyDict_New(); |
|
|
|
if (state->once_registry == NULL) |
|
|
|
return NULL; |
|
|
|
Py_INCREF(st->filters); |
|
|
|
if (PyModule_AddObject(m, "filters", st->filters) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
Py_INCREF(state->once_registry); |
|
|
|
if (PyModule_AddObject(m, "_onceregistry", |
|
|
|
state->once_registry) < 0) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
if (state->default_action == NULL) { |
|
|
|
state->default_action = PyUnicode_FromString("default"); |
|
|
|
if (state->default_action == NULL) |
|
|
|
return NULL; |
|
|
|
Py_INCREF(st->once_registry); |
|
|
|
if (PyModule_AddObject(m, "_onceregistry", st->once_registry) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
Py_INCREF(st->default_action); |
|
|
|
if (PyModule_AddObject(m, "_defaultaction", st->default_action) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
Py_INCREF(state->default_action); |
|
|
|
if (PyModule_AddObject(m, "_defaultaction", |
|
|
|
state->default_action) < 0) |
|
|
|
return NULL; |
|
|
|
|
|
|
|
state->filters_version = 0; |
|
|
|
return m; |
|
|
|
} |
|
|
|
|
|
|
|
error: |
|
|
|
if (st != NULL) { |
|
|
|
_Warnings_ClearState(st); |
|
|
|
} |
|
|
|
Py_DECREF(m); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
// We need this to ensure that warnings still work until late in finalization. |
|
|
|
void |
|
|
|
_PyWarnings_Fini(_PyRuntimeState *runtime) |
|
|
|
_PyWarnings_Fini(PyInterpreterState *interp) |
|
|
|
{ |
|
|
|
struct _warnings_runtime_state *state = &runtime->warnings; |
|
|
|
Py_CLEAR(state->filters); |
|
|
|
Py_CLEAR(state->once_registry); |
|
|
|
Py_CLEAR(state->default_action); |
|
|
|
_Warnings_ClearState(&interp->warnings); |
|
|
|
} |