bpo-27535: Optimize warnings.warn() (#4508)
* Optimize warnings.filterwarnings(). Replace re.compile('') with None to avoid the cost of calling a regex.match() method, whereas it always matchs. * Optimize get_warnings_attr(): replace PyObject_GetAttrString() with _PyObject_GetAttrId(). Cleanup also create_filter(): * Use _Py_IDENTIFIER() to allow to cleanup strings at Python finalization * Replace Py_FatalError() with a regular exceptions
This commit is contained in:
parent
bb11c3c967
commit
82656276ca
|
@ -128,7 +128,6 @@ def filterwarnings(action, message="", category=Warning, module="", lineno=0,
|
|||
'lineno' -- an integer line number, 0 matches all warnings
|
||||
'append' -- if true, append to the list of filters
|
||||
"""
|
||||
import re
|
||||
assert action in ("error", "ignore", "always", "default", "module",
|
||||
"once"), "invalid action: %r" % (action,)
|
||||
assert isinstance(message, str), "message must be a string"
|
||||
|
@ -137,8 +136,20 @@ def filterwarnings(action, message="", category=Warning, module="", lineno=0,
|
|||
assert isinstance(module, str), "module must be a string"
|
||||
assert isinstance(lineno, int) and lineno >= 0, \
|
||||
"lineno must be an int >= 0"
|
||||
_add_filter(action, re.compile(message, re.I), category,
|
||||
re.compile(module), lineno, append=append)
|
||||
|
||||
if message or module:
|
||||
import re
|
||||
|
||||
if message:
|
||||
message = re.compile(message, re.I)
|
||||
else:
|
||||
message = None
|
||||
if module:
|
||||
module = re.compile(module)
|
||||
else:
|
||||
module = None
|
||||
|
||||
_add_filter(action, message, category, module, lineno, append=append)
|
||||
|
||||
def simplefilter(action, category=Warning, lineno=0, append=False):
|
||||
"""Insert a simple entry into the list of warnings filters (at the front).
|
||||
|
|
|
@ -35,15 +35,15 @@ check_matched(PyObject *obj, PyObject *arg)
|
|||
A NULL return value can mean false or an error.
|
||||
*/
|
||||
static PyObject *
|
||||
get_warnings_attr(const char *attr, int try_import)
|
||||
get_warnings_attr(_Py_Identifier *attr_id, int try_import)
|
||||
{
|
||||
static PyObject *warnings_str = NULL;
|
||||
PyObject *warnings_str;
|
||||
PyObject *warnings_module, *obj;
|
||||
_Py_IDENTIFIER(warnings);
|
||||
|
||||
warnings_str = _PyUnicode_FromId(&PyId_warnings);
|
||||
if (warnings_str == NULL) {
|
||||
warnings_str = PyUnicode_InternFromString("warnings");
|
||||
if (warnings_str == NULL)
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* don't try to import after the start of the Python finallization */
|
||||
|
@ -64,7 +64,7 @@ get_warnings_attr(const char *attr, int try_import)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
obj = PyObject_GetAttrString(warnings_module, attr);
|
||||
obj = _PyObject_GetAttrId(warnings_module, attr_id);
|
||||
Py_DECREF(warnings_module);
|
||||
if (obj == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
|
@ -77,8 +77,9 @@ static PyObject *
|
|||
get_once_registry(void)
|
||||
{
|
||||
PyObject *registry;
|
||||
_Py_IDENTIFIER(onceregistry);
|
||||
|
||||
registry = get_warnings_attr("onceregistry", 0);
|
||||
registry = get_warnings_attr(&PyId_onceregistry, 0);
|
||||
if (registry == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
@ -102,8 +103,9 @@ static PyObject *
|
|||
get_default_action(void)
|
||||
{
|
||||
PyObject *default_action;
|
||||
_Py_IDENTIFIER(defaultaction);
|
||||
|
||||
default_action = get_warnings_attr("defaultaction", 0);
|
||||
default_action = get_warnings_attr(&PyId_defaultaction, 0);
|
||||
if (default_action == NULL) {
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
|
@ -132,8 +134,9 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
|
|||
PyObject *action;
|
||||
Py_ssize_t i;
|
||||
PyObject *warnings_filters;
|
||||
_Py_IDENTIFIER(filters);
|
||||
|
||||
warnings_filters = get_warnings_attr("filters", 0);
|
||||
warnings_filters = get_warnings_attr(&PyId_filters, 0);
|
||||
if (warnings_filters == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
return NULL;
|
||||
|
@ -389,11 +392,13 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,
|
|||
PyObject *sourceline, PyObject *source)
|
||||
{
|
||||
PyObject *show_fn, *msg, *res, *warnmsg_cls = NULL;
|
||||
_Py_IDENTIFIER(_showwarnmsg);
|
||||
_Py_IDENTIFIER(WarningMessage);
|
||||
|
||||
/* If the source parameter is set, try to get the Python implementation.
|
||||
The Python implementation is able to log the traceback where the source
|
||||
was allocated, whereas the C implementation doesn't. */
|
||||
show_fn = get_warnings_attr("_showwarnmsg", source != NULL);
|
||||
show_fn = get_warnings_attr(&PyId__showwarnmsg, source != NULL);
|
||||
if (show_fn == NULL) {
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
|
@ -407,7 +412,7 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,
|
|||
goto error;
|
||||
}
|
||||
|
||||
warnmsg_cls = get_warnings_attr("WarningMessage", 0);
|
||||
warnmsg_cls = get_warnings_attr(&PyId_WarningMessage, 0);
|
||||
if (warnmsg_cls == NULL) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
|
@ -1146,50 +1151,36 @@ static PyMethodDef warnings_functions[] = {
|
|||
static PyObject *
|
||||
create_filter(PyObject *category, const char *action)
|
||||
{
|
||||
static PyObject *ignore_str = NULL;
|
||||
static PyObject *error_str = NULL;
|
||||
static PyObject *default_str = NULL;
|
||||
static PyObject *always_str = NULL;
|
||||
PyObject *action_obj = NULL;
|
||||
_Py_IDENTIFIER(ignore);
|
||||
_Py_IDENTIFIER(error);
|
||||
_Py_IDENTIFIER(always);
|
||||
_Py_static_string(PyId_default, "default");
|
||||
_Py_Identifier *id;
|
||||
|
||||
if (!strcmp(action, "ignore")) {
|
||||
if (ignore_str == NULL) {
|
||||
ignore_str = PyUnicode_InternFromString("ignore");
|
||||
if (ignore_str == NULL)
|
||||
return NULL;
|
||||
}
|
||||
action_obj = ignore_str;
|
||||
id = &PyId_ignore;
|
||||
}
|
||||
else if (!strcmp(action, "error")) {
|
||||
if (error_str == NULL) {
|
||||
error_str = PyUnicode_InternFromString("error");
|
||||
if (error_str == NULL)
|
||||
return NULL;
|
||||
}
|
||||
action_obj = error_str;
|
||||
id = &PyId_error;
|
||||
}
|
||||
else if (!strcmp(action, "default")) {
|
||||
if (default_str == NULL) {
|
||||
default_str = PyUnicode_InternFromString("default");
|
||||
if (default_str == NULL)
|
||||
return NULL;
|
||||
}
|
||||
action_obj = default_str;
|
||||
id = &PyId_default;
|
||||
}
|
||||
else if (!strcmp(action, "always")) {
|
||||
if (always_str == NULL) {
|
||||
always_str = PyUnicode_InternFromString("always");
|
||||
if (always_str == NULL)
|
||||
return NULL;
|
||||
}
|
||||
action_obj = always_str;
|
||||
id = &PyId_always;
|
||||
}
|
||||
else {
|
||||
Py_FatalError("unknown action");
|
||||
PyErr_SetString(PyExc_ValueError, "unknown action");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *action_str = _PyUnicode_FromId(id);
|
||||
if (action_str == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This assumes the line number is zero for now. */
|
||||
return PyTuple_Pack(5, action_obj, Py_None,
|
||||
return PyTuple_Pack(5, action_str, Py_None,
|
||||
category, Py_None, _PyLong_Zero);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue