Skip to content

Commit 470c429

Browse files
committed
py/runtime: Properly handle passing user mappings to ** keyword args.
1 parent 12dd8df commit 470c429

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

py/runtime.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -714,13 +714,18 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const
714714
}
715715
}
716716
} else {
717-
// generic mapping
718-
// TODO is calling 'items' on the mapping the correct thing to do here?
719-
mp_obj_t dest[2];
720-
mp_load_method(kw_dict, MP_QSTR_items, dest);
717+
// generic mapping:
718+
// - call keys() to get an iterable of all keys in the mapping
719+
// - call __getitem__ for each key to get the corresponding value
720+
721+
// get the keys iterable
722+
mp_obj_t dest[3];
723+
mp_load_method(kw_dict, MP_QSTR_keys, dest);
721724
mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest));
722-
mp_obj_t item;
723-
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
725+
726+
mp_obj_t key;
727+
while ((key = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
728+
// expand size of args array if needed
724729
if (args2_len + 1 >= args2_alloc) {
725730
uint new_alloc = args2_alloc * 2;
726731
if (new_alloc < 4) {
@@ -729,15 +734,20 @@ void mp_call_prepare_args_n_kw_var(bool have_self, mp_uint_t n_args_n_kw, const
729734
args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc);
730735
args2_alloc = new_alloc;
731736
}
732-
mp_obj_t *items;
733-
mp_obj_get_array_fixed_n(item, 2, &items);
737+
734738
// the key must be a qstr, so intern it if it's a string
735-
mp_obj_t key = items[0];
736739
if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
737740
key = mp_obj_str_intern(key);
738741
}
742+
743+
// get the value corresponding to the key
744+
mp_load_method(kw_dict, MP_QSTR___getitem__, dest);
745+
dest[2] = key;
746+
mp_obj_t value = mp_call_method_n_kw(1, 0, dest);
747+
748+
// store the key/value pair in the argument array
739749
args2[args2_len++] = key;
740-
args2[args2_len++] = items[1];
750+
args2[args2_len++] = value;
741751
}
742752
}
743753

tests/basics/fun_calldblstar3.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# test passing a user-defined mapping as the argument to **
2+
3+
def foo(**kw):
4+
print(sorted(kw.items()))
5+
6+
class Mapping:
7+
def keys(self):
8+
return ['a', 'b', 'c']
9+
10+
def __getitem__(self, key):
11+
if key == 'a':
12+
return 1
13+
else:
14+
return 2
15+
16+
foo(**Mapping())

0 commit comments

Comments
 (0)