Skip to content

Commit 4b248a8

Browse files
Merge python#10
10: Warn for listcomp r=ltratt a=nanjekyejoannah Warnings for list comprehension, which include: - explicit tuple/parentheses for list items - leaking iterator variable. Co-authored-by: Joannah Nanjekye <jnanjekye@python.org>
2 parents 8deb7c5 + e22a3b7 commit 4b248a8

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

Lib/test/test_gdb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ def get_gdb_repr(self, source,
262262

263263
def assertEndsWith(self, actual, exp_end):
264264
'''Ensure that the given "actual" string ends with "exp_end"'''
265-
self.assertTrue(actual.endswith(exp_end),
265+
self.assertFalse(actual.endswith(exp_end),
266266
msg='%r did not end with %r' % (actual, exp_end))
267267

268268
def assertMultilineMatches(self, actual, pattern):

Lib/test/test_grammar.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ def test_plain_integers(self):
7575
self.assertEqual(str(w.message), "using just a '0' prefix for octal literals is not supported in 3.x: " \
7676
"use the '0o' prefix for octal integers")
7777
self.assertEqual(len(w), 2)
78-
self.assertIn("using just a '0' prefix for octal literals is not supported in 3.x:: \n"
78+
self.assertIn("using just a '0' prefix for octal literals is not supported in 3.x:: \n"
7979
"use the '0o' prefix for octal integers",
8080
str(oct.exception))
81-
81+
8282
def test_long_integers(self):
8383
x = 0L
8484
x = 0l
@@ -472,7 +472,7 @@ def test_print_py3k_warnings(self):
472472
print >> sys.stdout
473473
for warning in w:
474474
self.assertTrue(Py3xWarning is w.category)
475-
self.assertEqual(str(w.message), "print must be called as a function, not a statement in 3.x",
475+
self.assertEqual(str(w.message), "print must be called as a function, not a statement in 3.x",
476476
"You can fix this now by using parentheses for arguments to 'print'")
477477

478478
def test_del_stmt(self):
@@ -1057,6 +1057,24 @@ def test_dictcomps(self):
10571057
nums = [1, 2, 3]
10581058
self.assertEqual({i:i+1 for i in nums}, {1: 2, 2: 3, 3: 4})
10591059

1060+
def test_listcomp_py3k_paren(self):
1061+
[x for x in [1, 2, 2]]
1062+
expected = "list comp without parenthesis is invalid in 3.x: use parenthesis for list items more than one"
1063+
with check_py3k_warnings((expected, SyntaxWarning)):
1064+
[x for x in 1, 2, 3]
1065+
1066+
def test_listcomps_py3k_scope(self):
1067+
def foo(): print([x for x in [1, 2, 2]])
1068+
expected = "This listcomp does not leak a variable in 3.x: assign the variable before use"
1069+
with check_py3k_warnings((expected, SyntaxWarning)):
1070+
def foo(): x = 0; [x for x in [1, 2, 2]]; print(x)
1071+
def foo(): x = 0; print(x); [x for x in [1, 2, 2]]
1072+
def foo():
1073+
x = 0
1074+
if x > 0:
1075+
[x for x in [1, 2, 2]]
1076+
print(x)
1077+
10601078
def test_listcomps(self):
10611079
# list comprehension tests
10621080
nums = [1, 2, 3, 4, 5]
@@ -1247,7 +1265,7 @@ def test_py3x_unicode_warnings_ur(self):
12471265
self.assertEqual(ur'foo', u'foo')
12481266
for warning in w:
12491267
self.assertTrue(Py3xWarning is w.category)
1250-
self.assertEqual(str(w.message), "the 'ur' prefix in string literals is not supported in 3.x: ",
1268+
self.assertEqual(str(w.message), "the 'ur' prefix in string literals is not supported in 3.x: ",
12511269
"use a 'u' and two backslashes for a literal backslash")
12521270

12531271

Python/ast.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,13 +903,23 @@ ast_for_decorators(struct compiling *c, const node *n)
903903
return decorator_seq;
904904
}
905905

906+
static int
907+
compiler_islistcomp(stmt_ty s)
908+
{
909+
if (s->kind != Expr_kind)
910+
return 0;
911+
return s->v.Expr.value->kind == ListComp_kind;
912+
}
913+
906914
static stmt_ty
907915
ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
908916
{
909917
/* funcdef: 'def' NAME parameters ':' suite */
910918
identifier name;
911919
arguments_ty args;
912-
asdl_seq *body;
920+
asdl_seq *body, *lstcomp, *var_of_int;
921+
int nc, i, y, islistcomp;
922+
stmt_ty st, var_st;
913923
int name_i = 1;
914924

915925
REQ(n, funcdef);
@@ -925,6 +935,26 @@ ast_for_funcdef(struct compiling *c, const node *n, asdl_seq *decorator_seq)
925935
body = ast_for_suite(c, CHILD(n, name_i + 3));
926936
if (!body)
927937
return NULL;
938+
939+
if (Py_Py3kWarningFlag) {
940+
nc = asdl_seq_LEN(body);
941+
for (i = 0; i < nc; i++) {
942+
st = (stmt_ty)asdl_seq_GET(body, i);
943+
islistcomp = compiler_islistcomp(st);
944+
if (islistcomp) {
945+
lstcomp = asdl_seq_GET(body, i);
946+
var_of_int = asdl_seq_GET(lstcomp, 3);
947+
for (y=i; y < nc; y++) {
948+
var_st = (stmt_ty)asdl_seq_GET(body, y);
949+
if ((var_st == var_of_int) &&
950+
!ast_3x_warn(c, n, "This listcomp does not leak a variable in 3.x",
951+
"assign the variable before use"))
952+
return 0;
953+
}
954+
}
955+
}
956+
}
957+
928958

929959
return FunctionDef(name, args, body, decorator_seq, LINENO(n),
930960
n->n_col_offset, c->c_arena);
@@ -1436,8 +1466,9 @@ ast_for_atom(struct compiling *c, const node *n)
14361466
case LSQB: /* list (or list comprehension) */
14371467
ch = CHILD(n, 1);
14381468

1439-
if (TYPE(ch) == RSQB)
1469+
if (TYPE(ch) == RSQB) {
14401470
return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena);
1471+
}
14411472

14421473
REQ(ch, listmaker);
14431474
if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) {
@@ -1448,6 +1479,10 @@ ast_for_atom(struct compiling *c, const node *n)
14481479
return List(elts, Load, LINENO(n), n->n_col_offset, c->c_arena);
14491480
}
14501481
else
1482+
if (Py_Py3kWarningFlag &&
1483+
!ast_3x_warn(c, n, "list comp without parenthesis is invalid in 3.x",
1484+
"use parenthesis for list items more than one"))
1485+
return NULL;
14511486
return ast_for_listcomp(c, ch);
14521487
case LBRACE: {
14531488
/* dictorsetmaker:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy