mirror of
https://github.com/python/cpython.git
synced 2025-09-10 02:36:56 +00:00
Issue #22676: Make the pickling of global objects which don't have a __module__ attribute less slow.
This commit is contained in:
parent
7744cf7d5e
commit
fce60eaf15
2 changed files with 75 additions and 36 deletions
|
@ -181,6 +181,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #22676: Make the pickling of global objects which don't have a
|
||||||
|
__module__ attribute less slow.
|
||||||
|
|
||||||
- Issue #18853: Fixed ResourceWarning in shlex.__nain__.
|
- Issue #18853: Fixed ResourceWarning in shlex.__nain__.
|
||||||
|
|
||||||
- Issue #9351: Defaults set with set_defaults on an argparse subparser
|
- Issue #9351: Defaults set with set_defaults on an argparse subparser
|
||||||
|
|
|
@ -1535,18 +1535,18 @@ memo_put(PicklerObject *self, PyObject *obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
|
get_dotted_path(PyObject *obj, PyObject *name, int allow_qualname) {
|
||||||
PyObject *dotted_path;
|
|
||||||
Py_ssize_t i;
|
|
||||||
_Py_static_string(PyId_dot, ".");
|
_Py_static_string(PyId_dot, ".");
|
||||||
_Py_static_string(PyId_locals, "<locals>");
|
_Py_static_string(PyId_locals, "<locals>");
|
||||||
|
PyObject *dotted_path;
|
||||||
|
Py_ssize_t i, n;
|
||||||
|
|
||||||
dotted_path = PyUnicode_Split(name, _PyUnicode_FromId(&PyId_dot), -1);
|
dotted_path = PyUnicode_Split(name, _PyUnicode_FromId(&PyId_dot), -1);
|
||||||
if (dotted_path == NULL) {
|
if (dotted_path == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
n = PyList_GET_SIZE(dotted_path);
|
||||||
assert(Py_SIZE(dotted_path) >= 1);
|
assert(n >= 1);
|
||||||
if (!allow_qualname && Py_SIZE(dotted_path) > 1) {
|
if (!allow_qualname && n > 1) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"Can't get qualified attribute %R on %R;"
|
"Can't get qualified attribute %R on %R;"
|
||||||
"use protocols >= 4 to enable support",
|
"use protocols >= 4 to enable support",
|
||||||
|
@ -1554,10 +1554,8 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
|
||||||
Py_DECREF(dotted_path);
|
Py_DECREF(dotted_path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
Py_INCREF(obj);
|
for (i = 0; i < n; i++) {
|
||||||
for (i = 0; i < Py_SIZE(dotted_path); i++) {
|
|
||||||
PyObject *subpath = PyList_GET_ITEM(dotted_path, i);
|
PyObject *subpath = PyList_GET_ITEM(dotted_path, i);
|
||||||
PyObject *tmp;
|
|
||||||
PyObject *result = PyUnicode_RichCompare(
|
PyObject *result = PyUnicode_RichCompare(
|
||||||
subpath, _PyUnicode_FromId(&PyId_locals), Py_EQ);
|
subpath, _PyUnicode_FromId(&PyId_locals), Py_EQ);
|
||||||
int is_equal = (result == Py_True);
|
int is_equal = (result == Py_True);
|
||||||
|
@ -1567,37 +1565,69 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
PyErr_Format(PyExc_AttributeError,
|
||||||
"Can't get local attribute %R on %R", name, obj);
|
"Can't get local attribute %R on %R", name, obj);
|
||||||
Py_DECREF(dotted_path);
|
Py_DECREF(dotted_path);
|
||||||
Py_DECREF(obj);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
tmp = PyObject_GetAttr(obj, subpath);
|
}
|
||||||
|
return dotted_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
get_deep_attribute(PyObject *obj, PyObject *names)
|
||||||
|
{
|
||||||
|
Py_ssize_t i, n;
|
||||||
|
|
||||||
|
assert(PyList_CheckExact(names));
|
||||||
|
Py_INCREF(obj);
|
||||||
|
n = PyList_GET_SIZE(names);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
PyObject *name = PyList_GET_ITEM(names, i);
|
||||||
|
PyObject *tmp;
|
||||||
|
tmp = PyObject_GetAttr(obj, name);
|
||||||
Py_DECREF(obj);
|
Py_DECREF(obj);
|
||||||
if (tmp == NULL) {
|
if (tmp == NULL)
|
||||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
|
||||||
PyErr_Clear();
|
|
||||||
PyErr_Format(PyExc_AttributeError,
|
|
||||||
"Can't get attribute %R on %R", name, obj);
|
|
||||||
}
|
|
||||||
Py_DECREF(dotted_path);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
obj = tmp;
|
obj = tmp;
|
||||||
}
|
}
|
||||||
Py_DECREF(dotted_path);
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reformat_attribute_error(PyObject *obj, PyObject *name)
|
||||||
|
{
|
||||||
|
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
PyErr_Clear();
|
||||||
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
"Can't get attribute %R on %R", name, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
getattribute(PyObject *obj, PyObject *name, int allow_qualname)
|
||||||
|
{
|
||||||
|
PyObject *dotted_path, *attr;
|
||||||
|
|
||||||
|
dotted_path = get_dotted_path(obj, name, allow_qualname);
|
||||||
|
if (dotted_path == NULL)
|
||||||
|
return NULL;
|
||||||
|
attr = get_deep_attribute(obj, dotted_path);
|
||||||
|
Py_DECREF(dotted_path);
|
||||||
|
if (attr == NULL)
|
||||||
|
reformat_attribute_error(obj, name);
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
|
whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
|
||||||
{
|
{
|
||||||
PyObject *module_name;
|
PyObject *module_name;
|
||||||
PyObject *modules_dict;
|
PyObject *modules_dict;
|
||||||
PyObject *module;
|
PyObject *module;
|
||||||
PyObject *obj;
|
Py_ssize_t i;
|
||||||
Py_ssize_t i, j;
|
|
||||||
_Py_IDENTIFIER(__module__);
|
_Py_IDENTIFIER(__module__);
|
||||||
_Py_IDENTIFIER(modules);
|
_Py_IDENTIFIER(modules);
|
||||||
_Py_IDENTIFIER(__main__);
|
_Py_IDENTIFIER(__main__);
|
||||||
|
PyObject *dotted_path;
|
||||||
|
|
||||||
module_name = _PyObject_GetAttrId(global, &PyId___module__);
|
module_name = _PyObject_GetAttrId(global, &PyId___module__);
|
||||||
|
|
||||||
|
@ -1616,43 +1646,49 @@ whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
|
||||||
}
|
}
|
||||||
assert(module_name == NULL);
|
assert(module_name == NULL);
|
||||||
|
|
||||||
|
/* Fallback on walking sys.modules */
|
||||||
modules_dict = _PySys_GetObjectId(&PyId_modules);
|
modules_dict = _PySys_GetObjectId(&PyId_modules);
|
||||||
if (modules_dict == NULL) {
|
if (modules_dict == NULL) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
|
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dotted_path = get_dotted_path(module, global_name, allow_qualname);
|
||||||
|
if (dotted_path == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) {
|
while (PyDict_Next(modules_dict, &i, &module_name, &module)) {
|
||||||
PyObject *result = PyUnicode_RichCompare(
|
PyObject *candidate;
|
||||||
module_name, _PyUnicode_FromId(&PyId___main__), Py_EQ);
|
if (PyUnicode_Check(module_name) &&
|
||||||
int is_equal = (result == Py_True);
|
!PyUnicode_CompareWithASCIIString(module_name, "__main__"))
|
||||||
assert(PyBool_Check(result));
|
|
||||||
Py_DECREF(result);
|
|
||||||
if (is_equal)
|
|
||||||
continue;
|
continue;
|
||||||
if (module == Py_None)
|
if (module == Py_None)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
obj = getattribute(module, global_name, allow_qualname);
|
candidate = get_deep_attribute(module, dotted_path);
|
||||||
if (obj == NULL) {
|
if (candidate == NULL) {
|
||||||
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
|
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||||
|
Py_DECREF(dotted_path);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj == global) {
|
if (candidate == global) {
|
||||||
Py_DECREF(obj);
|
|
||||||
Py_INCREF(module_name);
|
Py_INCREF(module_name);
|
||||||
|
Py_DECREF(dotted_path);
|
||||||
|
Py_DECREF(candidate);
|
||||||
return module_name;
|
return module_name;
|
||||||
}
|
}
|
||||||
Py_DECREF(obj);
|
Py_DECREF(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If no module is found, use __main__. */
|
/* If no module is found, use __main__. */
|
||||||
module_name = _PyUnicode_FromId(&PyId___main__);
|
module_name = _PyUnicode_FromId(&PyId___main__);
|
||||||
Py_INCREF(module_name);
|
Py_INCREF(module_name);
|
||||||
|
Py_DECREF(dotted_path);
|
||||||
return module_name;
|
return module_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue