summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2017-11-22 22:51:42 (GMT)
committerGitHub <noreply@github.com>2017-11-22 22:51:42 (GMT)
commit82656276caf4cb889193572d2d14dbc5f3d2bdff (patch)
tree19060972ab524aa7962ca411f079cfa14ec614fa
parentbb11c3c967afaf263e00844d4ab461b7fafd6d36 (diff)
downloadcpython-82656276caf4cb889193572d2d14dbc5f3d2bdff.zip
cpython-82656276caf4cb889193572d2d14dbc5f3d2bdff.tar.gz
cpython-82656276caf4cb889193572d2d14dbc5f3d2bdff.tar.bz2
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
-rw-r--r--Lib/warnings.py17
-rw-r--r--Python/_warnings.c75
2 files changed, 47 insertions, 45 deletions
diff --git a/Lib/warnings.py b/Lib/warnings.py
index b2605f8..5b62569 100644
--- a/Lib/warnings.py
+++ b/Lib/warnings.py
@@ -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).
diff --git a/Python/_warnings.c b/Python/_warnings.c
index f2110ed..d865f0a 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.c
@@ -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);
}