From 3b3aae013b158114fdc90a72355d2d9b1b434875 Mon Sep 17 00:00:00 2001 From: Neal Norwitz Date: Tue, 5 Sep 2006 03:56:01 +0000 Subject: [PATCH] Bug #1520864 (again): unpacking singleton tuples in list comprehensions and generator expressions (x for x, in ... ) works again. Sigh, I only fixed for loops the first time, not list comps and genexprs too. I couldn't find any more unpacking cases where there is a similar bug lurking. --- Lib/test/test_grammar.py | 4 ++++ Misc/NEWS | 5 +++++ Python/ast.c | 16 ++++++++++++---- Python/import.c | 3 ++- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index f1608673437..c39e41699e9 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -825,6 +825,10 @@ verify([(i,j) for i in range(10) for j in range(5)] == list(g)) verify([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) verify((x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) +# Verify unpacking single element tuples in listcomp/genexp. +vereq([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) +vereq(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) + # Test ifelse expressions in various cases def _checkeval(msg, ret): "helper to check that evaluation of expressions is done correctly" diff --git a/Misc/NEWS b/Misc/NEWS index 394d9211ee8..6bb2f97bea7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -30,6 +30,11 @@ Core and builtins - The return tuple from str.rpartition(sep) is (tail, sep, head) where head is the original string if sep was not found. +- Bug #1520864: unpacking singleton tuples in list comprehensions and + generator expressions (x for x, in ... ) works again. Fixing this problem + required changing the .pyc magic number. This means that .pyc files + generated before 2.5c2 will be regenerated. + Library ------- diff --git a/Python/ast.c b/Python/ast.c index b356192d892..4d0b991c2cf 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -983,17 +983,21 @@ ast_for_listcomp(struct compiling *c, const node *n) comprehension_ty lc; asdl_seq *t; expr_ty expression; + node *for_ch; REQ(ch, list_for); - t = ast_for_exprlist(c, CHILD(ch, 1), Store); + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); if (!t) return NULL; expression = ast_for_testlist(c, CHILD(ch, 3)); if (!expression) return NULL; - if (asdl_seq_LEN(t) == 1) + /* Check the # of children rather than the length of t, since + [x for x, in ... ] has 1 element in t, but still requires a Tuple. */ + if (NCH(for_ch) == 1) lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, c->c_arena); else @@ -1129,17 +1133,21 @@ ast_for_genexp(struct compiling *c, const node *n) comprehension_ty ge; asdl_seq *t; expr_ty expression; + node *for_ch; REQ(ch, gen_for); - t = ast_for_exprlist(c, CHILD(ch, 1), Store); + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); if (!t) return NULL; expression = ast_for_expr(c, CHILD(ch, 3)); if (!expression) return NULL; - if (asdl_seq_LEN(t) == 1) + /* Check the # of children rather than the length of t, since + (x for x, in ...) has 1 element in t, but still requires a Tuple. */ + if (NCH(for_ch) == 1) ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, c->c_arena); else diff --git a/Python/import.c b/Python/import.c index da9de8b64fd..a0c5055142b 100644 --- a/Python/import.c +++ b/Python/import.c @@ -64,9 +64,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *); Python 2.5b3: 62111 (fix wrong code: x += yield) Python 2.5c1: 62121 (fix wrong lnotab with for loops and storing constants that should have been removed) + Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp) . */ -#define MAGIC (62121 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (62131 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the