@@ -1535,29 +1535,27 @@ memo_put(PicklerObject *self, PyObject *obj)
1535
1535
}
1536
1536
1537
1537
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 ) {
1541
1539
_Py_static_string (PyId_dot , "." );
1542
1540
_Py_static_string (PyId_locals , "<locals>" );
1541
+ PyObject * dotted_path ;
1542
+ Py_ssize_t i , n ;
1543
1543
1544
1544
dotted_path = PyUnicode_Split (name , _PyUnicode_FromId (& PyId_dot ), -1 );
1545
- if (dotted_path == NULL ) {
1545
+ if (dotted_path == NULL )
1546
1546
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 ) {
1550
1550
PyErr_Format (PyExc_AttributeError ,
1551
1551
"Can't get qualified attribute %R on %R;"
1552
1552
"use protocols >= 4 to enable support" ,
1553
1553
name , obj );
1554
1554
Py_DECREF (dotted_path );
1555
1555
return NULL ;
1556
1556
}
1557
- Py_INCREF (obj );
1558
- for (i = 0 ; i < Py_SIZE (dotted_path ); i ++ ) {
1557
+ for (i = 0 ; i < n ; i ++ ) {
1559
1558
PyObject * subpath = PyList_GET_ITEM (dotted_path , i );
1560
- PyObject * tmp ;
1561
1559
PyObject * result = PyUnicode_RichCompare (
1562
1560
subpath , _PyUnicode_FromId (& PyId_locals ), Py_EQ );
1563
1561
int is_equal = (result == Py_True );
@@ -1567,37 +1565,69 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname) {
1567
1565
PyErr_Format (PyExc_AttributeError ,
1568
1566
"Can't get local attribute %R on %R" , name , obj );
1569
1567
Py_DECREF (dotted_path );
1570
- Py_DECREF (obj );
1571
1568
return NULL ;
1572
1569
}
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 );
1574
1586
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 )
1582
1588
return NULL ;
1583
- }
1584
1589
obj = tmp ;
1585
1590
}
1586
- Py_DECREF (dotted_path );
1587
1591
return obj ;
1588
1592
}
1589
1593
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
+
1590
1620
static PyObject *
1591
1621
whichmodule (PyObject * global , PyObject * global_name , int allow_qualname )
1592
1622
{
1593
1623
PyObject * module_name ;
1594
1624
PyObject * modules_dict ;
1595
1625
PyObject * module ;
1596
- PyObject * obj ;
1597
- Py_ssize_t i , j ;
1626
+ Py_ssize_t i ;
1598
1627
_Py_IDENTIFIER (__module__ );
1599
1628
_Py_IDENTIFIER (modules );
1600
1629
_Py_IDENTIFIER (__main__ );
1630
+ PyObject * dotted_path ;
1601
1631
1602
1632
module_name = _PyObject_GetAttrId (global , & PyId___module__ );
1603
1633
@@ -1616,43 +1646,49 @@ whichmodule(PyObject *global, PyObject *global_name, int allow_qualname)
1616
1646
}
1617
1647
assert (module_name == NULL );
1618
1648
1649
+ /* Fallback on walking sys.modules */
1619
1650
modules_dict = _PySys_GetObjectId (& PyId_modules );
1620
1651
if (modules_dict == NULL ) {
1621
1652
PyErr_SetString (PyExc_RuntimeError , "unable to get sys.modules" );
1622
1653
return NULL ;
1623
1654
}
1624
1655
1656
+ dotted_path = get_dotted_path (module , global_name , allow_qualname );
1657
+ if (dotted_path == NULL )
1658
+ return NULL ;
1659
+
1625
1660
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__" ))
1633
1665
continue ;
1634
1666
if (module == Py_None )
1635
1667
continue ;
1636
1668
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 );
1640
1673
return NULL ;
1674
+ }
1641
1675
PyErr_Clear ();
1642
1676
continue ;
1643
1677
}
1644
1678
1645
- if (obj == global ) {
1646
- Py_DECREF (obj );
1679
+ if (candidate == global ) {
1647
1680
Py_INCREF (module_name );
1681
+ Py_DECREF (dotted_path );
1682
+ Py_DECREF (candidate );
1648
1683
return module_name ;
1649
1684
}
1650
- Py_DECREF (obj );
1685
+ Py_DECREF (candidate );
1651
1686
}
1652
1687
1653
1688
/* If no module is found, use __main__. */
1654
1689
module_name = _PyUnicode_FromId (& PyId___main__ );
1655
1690
Py_INCREF (module_name );
1691
+ Py_DECREF (dotted_path );
1656
1692
return module_name ;
1657
1693
}
1658
1694
0 commit comments