summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMacBox7 <ajankit2304@gmail.com>2018-06-30 13:14:23 +0530
committerMacBox7 <ajankit2304@gmail.com>2018-08-01 23:33:17 +0530
commitfb1f223ac2141772f140be6f1108d02009c1d658 (patch)
tree0bdd1cdc10a1864d388b418a09a5a0119b35d524
parent9dd73ec54411a563410872b47e76f0f89f34ecfe (diff)
downloadpyflakes-fb1f223ac2141772f140be6f1108d02009c1d658.tar.gz
checker.py: Handle UnboundLocal error for builtins
This patch ensures that UnboundLocalError is not ignored for Python builtins. Populates ModuleScope with Builtin nodes to manage them as bindings. Fixes https://github.com/PyCQA/pyflakes/issues/350
-rw-r--r--pyflakes/checker.py27
-rw-r--r--pyflakes/messages.py13
-rw-r--r--pyflakes/test/test_builtin.py41
3 files changed, 68 insertions, 13 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 1c30dda..2ce6250 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -180,6 +180,18 @@ class Definition(Binding):
"""
+class Builtin(Definition):
+ """A definition created for all Python builtins."""
+
+ def __init__(self, name):
+ super(Builtin, self).__init__(name, None)
+
+ def __repr__(self):
+ return '<%s object %r at 0x%x>' % (self.__class__.__name__,
+ self.name,
+ id(self))
+
+
class UnhandledKeyType(object):
"""
A dictionary key of a type that we cannot or do not check for duplicates.
@@ -516,6 +528,8 @@ class Checker(object):
raise RuntimeError('No scope implemented for the node %r' % tree)
self.exceptHandlers = [()]
self.root = tree
+ for builtin in self.builtIns:
+ self.addBinding(None, Builtin(builtin))
self.handleChildren(tree)
self.runDeferred(self._deferredFunctions)
# Set _deferredFunctions to None so that deferFunction will fail
@@ -699,7 +713,8 @@ class Checker(object):
break
existing = scope.get(value.name)
- if existing and not self.differentForks(node, existing.source):
+ if (existing and not isinstance(existing, Builtin) and
+ not self.differentForks(node, existing.source)):
parent_stmt = self.getParent(value.source)
if isinstance(existing, Importation) and isinstance(parent_stmt, ast.For):
@@ -765,10 +780,6 @@ class Checker(object):
if in_generators is not False:
in_generators = isinstance(scope, GeneratorScope)
- # look in the built-ins
- if name in self.builtIns:
- return
-
if importStarred:
from_list = []
@@ -943,9 +954,7 @@ class Checker(object):
self.scopeStack = [self.scopeStack[0]]
node_offset = self.offset or (0, 0)
self.pushScope(DoctestScope)
- underscore_in_builtins = '_' in self.builtIns
- if not underscore_in_builtins:
- self.builtIns.add('_')
+ self.addBinding(None, Builtin('_'))
for example in examples:
try:
tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST)
@@ -961,8 +970,6 @@ class Checker(object):
node_offset[1] + example.indent + 4)
self.handleChildren(tree)
self.offset = node_offset
- if not underscore_in_builtins:
- self.builtIns.remove('_')
self.popScope()
self.scopeStack = saved_stack
diff --git a/pyflakes/messages.py b/pyflakes/messages.py
index eb87a72..bd70693 100644
--- a/pyflakes/messages.py
+++ b/pyflakes/messages.py
@@ -100,12 +100,19 @@ class UndefinedExport(Message):
class UndefinedLocal(Message):
- message = ('local variable %r (defined in enclosing scope on line %r) '
- 'referenced before assignment')
+ message = 'local variable %r {0} referenced before assignment'
+
+ default = 'defined in enclosing scope on line %r'
+ builtin = 'defined as a builtin'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
- self.message_args = (name, orig_loc.lineno)
+ if orig_loc is None:
+ self.message = self.message.format(self.builtin)
+ self.message_args = name
+ else:
+ self.message = self.message.format(self.default)
+ self.message_args = (name, orig_loc.lineno)
class DuplicateArgument(Message):
diff --git a/pyflakes/test/test_builtin.py b/pyflakes/test/test_builtin.py
new file mode 100644
index 0000000..7150ddb
--- /dev/null
+++ b/pyflakes/test/test_builtin.py
@@ -0,0 +1,41 @@
+"""
+Tests for detecting redefinition of builtins.
+"""
+from sys import version_info
+
+from pyflakes import messages as m
+from pyflakes.test.harness import TestCase, skipIf
+
+
+class TestBuiltins(TestCase):
+
+ def test_builtin_unbound_local(self):
+ self.flakes('''
+ def foo():
+ a = range(1, 10)
+ range = a
+ return range
+
+ foo()
+
+ print(range)
+ ''', m.UndefinedLocal)
+
+ def test_global_shadowing_builtin(self):
+ self.flakes('''
+ def f():
+ global range
+ range = None
+ print(range)
+
+ f()
+ ''')
+
+ @skipIf(version_info >= (3,), 'not an UnboundLocalError in Python 3')
+ def test_builtin_in_comprehension(self):
+ self.flakes('''
+ def f():
+ [range for range in range(1, 10)]
+
+ f()
+ ''', m.UndefinedLocal)