Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: flake8-eyeo/flake8_eyeo.py

Issue 29565854: Noissue - Improved accuracy of evaluated expressions for A103 and A207 (Closed)
Left Patch Set: Rebased Created Oct. 11, 2017, 6:23 p.m.
Right Patch Set: Changed behavior of A207 Created Oct. 11, 2017, 6:25 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | flake8-eyeo/tests/A103.py » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This file is part of Adblock Plus <https://adblockplus.org/>, 1 # This file is part of Adblock Plus <https://adblockplus.org/>,
2 # Copyright (C) 2006-present eyeo GmbH 2 # Copyright (C) 2006-present eyeo GmbH
3 # 3 #
4 # Adblock Plus is free software: you can redistribute it and/or modify 4 # Adblock Plus is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License version 3 as 5 # it under the terms of the GNU General Public License version 3 as
6 # published by the Free Software Foundation. 6 # published by the Free Software Foundation.
7 # 7 #
8 # Adblock Plus is distributed in the hope that it will be useful, 8 # Adblock Plus is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
(...skipping 27 matching lines...) Expand all
38 'codecs.open': 'io.open', 38 'codecs.open': 'io.open',
39 } 39 }
40 40
41 ESSENTIAL_BUILTINS = set(dir(builtins)) - {'apply', 'buffer', 'coerce', 41 ESSENTIAL_BUILTINS = set(dir(builtins)) - {'apply', 'buffer', 'coerce',
42 'intern', 'file'} 42 'intern', 'file'}
43 43
44 LEAVE_BLOCK = (ast.Return, ast.Raise, ast.Continue, ast.Break) 44 LEAVE_BLOCK = (ast.Return, ast.Raise, ast.Continue, ast.Break)
45 VOLATILE = object() 45 VOLATILE = object()
46 46
47 47
48 def evaluate(node): 48 def evaluate(node, namespace):
49 names = {'__builtins__': {'True': True, 'False': False, 'None': None}}
50 try: 49 try:
51 return eval(compile(ast.Expression(node), '', 'eval'), names) 50 return eval(compile(ast.Expression(node), '', 'eval'), namespace)
52 except Exception: 51 except Exception:
53 return VOLATILE 52 return VOLATILE
54 53
55 54
56 def is_const(node): 55 def is_const(node):
57 return evaluate(node) is not VOLATILE 56 namespace = {'__builtins__': {'True': True, 'False': False, 'None': None}}
57 return evaluate(node, namespace) is not VOLATILE
58 58
59 59
60 def get_identifier(node): 60 def get_identifier(node):
61 if isinstance(node, ast.Name): 61 if isinstance(node, ast.Name):
62 return node.id 62 return node.id
63 if isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name): 63 if isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name):
64 return '{}.{}'.format(node.value.id, node.attr) 64 return '{}.{}'.format(node.value.id, node.attr)
65 65
66 66
67 def get_statement(node): 67 def get_statement(node):
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 left_is_target = (isinstance(target, ast.Name) and 329 left_is_target = (isinstance(target, ast.Name) and
330 isinstance(node.value.left, ast.Name) and 330 isinstance(node.value.left, ast.Name) and
331 target.id == node.value.left.id) 331 target.id == node.value.left.id)
332 if left_is_target: 332 if left_is_target:
333 self.errors.append((node, 'A106 use augment assignment, ' 333 self.errors.append((node, 'A106 use augment assignment, '
334 'e.g. x += y instead x = x + y')) 334 'e.g. x += y instead x = x + y'))
335 self.generic_visit(node) 335 self.generic_visit(node)
336 336
337 def _visit_hash_keys(self, nodes, what): 337 def _visit_hash_keys(self, nodes, what):
338 keys = [] 338 keys = []
339 namespace = collections.defaultdict(object, vars(builtins))
Vasily Kuznetsov 2017/10/11 19:29:02 This is clever!
339 for node in nodes: 340 for node in nodes:
340 key = evaluate(node) 341 key = evaluate(node, namespace)
341 if key is VOLATILE: 342 if key is VOLATILE:
342 continue 343 continue
343 344
344 if key in keys: 345 if key in keys:
345 self.errors.append((node, 'A207 duplicate ' + what)) 346 self.errors.append((node, 'A207 duplicate ' + what))
346 continue 347 continue
347 348
348 keys.append(key) 349 keys.append(key)
349 350
350 def visit_Dict(self, node): 351 def visit_Dict(self, node):
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 return [(pos, 'A111 redundant parenthesis for {} ' 466 return [(pos, 'A111 redundant parenthesis for {} '
466 'statement'.format(statement))] 467 'statement'.format(statement))]
467 468
468 return [] 469 return []
469 470
470 471
471 for checker in [check_ast, check_non_default_encoding, 472 for checker in [check_ast, check_non_default_encoding,
472 check_quotes, check_redundant_parenthesis]: 473 check_quotes, check_redundant_parenthesis]:
473 checker.name = 'eyeo' 474 checker.name = 'eyeo'
474 checker.version = __version__ 475 checker.version = __version__
LEFTRIGHT

Powered by Google App Engine
This is Rietveld