Skip to content

Commit 021dc44

Browse files
stinospfalcon
authored andcommitted
py: Allow keyword arguments for namedtuple
1 parent 1234014 commit 021dc44

2 files changed

Lines changed: 52 additions & 12 deletions

File tree

py/objnamedtuple.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,39 @@ STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_
8989
// Counts include implicit "self"
9090
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
9191
"__new__() takes %d positional arguments but %d were given",
92-
num_fields + 1, n_args + 1));
92+
num_fields + 1, n_args + n_kw + 1));
9393
}
94-
mp_obj_tuple_t *tuple = mp_obj_new_tuple(n_args, args);
94+
95+
mp_obj_t *arg_objects;
96+
if (n_args == num_fields) {
97+
arg_objects = (mp_obj_t*)args;
98+
} else {
99+
size_t alloc_size = sizeof(mp_obj_t) * num_fields;
100+
arg_objects = alloca(alloc_size);
101+
memset(arg_objects, 0, alloc_size);
102+
103+
for (mp_uint_t i = 0; i < n_args; i++) {
104+
arg_objects[i] = args[i];
105+
}
106+
107+
for (mp_uint_t i = n_args; i < n_args + 2 * n_kw; i += 2) {
108+
qstr kw = MP_OBJ_QSTR_VALUE(args[i]);
109+
int id = namedtuple_find_field(type, kw);
110+
if (id == -1) {
111+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
112+
"__new__() got an unexpected keyword argument '%s'",
113+
qstr_str(kw)));
114+
}
115+
if (arg_objects[id] != NULL) {
116+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
117+
"__new__() got multiple values for argument '%s'",
118+
qstr_str(kw)));
119+
}
120+
arg_objects[id] = args[i + 1];
121+
}
122+
}
123+
124+
mp_obj_tuple_t *tuple = mp_obj_new_tuple(num_fields, arg_objects);
95125
tuple->base.type = type_in;
96126
return tuple;
97127
}

tests/basics/namedtuple1.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@
66
T = namedtuple("Tup", ["foo", "bar"])
77
# CPython prints fully qualified name, what we don't bother to do so far
88
#print(T)
9-
t = T(1, 2)
10-
print(t)
11-
print(t[0], t[1])
12-
print(t.foo, t.bar)
9+
for t in T(1, 2), T(bar=1, foo=2):
10+
print(t)
11+
print(t[0], t[1])
12+
print(t.foo, t.bar)
1313

14-
print(len(t))
15-
print(bool(t))
16-
print(t + t)
17-
print(t * 3)
14+
print(len(t))
15+
print(bool(t))
16+
print(t + t)
17+
print(t * 3)
1818

19-
print([f for f in t])
19+
print([f for f in t])
2020

21-
print(isinstance(t, tuple))
21+
print(isinstance(t, tuple))
2222

2323
try:
2424
t[0] = 200
@@ -39,6 +39,16 @@
3939
except TypeError:
4040
print("TypeError")
4141

42+
try:
43+
t = T(foo=1)
44+
except TypeError:
45+
print("TypeError")
46+
47+
try:
48+
t = T(1, foo=1)
49+
except TypeError:
50+
print("TypeError")
51+
4252
# Try single string
4353
# Not implemented so far
4454
#T3 = namedtuple("TupComma", "foo bar")

0 commit comments

Comments
 (0)