Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-31572: Get rid of _PyObject_HasAttrId() and PyDict_GetItemString() in warnings. #3731

Merged
merged 2 commits into from
Nov 11, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 89 additions & 68 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ get_warnings_attr(const char *attr, int try_import)
if (warnings_module == NULL) {
/* Fallback to the C implementation if we cannot get
the Python implementation */
PyErr_Clear();
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
PyErr_Clear();
}
return NULL;
}
}
Expand All @@ -62,13 +64,11 @@ get_warnings_attr(const char *attr, int try_import)
return NULL;
}

if (!PyObject_HasAttrString(warnings_module, attr)) {
Py_DECREF(warnings_module);
return NULL;
}

obj = PyObject_GetAttrString(warnings_module, attr);
Py_DECREF(warnings_module);
if (obj == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
return obj;
}

Expand All @@ -82,16 +82,18 @@ get_once_registry(void)
if (registry == NULL) {
if (PyErr_Occurred())
return NULL;
assert(_PyRuntime.warnings.once_registry);
return _PyRuntime.warnings.once_registry;
}
if (!PyDict_Check(registry)) {
PyErr_SetString(PyExc_TypeError,
"warnings.onceregistry must be a dict");
PyErr_Format(PyExc_TypeError,
MODULE_NAME ".onceregistry must be a dict, "
"not '%.200s'",
Py_TYPE(registry)->tp_name);
Py_DECREF(registry);
return NULL;
}
Py_DECREF(_PyRuntime.warnings.once_registry);
_PyRuntime.warnings.once_registry = registry;
Py_SETREF(_PyRuntime.warnings.once_registry, registry);
return registry;
}

Expand All @@ -106,6 +108,7 @@ get_default_action(void)
if (PyErr_Occurred()) {
return NULL;
}
assert(_PyRuntime.warnings.default_action);
return _PyRuntime.warnings.default_action;
}
if (!PyUnicode_Check(default_action)) {
Expand All @@ -116,8 +119,7 @@ get_default_action(void)
Py_DECREF(default_action);
return NULL;
}
Py_DECREF(_PyRuntime.warnings.default_action);
_PyRuntime.warnings.default_action = default_action;
Py_SETREF(_PyRuntime.warnings.default_action, default_action);
return default_action;
}

Expand All @@ -137,8 +139,7 @@ get_filter(PyObject *category, PyObject *text, Py_ssize_t lineno,
return NULL;
}
else {
Py_DECREF(_PyRuntime.warnings.filters);
_PyRuntime.warnings.filters = warnings_filters;
Py_SETREF(_PyRuntime.warnings.filters, warnings_filters);
}

PyObject *filters = _PyRuntime.warnings.filters;
Expand Down Expand Up @@ -408,8 +409,10 @@ call_show_warning(PyObject *category, PyObject *text, PyObject *message,

warnmsg_cls = get_warnings_attr("WarningMessage", 0);
if (warnmsg_cls == NULL) {
PyErr_SetString(PyExc_RuntimeError,
"unable to get warnings.WarningMessage");
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError,
"unable to get warnings.WarningMessage");
}
goto error;
}

Expand Down Expand Up @@ -837,6 +840,68 @@ warnings_warn_impl(PyObject *module, PyObject *message, PyObject *category,
return do_warn(message, category, stacklevel, source);
}

static PyObject *
get_source_line(PyObject *module_globals, int lineno)
{
_Py_IDENTIFIER(get_source);
_Py_IDENTIFIER(__loader__);
_Py_IDENTIFIER(__name__);
PyObject *loader;
PyObject *module_name;
PyObject *get_source;
PyObject *source;
PyObject *source_list;
PyObject *source_line;

/* Check/get the requisite pieces needed for the loader. */
loader = _PyDict_GetItemIdWithError(module_globals, &PyId___loader__);
if (loader == NULL) {
return NULL;
}
Py_INCREF(loader);
module_name = _PyDict_GetItemIdWithError(module_globals, &PyId___name__);
if (!module_name) {
Py_DECREF(loader);
return NULL;
}
Py_INCREF(module_name);

/* Make sure the loader implements the optional get_source() method. */
get_source = _PyObject_GetAttrId(loader, &PyId_get_source);
Py_DECREF(loader);
if (!get_source) {
Py_DECREF(module_name);
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
return NULL;
}
/* Call get_source() to get the source code. */
source = PyObject_CallFunctionObjArgs(get_source, module_name, NULL);
Py_DECREF(get_source);
Py_DECREF(module_name);
if (!source) {
return NULL;
}
if (source == Py_None) {
Py_DECREF(source);
return NULL;
}

/* Split the source into lines. */
source_list = PyUnicode_Splitlines(source, 0);
Py_DECREF(source);
if (!source_list) {
return NULL;
}

/* Get the source line. */
source_line = PyList_GetItem(source_list, lineno-1);
Py_XINCREF(source_line);
Py_DECREF(source_list);
return source_line;
}

static PyObject *
warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
{
Expand All @@ -851,68 +916,24 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds)
PyObject *registry = NULL;
PyObject *module_globals = NULL;
PyObject *sourceobj = NULL;
PyObject *source_line = NULL;
PyObject *returned;

if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOUi|OOOO:warn_explicit",
kwd_list, &message, &category, &filename, &lineno, &module,
&registry, &module_globals, &sourceobj))
return NULL;

if (module_globals) {
_Py_IDENTIFIER(get_source);
PyObject *tmp;
PyObject *loader;
PyObject *module_name;
PyObject *source;
PyObject *source_list;
PyObject *source_line;
PyObject *returned;

if ((tmp = _PyUnicode_FromId(&PyId_get_source)) == NULL)
return NULL;

/* Check/get the requisite pieces needed for the loader. */
loader = PyDict_GetItemString(module_globals, "__loader__");
module_name = PyDict_GetItemString(module_globals, "__name__");

if (loader == NULL || module_name == NULL)
goto standard_call;

/* Make sure the loader implements the optional get_source() method. */
if (!_PyObject_HasAttrId(loader, &PyId_get_source))
goto standard_call;
/* Call get_source() to get the source code. */
source = PyObject_CallMethodObjArgs(loader, PyId_get_source.object,
module_name, NULL);
if (!source)
source_line = get_source_line(module_globals, lineno);
if (source_line == NULL && PyErr_Occurred()) {
return NULL;
else if (source == Py_None) {
Py_DECREF(Py_None);
goto standard_call;
}

/* Split the source into lines. */
source_list = PyUnicode_Splitlines(source, 0);
Py_DECREF(source);
if (!source_list)
return NULL;

/* Get the source line. */
source_line = PyList_GetItem(source_list, lineno-1);
if (!source_line) {
Py_DECREF(source_list);
return NULL;
}

/* Handle the warning. */
returned = warn_explicit(category, message, filename, lineno, module,
registry, source_line, sourceobj);
Py_DECREF(source_list);
return returned;
}

standard_call:
return warn_explicit(category, message, filename, lineno, module,
registry, NULL, sourceobj);
returned = warn_explicit(category, message, filename, lineno, module,
registry, source_line, sourceobj);
Py_XDECREF(source_line);
return returned;
}

static PyObject *
Expand Down