@@ -1541,19 +1541,11 @@ impl ExecutingFrame<'_> {
1541
1541
let map_obj = vm. ctx . new_dict ( ) ;
1542
1542
for obj in self . pop_multiple ( size) {
1543
1543
// Use keys() method for all mapping objects to preserve order
1544
- let Some ( keys_method) = vm. get_method ( obj. clone ( ) , vm. ctx . intern_str ( "keys" ) ) else {
1545
- return Err (
1546
- vm. new_type_error ( format ! ( "'{}' object is not a mapping" , obj. class( ) . name( ) ) )
1547
- ) ;
1548
- } ;
1549
-
1550
- let keys = keys_method?. call ( ( ) , vm) ?. get_iter ( vm) ?;
1551
- while let PyIterReturn :: Return ( key) = keys. next ( vm) ? {
1544
+ Self :: iterate_mapping_keys ( vm, & obj, "keyword argument" , |key| {
1552
1545
// Check for keyword argument restrictions
1553
1546
if key. downcast_ref :: < PyStr > ( ) . is_none ( ) {
1554
1547
return Err ( vm. new_type_error ( "keywords must be strings" . to_owned ( ) ) ) ;
1555
1548
}
1556
-
1557
1549
if map_obj. contains_key ( & * key, vm) {
1558
1550
let key_repr = & key. repr ( vm) ?;
1559
1551
let msg = format ! (
@@ -1565,7 +1557,8 @@ impl ExecutingFrame<'_> {
1565
1557
1566
1558
let value = obj. get_item ( & * key, vm) ?;
1567
1559
map_obj. set_item ( & * key, value, vm) ?;
1568
- }
1560
+ Ok ( ( ) )
1561
+ } ) ?;
1569
1562
}
1570
1563
1571
1564
self . push_value ( map_obj. into ( ) ) ;
@@ -1614,19 +1607,14 @@ impl ExecutingFrame<'_> {
1614
1607
let mut kwargs = IndexMap :: new ( ) ;
1615
1608
1616
1609
// Use keys() method for all mapping objects to preserve order
1617
- let Some ( keys_method) = vm. get_method ( kw_obj. clone ( ) , vm. ctx . intern_str ( "keys" ) ) else {
1618
- return Err ( vm. new_type_error ( "argument after ** must be a mapping" . to_owned ( ) ) ) ;
1619
- } ;
1620
-
1621
- // Handle custom mapping objects like OrderedDict using keys() method
1622
- let keys = keys_method?. call ( ( ) , vm) ?. get_iter ( vm) ?;
1623
- while let PyIterReturn :: Return ( key) = keys. next ( vm) ? {
1610
+ Self :: iterate_mapping_keys ( vm, & kw_obj, "argument after **" , |key| {
1624
1611
let key_str = key
1625
1612
. payload_if_subclass :: < PyStr > ( vm)
1626
1613
. ok_or_else ( || vm. new_type_error ( "keywords must be strings" . to_owned ( ) ) ) ?;
1627
1614
let value = kw_obj. get_item ( & * key, vm) ?;
1628
1615
kwargs. insert ( key_str. as_str ( ) . to_owned ( ) , value) ;
1629
- }
1616
+ Ok ( ( ) )
1617
+ } ) ?;
1630
1618
kwargs
1631
1619
} else {
1632
1620
IndexMap :: new ( )
@@ -1638,6 +1626,28 @@ impl ExecutingFrame<'_> {
1638
1626
Ok ( FuncArgs { args, kwargs } )
1639
1627
}
1640
1628
1629
+ /// Helper function to iterate over mapping keys using the keys() method.
1630
+ /// This ensures proper order preservation for OrderedDict and other custom mappings.
1631
+ fn iterate_mapping_keys < F > (
1632
+ vm : & VirtualMachine ,
1633
+ mapping : & PyObjectRef ,
1634
+ error_prefix : & str ,
1635
+ mut key_handler : F ,
1636
+ ) -> PyResult < ( ) >
1637
+ where
1638
+ F : FnMut ( PyObjectRef ) -> PyResult < ( ) > ,
1639
+ {
1640
+ let Some ( keys_method) = vm. get_method ( mapping. clone ( ) , vm. ctx . intern_str ( "keys" ) ) else {
1641
+ return Err ( vm. new_type_error ( format ! ( "{} must be a mapping" , error_prefix) ) ) ;
1642
+ } ;
1643
+
1644
+ let keys = keys_method?. call ( ( ) , vm) ?. get_iter ( vm) ?;
1645
+ while let PyIterReturn :: Return ( key) = keys. next ( vm) ? {
1646
+ key_handler ( key) ?;
1647
+ }
1648
+ Ok ( ( ) )
1649
+ }
1650
+
1641
1651
#[ inline]
1642
1652
fn execute_call ( & mut self , args : FuncArgs , vm : & VirtualMachine ) -> FrameResult {
1643
1653
let func_ref = self . pop_value ( ) ;
0 commit comments