Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fce60ea

Browse files
committed
Issue #22676: Make the pickling of global objects which don't have a __module__ attribute less slow.
1 parent 7744cf7 commit fce60ea

File tree

2 files changed

+75
-36
lines changed

2 files changed

+75
-36
lines changed

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ Core and Builtins
181181
Library
182182
-------
183183

184+
- Issue #22676: Make the pickling of global objects which don't have a
185+
__module__ attribute less slow.
186+
184187
- Issue #18853: Fixed ResourceWarning in shlex.__nain__.
185188

186189
- Issue #9351: Defaults set with set_defaults on an argparse subparser

Modules/_pickle.c

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,29 +1535,27 @@ memo_put(PicklerObject *self, PyObject *obj)
15351535
}
15361536

15371537
static PyObject *
1538-
getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
1539-
PyObject *dotted_path;
1540-
Py_ssize_t i;
1538+
get_dotted_path(PyObject *obj, PyObject *name, int allow_qualname) {
15411539
_Py_static_string(PyId_dot, ".");
15421540
_Py_static_string(PyId_locals, "<locals>");
1541+
PyObject *dotted_path;
1542+
Py_ssize_t i, n;
15431543

15441544
dotted_path = PyUnicode_Split(name, _PyUnicode_FromId(&PyId_dot), -1);
1545-
if (dotted_path == NULL) {
1545+
if (dotted_path == NULL)
15461546
return NULL;
1547-
}
1548-
assert(Py_SIZE(dotted_path) >= 1);
1549-
if (!allow_qualname && Py_SIZE(dotted_path) > 1) {
1547+
n = PyList_GET_SIZE(dotted_path);
1548+
assert(n >= 1);
1549+
if (!allow_qualname && n > 1) {
15501550
PyErr_Format(PyExc_AttributeError,
15511551
"Can't get qualified attribute %R on %R;"
15521552
"use protocols >= 4 to enable support",
15531553
name, obj);
15541554
Py_DECREF(dotted_path);
15551555
return NULL;
15561556
}
1557-
Py_INCREF(obj);
1558-
for (i = 0; i < Py_SIZE(dotted_path); i++) {
1557+
for (i = 0; i < n; i++) {
15591558
PyObject *subpath = PyList_GET_ITEM(dotted_path, i);
1560-
PyObject *tmp;
15611559
PyObject *result = PyUnicode_RichCompare(
15621560
subpath, _PyUnicode_FromId(&PyId_locals), Py_EQ);
15631561
int is_equal = (result == Py_True);
@@ -1567,37 +1565,69 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
15671565
PyErr_Format(PyExc_AttributeError,
15681566
"Can't get local attribute %R on %R", name, obj);
15691567
Py_DECREF(dotted_path);
1570-
Py_DECREF(obj);
15711568
return NULL;
15721569
}
1573-
tmp = PyObject_GetAttr(obj, subpath);
1570+
}
1571+
return dotted_path;
1572+
}
1573+
1574+
static PyObject *
1575+
get_deep_attribute(PyObject *obj, PyObject *names)
1576+
{
1577+
Py_ssize_t i, n;
1578+
1579+
assert(PyList_CheckExact(names));
1580+
Py_INCREF(obj);
1581+
n = PyList_GET_SIZE(names);
1582+
for (i = 0; i < n; i++) {
1583+
PyObject *name = PyList_GET_ITEM(names, i);
1584+
PyObject *tmp;
1585+
tmp = PyObject_GetAttr(obj, name);
15741586
Py_DECREF(obj);
1575-
if (tmp == NULL) {
1576-
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
1577-
PyErr_Clear();
1578-
PyErr_Format(PyExc_AttributeError,
1579-
"Can't get attribute %R on %R", name, obj);
1580-
}
1581-
Py_DECREF(dotted_path);
1587+
if (tmp == NULL)
15821588
return NULL;
1583-
}
15841589
obj = tmp;
15851590
}
1586-
Py_DECREF(dotted_path);
15871591
return obj;
15881592
}
15891593

1594+
static void
1595+
reformat_attribute_error(PyObject *obj, PyObject *name)
1596+
{
1597+
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
1598+
PyErr_Clear();
1599+
PyErr_Format(PyExc_AttributeError,
1600+
"Can't get attribute %R on %R", name, obj);
1601+
}
1602+
}
1603+
1604+
1605+
static PyObject *
1606+
getattribute(PyObject *obj, PyObject *name, int allow_qualname)
1607+
{
1608+
PyObject *dotted_path, *attr;
1609+
1610+
dotted_path = get_dotted_path(obj, name, allow_qualname);
1611+
if (dotted_path == NULL)
1612+
return NULL;
1613+
attr = get_deep_attribute(obj, dotted_path);
1614+
Py_DECREF(dotted_path);
1615+
if (attr == NULL)
1616+
reformat_attribute_error(obj, name);
1617+
return attr;
1618+
}
1619+
15901620
static PyObject *
15911621
whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
15921622
{
15931623
PyObject *module_name;
15941624
PyObject *modules_dict;
15951625
PyObject *module;
1596-
PyObject *obj;
1597-
Py_ssize_t i, j;
1626+
Py_ssize_t i;
15981627
_Py_IDENTIFIER(__module__);
15991628
_Py_IDENTIFIER(modules);
16001629
_Py_IDENTIFIER(__main__);
1630+
PyObject *dotted_path;
16011631

16021632
module_name = _PyObject_GetAttrId(global, &PyId___module__);
16031633

@@ -1616,43 +1646,49 @@ whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
16161646
}
16171647
assert(module_name == NULL);
16181648

1649+
/* Fallback on walking sys.modules */
16191650
modules_dict = _PySys_GetObjectId(&PyId_modules);
16201651
if (modules_dict == NULL) {
16211652
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
16221653
return NULL;
16231654
}
16241655

1656+
dotted_path = get_dotted_path(module, global_name, allow_qualname);
1657+
if (dotted_path == NULL)
1658+
return NULL;
1659+
16251660
i = 0;
1626-
while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) {
1627-
PyObject *result = PyUnicode_RichCompare(
1628-
module_name, _PyUnicode_FromId(&PyId___main__), Py_EQ);
1629-
int is_equal = (result == Py_True);
1630-
assert(PyBool_Check(result));
1631-
Py_DECREF(result);
1632-
if (is_equal)
1661+
while (PyDict_Next(modules_dict, &i, &module_name, &module)) {
1662+
PyObject *candidate;
1663+
if (PyUnicode_Check(module_name) &&
1664+
!PyUnicode_CompareWithASCIIString(module_name, "__main__"))
16331665
continue;
16341666
if (module == Py_None)
16351667
continue;
16361668

1637-
obj = getattribute(module, global_name, allow_qualname);
1638-
if (obj == NULL) {
1639-
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
1669+
candidate = get_deep_attribute(module, dotted_path);
1670+
if (candidate == NULL) {
1671+
if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
1672+
Py_DECREF(dotted_path);
16401673
return NULL;
1674+
}
16411675
PyErr_Clear();
16421676
continue;
16431677
}
16441678

1645-
if (obj == global) {
1646-
Py_DECREF(obj);
1679+
if (candidate == global) {
16471680
Py_INCREF(module_name);
1681+
Py_DECREF(dotted_path);
1682+
Py_DECREF(candidate);
16481683
return module_name;
16491684
}
1650-
Py_DECREF(obj);
1685+
Py_DECREF(candidate);
16511686
}
16521687

16531688
/* If no module is found, use __main__. */
16541689
module_name = _PyUnicode_FromId(&PyId___main__);
16551690
Py_INCREF(module_name);
1691+
Py_DECREF(dotted_path);
16561692
return module_name;
16571693
}
16581694

0 commit comments

Comments
 (0)