diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 0fe2f774af..313eeac5e4 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -89,9 +89,39 @@ STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_ // Counts include implicit "self" nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__new__() takes %d positional arguments but %d were given", - num_fields + 1, n_args + 1)); + num_fields + 1, n_args + n_kw + 1)); } - mp_obj_tuple_t *tuple = mp_obj_new_tuple(n_args, args); + + mp_obj_t *arg_objects; + if (n_args == num_fields) { + arg_objects = (mp_obj_t*)args; + } else { + size_t alloc_size = sizeof(mp_obj_t) * num_fields; + arg_objects = alloca(alloc_size); + memset(arg_objects, 0, alloc_size); + + for (mp_uint_t i = 0; i < n_args; i++) { + arg_objects[i] = args[i]; + } + + for (mp_uint_t i = n_args; i < n_args + 2 * n_kw; i += 2) { + qstr kw = MP_OBJ_QSTR_VALUE(args[i]); + int id = namedtuple_find_field(type, kw); + if (id == -1) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "__new__() got an unexpected keyword argument '%s'", + qstr_str(kw))); + } + if (arg_objects[id] != NULL) { + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, + "__new__() got multiple values for argument '%s'", + qstr_str(kw))); + } + arg_objects[id] = args[i + 1]; + } + } + + mp_obj_tuple_t *tuple = mp_obj_new_tuple(num_fields, arg_objects); tuple->base.type = type_in; return tuple; } diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py index a94b7e7ab0..9afeed9408 100644 --- a/tests/basics/namedtuple1.py +++ b/tests/basics/namedtuple1.py @@ -6,19 +6,19 @@ except ImportError: T = namedtuple("Tup", ["foo", "bar"]) # CPython prints fully qualified name, what we don't bother to do so far #print(T) -t = T(1, 2) -print(t) -print(t[0], t[1]) -print(t.foo, t.bar) +for t in T(1, 2), T(bar=1, foo=2): + print(t) + print(t[0], t[1]) + print(t.foo, t.bar) -print(len(t)) -print(bool(t)) -print(t + t) -print(t * 3) + print(len(t)) + print(bool(t)) + print(t + t) + print(t * 3) -print([f for f in t]) + print([f for f in t]) -print(isinstance(t, tuple)) + print(isinstance(t, tuple)) try: t[0] = 200 @@ -39,6 +39,16 @@ try: except TypeError: print("TypeError") +try: + t = T(foo=1) +except TypeError: + print("TypeError") + +try: + t = T(1, foo=1) +except TypeError: + print("TypeError") + # Try single string # Not implemented so far #T3 = namedtuple("TupComma", "foo bar")