Merge lp:~florent.x/pyflakes/989203-python3 into lp:pyflakes

Proposed by Florent
Status: Merged
Merged at revision: 53
Proposed branch: lp:~florent.x/pyflakes/989203-python3
Merge into: lp:pyflakes
Diff against target: 814 lines (+215/-149)
9 files modified
.travis.yml (+5/-1)
pyflakes/checker.py (+128/-96)
pyflakes/reporter.py (+11/-7)
pyflakes/scripts/pyflakes.py (+7/-5)
pyflakes/test/harness.py (+2/-2)
pyflakes/test/test_imports.py (+23/-17)
pyflakes/test/test_script.py (+28/-15)
pyflakes/test/test_undefined_names.py (+9/-6)
setup.py (+2/-0)
To merge this branch: bzr merge lp:~florent.x/pyflakes/989203-python3
Reviewer Review Type Date Requested Status
Pyflakes Dev Pending
Review via email: mp+144668@code.launchpad.net

Description of the change

This branch brings the minimal changes to achieve Python 3 support.

Tests are green: https://travis-ci.org/florentx/pyflakes/builds/4250803

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.travis.yml'
--- .travis.yml 2013-01-19 00:26:52 +0000
+++ .travis.yml 2013-01-24 10:27:21 +0000
@@ -3,10 +3,14 @@
3 - 2.53 - 2.5
4 - 2.64 - 2.6
5 - 2.75 - 2.7
6 - 3.2
7 - 3.3
6 - pypy8 - pypy
9before_install:
10 - if [ "${TRAVIS_PYTHON_VERSION::1}" == "3" ]; then export TEST_PKG=unittest2py3k; else export TEST_PKG=unittest2; fi
7install:11install:
8 - python setup.py install12 - python setup.py install
9 - pip install unittest213 - pip install $TEST_PKG
10script:14script:
11 - unit2 discover15 - unit2 discover
12matrix:16matrix:
1317
=== modified file 'pyflakes/checker.py'
--- pyflakes/checker.py 2012-01-10 19:09:22 +0000
+++ pyflakes/checker.py 2013-01-24 10:27:21 +0000
@@ -2,9 +2,14 @@
2# (c) 2005-2010 Divmod, Inc.2# (c) 2005-2010 Divmod, Inc.
3# See LICENSE file for details3# See LICENSE file for details
44
5import __builtin__
6import os.path5import os.path
7import _ast6import _ast
7try:
8 import builtins
9 PY2 = False
10except ImportError:
11 import __builtin__ as builtins
12 PY2 = True
813
9from pyflakes import messages14from pyflakes import messages
1015
@@ -173,11 +178,18 @@
173 pass178 pass
174179
175180
176# Globally defined names which are not attributes of the __builtin__ module, or181# Globally defined names which are not attributes of the builtins module, or
177# are only present on some platforms.182# are only present on some platforms.
178_MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']183_MAGIC_GLOBALS = ['__file__', '__builtins__', 'WindowsError']
179184
180185
186def getNodeName(node):
187 # Returns node.id, or node.name, or None
188 if hasattr(node, 'id'): # One of the many nodes with an id
189 return node.id
190 if hasattr(node, 'name'): # a ExceptHandler node
191 return node.name
192
181193
182class Checker(object):194class Checker(object):
183 """195 """
@@ -275,7 +287,7 @@
275 all = []287 all = []
276288
277 # Look for imported names that aren't used.289 # Look for imported names that aren't used.
278 for importation in scope.itervalues():290 for importation in scope.values():
279 if isinstance(importation, Importation):291 if isinstance(importation, Importation):
280 if not importation.used and importation.name not in all:292 if not importation.used and importation.name not in all:
281 self.report(293 self.report(
@@ -293,6 +305,83 @@
293 def report(self, messageClass, *args, **kwargs):305 def report(self, messageClass, *args, **kwargs):
294 self.messages.append(messageClass(self.filename, *args, **kwargs))306 self.messages.append(messageClass(self.filename, *args, **kwargs))
295307
308 def handleNodeLoad(self, node):
309 name = getNodeName(node)
310 if not name:
311 return
312 # try local scope
313 importStarred = self.scope.importStarred
314 try:
315 self.scope[name].used = (self.scope, node.lineno)
316 except KeyError:
317 pass
318 else:
319 return
320
321 # try enclosing function scopes
322 for scope in self.scopeStack[-2:0:-1]:
323 importStarred = importStarred or scope.importStarred
324 if not isinstance(scope, FunctionScope):
325 continue
326 try:
327 scope[name].used = (self.scope, node.lineno)
328 except KeyError:
329 pass
330 else:
331 return
332
333 # try global scope
334 importStarred = importStarred or self.scopeStack[0].importStarred
335 try:
336 self.scopeStack[0][name].used = (self.scope, node.lineno)
337 except KeyError:
338 if ((not hasattr(builtins, name)) and name not in _MAGIC_GLOBALS and not importStarred):
339 if (os.path.basename(self.filename) == '__init__.py' and name == '__path__'):
340 # the special name __path__ is valid only in packages
341 pass
342 else:
343 self.report(messages.UndefinedName, node.lineno, name)
344
345 def handleNodeStore(self, node):
346 name = getNodeName(node)
347 if not name:
348 return
349 # if the name hasn't already been defined in the current scope
350 if isinstance(self.scope, FunctionScope) and name not in self.scope:
351 # for each function or module scope above us
352 for scope in self.scopeStack[:-1]:
353 if not isinstance(scope, (FunctionScope, ModuleScope)):
354 continue
355 # if the name was defined in that scope, and the name has
356 # been accessed already in the current scope, and hasn't
357 # been declared global
358 if (name in scope and scope[name].used and scope[name].used[0] is self.scope
359 and name not in self.scope.globals):
360 # then it's probably a mistake
361 self.report(messages.UndefinedLocal, scope[name].used[1], name,
362 scope[name].source.lineno)
363 break
364
365 parent = getattr(node, 'parent', None)
366 if isinstance(parent, (_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
367 binding = Binding(name, node)
368 elif parent is not None and name == '__all__' and isinstance(self.scope, ModuleScope):
369 binding = ExportBinding(name, parent.value)
370 else:
371 binding = Assignment(name, node)
372 if name in self.scope:
373 binding.used = self.scope[name].used
374 self.addBinding(node.lineno, binding)
375
376 def handleNodeDelete(self, node):
377 name = getNodeName(node)
378 if not name:
379 return
380 if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
381 del self.scope.globals[name]
382 else:
383 self.addBinding(node.lineno, UnBinding(name, node))
384
296 def handleChildren(self, tree):385 def handleChildren(self, tree):
297 for node in iter_child_nodes(tree):386 for node in iter_child_nodes(tree):
298 self.handleNode(node, tree)387 self.handleNode(node, tree)
@@ -309,7 +398,7 @@
309 def handleNode(self, node, parent):398 def handleNode(self, node, parent):
310 node.parent = parent399 node.parent = parent
311 if self.traceTree:400 if self.traceTree:
312 print ' ' * self.nodeDepth + node.__class__.__name__401 print(' ' * self.nodeDepth + node.__class__.__name__)
313 self.nodeDepth += 1402 self.nodeDepth += 1
314 if self.futuresAllowed and not \403 if self.futuresAllowed and not \
315 (isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):404 (isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):
@@ -321,14 +410,14 @@
321 finally:410 finally:
322 self.nodeDepth -= 1411 self.nodeDepth -= 1
323 if self.traceTree:412 if self.traceTree:
324 print ' ' * self.nodeDepth + 'end ' + node.__class__.__name__413 print(' ' * self.nodeDepth + 'end ' + node.__class__.__name__)
325414
326 def ignore(self, node):415 def ignore(self, node):
327 pass416 pass
328417
329 # "stmt" type nodes418 # "stmt" type nodes
330 RETURN = DELETE = PRINT = WHILE = IF = WITH = RAISE = TRYEXCEPT = \419 RETURN = DELETE = PRINT = WHILE = IF = WITH = WITHITEM = RAISE = \
331 TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren420 TRYEXCEPT = TRYFINALLY = TRY = ASSERT = EXEC = EXPR = handleChildren
332421
333 CONTINUE = BREAK = PASS = ignore422 CONTINUE = BREAK = PASS = ignore
334423
@@ -350,7 +439,7 @@
350 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore439 EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
351440
352 # additional node types441 # additional node types
353 COMPREHENSION = EXCEPTHANDLER = KEYWORD = handleChildren442 COMPREHENSION = KEYWORD = handleChildren
354443
355 def addBinding(self, lineno, value, reportRedef=True):444 def addBinding(self, lineno, value, reportRedef=True):
356 '''Called when a binding is altered.445 '''Called when a binding is altered.
@@ -436,81 +525,11 @@
436 """525 """
437 # Locate the name in locals / function / globals scopes.526 # Locate the name in locals / function / globals scopes.
438 if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):527 if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):
439 # try local scope528 self.handleNodeLoad(node)
440 importStarred = self.scope.importStarred
441 try:
442 self.scope[node.id].used = (self.scope, node.lineno)
443 except KeyError:
444 pass
445 else:
446 return
447
448 # try enclosing function scopes
449
450 for scope in self.scopeStack[-2:0:-1]:
451 importStarred = importStarred or scope.importStarred
452 if not isinstance(scope, FunctionScope):
453 continue
454 try:
455 scope[node.id].used = (self.scope, node.lineno)
456 except KeyError:
457 pass
458 else:
459 return
460
461 # try global scope
462
463 importStarred = importStarred or self.scopeStack[0].importStarred
464 try:
465 self.scopeStack[0][node.id].used = (self.scope, node.lineno)
466 except KeyError:
467 if ((not hasattr(__builtin__, node.id))
468 and node.id not in _MAGIC_GLOBALS
469 and not importStarred):
470 if (os.path.basename(self.filename) == '__init__.py' and
471 node.id == '__path__'):
472 # the special name __path__ is valid only in packages
473 pass
474 else:
475 self.report(messages.UndefinedName, node.lineno, node.id)
476 elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):529 elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
477 # if the name hasn't already been defined in the current scope530 self.handleNodeStore(node)
478 if isinstance(self.scope, FunctionScope) and node.id not in self.scope:
479 # for each function or module scope above us
480 for scope in self.scopeStack[:-1]:
481 if not isinstance(scope, (FunctionScope, ModuleScope)):
482 continue
483 # if the name was defined in that scope, and the name has
484 # been accessed already in the current scope, and hasn't
485 # been declared global
486 if (node.id in scope
487 and scope[node.id].used
488 and scope[node.id].used[0] is self.scope
489 and node.id not in self.scope.globals):
490 # then it's probably a mistake
491 self.report(messages.UndefinedLocal,
492 scope[node.id].used[1],
493 node.id,
494 scope[node.id].source.lineno)
495 break
496
497 if isinstance(node.parent,
498 (_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
499 binding = Binding(node.id, node)
500 elif (node.id == '__all__' and
501 isinstance(self.scope, ModuleScope)):
502 binding = ExportBinding(node.id, node.parent.value)
503 else:
504 binding = Assignment(node.id, node)
505 if node.id in self.scope:
506 binding.used = self.scope[node.id].used
507 self.addBinding(node.lineno, binding)
508 elif isinstance(node.ctx, _ast.Del):531 elif isinstance(node.ctx, _ast.Del):
509 if isinstance(self.scope, FunctionScope) and \532 self.handleNodeDelete(node)
510 node.id in self.scope.globals:
511 del self.scope.globals[node.id]
512 else:
513 self.addBinding(node.lineno, UnBinding(node.id, node))
514 else:533 else:
515 # must be a Param context -- this only happens for names in function534 # must be a Param context -- this only happens for names in function
516 # arguments, but these aren't dispatched through here535 # arguments, but these aren't dispatched through here
@@ -536,18 +555,28 @@
536 def runFunction():555 def runFunction():
537 args = []556 args = []
538557
539 def addArgs(arglist):558 if PY2:
540 for arg in arglist:559 def addArgs(arglist):
541 if isinstance(arg, _ast.Tuple):560 for arg in arglist:
542 addArgs(arg.elts)561 if isinstance(arg, _ast.Tuple):
543 else:562 addArgs(arg.elts)
544 if arg.id in args:563 else:
564 if arg.id in args:
565 self.report(messages.DuplicateArgument,
566 node.lineno, arg.id)
567 args.append(arg.id)
568 else:
569 def addArgs(arglist):
570 for arg in arglist:
571 if arg.arg in args:
545 self.report(messages.DuplicateArgument,572 self.report(messages.DuplicateArgument,
546 node.lineno, arg.id)573 node.lineno, arg.arg)
547 args.append(arg.id)574 args.append(arg.arg)
548575
549 self.pushFunctionScope()576 self.pushFunctionScope()
550 addArgs(node.args.args)577 addArgs(node.args.args)
578 if not PY2:
579 addArgs(node.args.kwonlyargs)
551 # vararg/kwarg identifiers are not Name nodes580 # vararg/kwarg identifiers are not Name nodes
552 if node.args.vararg:581 if node.args.vararg:
553 args.append(node.args.vararg)582 args.append(node.args.vararg)
@@ -566,7 +595,7 @@
566 """595 """
567 Check to see if any assignments have not been used.596 Check to see if any assignments have not been used.
568 """597 """
569 for name, binding in self.scope.iteritems():598 for name, binding in self.scope.items():
570 if (not binding.used and not name in self.scope.globals599 if (not binding.used and not name in self.scope.globals
571 and isinstance(binding, Assignment)):600 and isinstance(binding, Assignment)):
572 self.report(messages.UnusedVariable,601 self.report(messages.UnusedVariable,
@@ -600,13 +629,9 @@
600 self.handleNode(target, node)629 self.handleNode(target, node)
601630
602 def AUGASSIGN(self, node):631 def AUGASSIGN(self, node):
603 # AugAssign is awkward: must set the context explicitly and visit twice,632 self.handleNodeLoad(node.target)
604 # once with AugLoad context, once with AugStore context
605 node.target.ctx = _ast.AugLoad()
606 self.handleNode(node.target, node)
607 self.handleNode(node.value, node)633 self.handleNode(node.value, node)
608 node.target.ctx = _ast.AugStore()634 self.handleNodeStore(node.target)
609 self.handleNode(node.target, node)
610635
611 def IMPORT(self, node):636 def IMPORT(self, node):
612 for alias in node.names:637 for alias in node.names:
@@ -632,3 +657,10 @@
632 if node.module == '__future__':657 if node.module == '__future__':
633 importation.used = (self.scope, node.lineno)658 importation.used = (self.scope, node.lineno)
634 self.addBinding(node.lineno, importation)659 self.addBinding(node.lineno, importation)
660
661 def EXCEPTHANDLER(self, node):
662 # in addition to handling children, we must handle the name of the exception, which is not
663 # a Name node, but a simple string.
664 if node.name:
665 self.handleNodeStore(node)
666 self.handleChildren(node)
635667
=== modified file 'pyflakes/reporter.py'
--- pyflakes/reporter.py 2012-10-23 13:07:35 +0000
+++ pyflakes/reporter.py 2013-01-24 10:27:21 +0000
@@ -2,6 +2,10 @@
2# See LICENSE file for details2# See LICENSE file for details
33
4import sys4import sys
5try:
6 u = unicode
7except NameError:
8 u = str
59
610
7class Reporter(object):11class Reporter(object):
@@ -33,7 +37,7 @@
33 @param msg: A message explaining the problem.37 @param msg: A message explaining the problem.
34 @ptype msg: C{unicode}38 @ptype msg: C{unicode}
35 """39 """
36 self._stderr.write(u"%s: %s\n" % (filename, msg))40 self._stderr.write(u("%s: %s\n") % (filename, msg))
3741
3842
39 def syntaxError(self, filename, msg, lineno, offset, text):43 def syntaxError(self, filename, msg, lineno, offset, text):
@@ -54,11 +58,11 @@
54 line = text.splitlines()[-1]58 line = text.splitlines()[-1]
55 if offset is not None:59 if offset is not None:
56 offset = offset - (len(text) - len(line))60 offset = offset - (len(text) - len(line))
57 self._stderr.write(u'%s:%d: %s\n' % (filename, lineno, msg))61 self._stderr.write(u('%s:%d: %s\n') % (filename, lineno, msg))
58 self._stderr.write(line)62 self._stderr.write(u(line))
59 self._stderr.write(u'\n')63 self._stderr.write(u('\n'))
60 if offset is not None:64 if offset is not None:
61 self._stderr.write(u" " * (offset + 1) + u"^\n")65 self._stderr.write(u(" " * (offset + 1) + "^\n"))
6266
6367
64 def flake(self, message):68 def flake(self, message):
@@ -67,8 +71,8 @@
6771
68 @param: A L{pyflakes.messages.Message}.72 @param: A L{pyflakes.messages.Message}.
69 """73 """
70 self._stdout.write(unicode(message))74 self._stdout.write(u(message))
71 self._stdout.write(u'\n')75 self._stdout.write(u('\n'))
7276
7377
7478
7579
=== modified file 'pyflakes/scripts/pyflakes.py'
--- pyflakes/scripts/pyflakes.py 2012-10-23 11:48:54 +0000
+++ pyflakes/scripts/pyflakes.py 2013-01-24 10:27:21 +0000
@@ -34,7 +34,8 @@
34 # First, compile into an AST and handle syntax errors.34 # First, compile into an AST and handle syntax errors.
35 try:35 try:
36 tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)36 tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
37 except SyntaxError, value:37 except SyntaxError:
38 value = sys.exc_info()[1]
38 msg = value.args[0]39 msg = value.args[0]
3940
40 (lineno, offset, text) = value.lineno, value.offset, value.text41 (lineno, offset, text) = value.lineno, value.offset, value.text
@@ -44,14 +45,14 @@
44 # Avoid using msg, since for the only known case, it contains a45 # Avoid using msg, since for the only known case, it contains a
45 # bogus message that claims the encoding the file declared was46 # bogus message that claims the encoding the file declared was
46 # unknown.47 # unknown.
47 reporter.unexpectedError(filename, u'problem decoding source')48 reporter.unexpectedError(filename, 'problem decoding source')
48 else:49 else:
49 reporter.syntaxError(filename, msg, lineno, offset, text)50 reporter.syntaxError(filename, msg, lineno, offset, text)
50 return 151 return 1
51 else:52 else:
52 # Okay, it's syntactically valid. Now check it.53 # Okay, it's syntactically valid. Now check it.
53 w = checker.Checker(tree, filename)54 w = checker.Checker(tree, filename)
54 w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))55 w.messages.sort(key=lambda m: m.lineno)
55 for warning in w.messages:56 for warning in w.messages:
56 reporter.flake(warning)57 reporter.flake(warning)
57 return len(w.messages)58 return len(w.messages)
@@ -69,8 +70,9 @@
69 if reporter is None:70 if reporter is None:
70 reporter = modReporter._makeDefaultReporter()71 reporter = modReporter._makeDefaultReporter()
71 try:72 try:
72 return check(file(filename, 'U').read() + '\n', filename, reporter)73 return check(open(filename, 'U').read() + '\n', filename, reporter)
73 except IOError, msg:74 except IOError:
75 msg = sys.exc_info()[1]
74 reporter.unexpectedError(filename, msg.args[1])76 reporter.unexpectedError(filename, msg.args[1])
75 return 177 return 1
7678
7779
=== modified file 'pyflakes/test/harness.py'
--- pyflakes/test/harness.py 2013-01-08 16:34:11 +0000
+++ pyflakes/test/harness.py 2013-01-24 10:27:21 +0000
@@ -15,8 +15,8 @@
15 w = checker.Checker(ast, **kw)15 w = checker.Checker(ast, **kw)
16 outputs = [type(o) for o in w.messages]16 outputs = [type(o) for o in w.messages]
17 expectedOutputs = list(expectedOutputs)17 expectedOutputs = list(expectedOutputs)
18 outputs.sort()18 outputs.sort(key=lambda t: t.__name__)
19 expectedOutputs.sort()19 expectedOutputs.sort(key=lambda t: t.__name__)
20 self.assertEqual(outputs, expectedOutputs, '''\20 self.assertEqual(outputs, expectedOutputs, '''\
21for input:21for input:
22%s22%s
2323
=== modified file 'pyflakes/test/test_imports.py'
--- pyflakes/test/test_imports.py 2013-01-08 16:34:11 +0000
+++ pyflakes/test/test_imports.py 2013-01-24 10:27:21 +0000
@@ -16,8 +16,8 @@
16 self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)16 self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
1717
18 def test_usedImport(self):18 def test_usedImport(self):
19 self.flakes('import fu; print fu')19 self.flakes('import fu; print(fu)')
20 self.flakes('from baz import fu; print fu')20 self.flakes('from baz import fu; print(fu)')
2121
22 def test_redefinedWhileUnused(self):22 def test_redefinedWhileUnused(self):
23 self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)23 self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)
@@ -74,28 +74,28 @@
74 import fu74 import fu
75 class bar:75 class bar:
76 fu = 176 fu = 1
77 print fu77 print(fu)
78 ''')78 ''')
7979
80 def test_usedInFunction(self):80 def test_usedInFunction(self):
81 self.flakes('''81 self.flakes('''
82 import fu82 import fu
83 def fun():83 def fun():
84 print fu84 print(fu)
85 ''')85 ''')
8686
87 def test_shadowedByParameter(self):87 def test_shadowedByParameter(self):
88 self.flakes('''88 self.flakes('''
89 import fu89 import fu
90 def fun(fu):90 def fun(fu):
91 print fu91 print(fu)
92 ''', m.UnusedImport)92 ''', m.UnusedImport)
9393
94 self.flakes('''94 self.flakes('''
95 import fu95 import fu
96 def fun(fu):96 def fun(fu):
97 print fu97 print(fu)
98 print fu98 print(fu)
99 ''')99 ''')
100100
101 def test_newAssignment(self):101 def test_newAssignment(self):
@@ -106,12 +106,12 @@
106 self.flakes('import fu; "bar".fu.baz', m.UnusedImport)106 self.flakes('import fu; "bar".fu.baz', m.UnusedImport)
107107
108 def test_usedInSlice(self):108 def test_usedInSlice(self):
109 self.flakes('import fu; print fu.bar[1:]')109 self.flakes('import fu; print(fu.bar[1:])')
110110
111 def test_usedInIfBody(self):111 def test_usedInIfBody(self):
112 self.flakes('''112 self.flakes('''
113 import fu113 import fu
114 if True: print fu114 if True: print(fu)
115 ''')115 ''')
116116
117 def test_usedInIfConditional(self):117 def test_usedInIfConditional(self):
@@ -131,7 +131,7 @@
131 self.flakes('''131 self.flakes('''
132 import fu132 import fu
133 if False: pass133 if False: pass
134 else: print fu134 else: print(fu)
135 ''')135 ''')
136136
137 def test_usedInCall(self):137 def test_usedInCall(self):
@@ -156,14 +156,14 @@
156 import fu156 import fu
157 def bleh():157 def bleh():
158 pass158 pass
159 print fu159 print(fu)
160 ''')160 ''')
161161
162 def test_usedInFor(self):162 def test_usedInFor(self):
163 self.flakes('''163 self.flakes('''
164 import fu164 import fu
165 for bar in range(9):165 for bar in range(9):
166 print fu166 print(fu)
167 ''')167 ''')
168168
169 def test_usedInForElse(self):169 def test_usedInForElse(self):
@@ -172,7 +172,7 @@
172 for bar in range(10):172 for bar in range(10):
173 pass173 pass
174 else:174 else:
175 print fu175 print(fu)
176 ''')176 ''')
177177
178 def test_redefinedByFor(self):178 def test_redefinedByFor(self):
@@ -262,11 +262,12 @@
262 ''')262 ''')
263263
264 def test_redefinedByExcept(self):264 def test_redefinedByExcept(self):
265 as_exc = ', ' if version_info < (2, 6) else ' as '
265 self.flakes('''266 self.flakes('''
266 import fu267 import fu
267 try: pass268 try: pass
268 except Exception, fu: pass269 except Exception%sfu: pass
269 ''', m.RedefinedWhileUnused)270 ''' % as_exc, m.RedefinedWhileUnused)
270271
271 def test_usedInRaise(self):272 def test_usedInRaise(self):
272 self.flakes('''273 self.flakes('''
@@ -341,11 +342,16 @@
341 def f(): global fu342 def f(): global fu
342 ''', m.UnusedImport)343 ''', m.UnusedImport)
343344
345 @skipIf(version_info >= (3,), 'deprecated syntax')
344 def test_usedInBackquote(self):346 def test_usedInBackquote(self):
345 self.flakes('import fu; `fu`')347 self.flakes('import fu; `fu`')
346348
347 def test_usedInExec(self):349 def test_usedInExec(self):
348 self.flakes('import fu; exec "print 1" in fu.bar')350 if version_info < (3,):
351 exec_stmt = 'exec "print 1" in fu.bar'
352 else:
353 exec_stmt = 'exec("print(1)", fu.bar)'
354 self.flakes('import fu; %s' % exec_stmt)
349355
350 def test_usedInLambda(self):356 def test_usedInLambda(self):
351 self.flakes('import fu; lambda: fu')357 self.flakes('import fu; lambda: fu')
@@ -385,7 +391,7 @@
385 import fu391 import fu
386 class b:392 class b:
387 def c(self):393 def c(self):
388 print fu394 print(fu)
389 ''')395 ''')
390396
391 def test_importStar(self):397 def test_importStar(self):
392398
=== modified file 'pyflakes/test/test_script.py'
--- pyflakes/test/test_script.py 2013-01-08 16:34:11 +0000
+++ pyflakes/test/test_script.py 2013-01-24 10:27:21 +0000
@@ -7,9 +7,12 @@
7import shutil7import shutil
8import subprocess8import subprocess
9import tempfile9import tempfile
10from StringIO import StringIO10try:
11 from io import StringIO
12except ImportError:
13 from StringIO import StringIO
1114
12from unittest2 import TestCase15from unittest2 import skipIf, TestCase
1316
14from pyflakes.messages import UnusedImport17from pyflakes.messages import UnusedImport
15from pyflakes.reporter import Reporter18from pyflakes.reporter import Reporter
@@ -207,8 +210,8 @@
207 """210 """
208 err = StringIO()211 err = StringIO()
209 reporter = Reporter(None, err)212 reporter = Reporter(None, err)
210 reporter.unexpectedError(u'source.py', u'error message')213 reporter.unexpectedError('source.py', 'error message')
211 self.assertEquals(u'source.py: error message\n', err.getvalue())214 self.assertEquals('source.py: error message\n', err.getvalue())
212215
213216
214 def test_flake(self):217 def test_flake(self):
@@ -234,6 +237,8 @@
234 Make a temporary file containing C{content} and return a path to it.237 Make a temporary file containing C{content} and return a path to it.
235 """238 """
236 _, fpath = tempfile.mkstemp()239 _, fpath = tempfile.mkstemp()
240 if not hasattr(content, 'decode'):
241 content = content.encode('ascii')
237 fd = open(fpath, 'wb')242 fd = open(fpath, 'wb')
238 fd.write(content)243 fd.write(content)
239 fd.close()244 fd.close()
@@ -309,10 +314,11 @@
309 # Sanity check - SyntaxError.text should be multiple lines, if it314 # Sanity check - SyntaxError.text should be multiple lines, if it
310 # isn't, something this test was unprepared for has happened.315 # isn't, something this test was unprepared for has happened.
311 def evaluate(source):316 def evaluate(source):
312 exec source317 exec(source)
313 try:318 try:
314 evaluate(source)319 evaluate(source)
315 except SyntaxError, e:320 except SyntaxError:
321 e = sys.exc_info()[1]
316 self.assertTrue(e.text.count('\n') > 1)322 self.assertTrue(e.text.count('\n') > 1)
317 else:323 else:
318 self.fail()324 self.fail()
@@ -353,12 +359,13 @@
353 pass359 pass
354"""360"""
355 sourcePath = self.makeTempFile(source)361 sourcePath = self.makeTempFile(source)
362 last_line = ' ^\n' if sys.version_info >= (3, 2) else ''
356 self.assertHasErrors(363 self.assertHasErrors(
357 sourcePath,364 sourcePath,
358 ["""\365 ["""\
359%s:1: non-default argument follows default argument366%s:1: non-default argument follows default argument
360def foo(bar=baz, bax):367def foo(bar=baz, bax):
361""" % (sourcePath,)])368%s""" % (sourcePath, last_line)])
362369
363370
364 def test_nonKeywordAfterKeywordSyntaxError(self):371 def test_nonKeywordAfterKeywordSyntaxError(self):
@@ -371,12 +378,13 @@
371foo(bar=baz, bax)378foo(bar=baz, bax)
372"""379"""
373 sourcePath = self.makeTempFile(source)380 sourcePath = self.makeTempFile(source)
381 last_line = ' ^\n' if sys.version_info >= (3, 2) else ''
374 self.assertHasErrors(382 self.assertHasErrors(
375 sourcePath,383 sourcePath,
376 ["""\384 ["""\
377%s:1: non-keyword arg after keyword arg385%s:1: non-keyword arg after keyword arg
378foo(bar=baz, bax)386foo(bar=baz, bax)
379""" % (sourcePath,)])387%s""" % (sourcePath, last_line)])
380388
381389
382 def test_permissionDenied(self):390 def test_permissionDenied(self):
@@ -405,15 +413,17 @@
405 errors, [('flake', str(UnusedImport(sourcePath, 1, 'foo')))])413 errors, [('flake', str(UnusedImport(sourcePath, 1, 'foo')))])
406414
407415
416 @skipIf(sys.version_info >= (3,), "need adaptation for Python 3")
408 def test_misencodedFile(self):417 def test_misencodedFile(self):
409 """418 """
410 If a source file contains bytes which cannot be decoded, this is419 If a source file contains bytes which cannot be decoded, this is
411 reported on stderr.420 reported on stderr.
412 """421 """
413 source = u"""\422 SNOWMAN = unichr(0x2603)
423 source = ("""\
414# coding: ascii424# coding: ascii
415x = "\N{SNOWMAN}"425x = "%s"
416""".encode('utf-8')426""" % SNOWMAN).encode('utf-8')
417 sourcePath = self.makeTempFile(source)427 sourcePath = self.makeTempFile(source)
418 self.assertHasErrors(428 self.assertHasErrors(
419 sourcePath, ["%s: problem decoding source\n" % (sourcePath,)])429 sourcePath, ["%s: problem decoding source\n" % (sourcePath,)])
@@ -428,11 +438,11 @@
428 os.mkdir(os.path.join(tempdir, 'foo'))438 os.mkdir(os.path.join(tempdir, 'foo'))
429 file1 = os.path.join(tempdir, 'foo', 'bar.py')439 file1 = os.path.join(tempdir, 'foo', 'bar.py')
430 fd = open(file1, 'wb')440 fd = open(file1, 'wb')
431 fd.write("import baz\n")441 fd.write("import baz\n".encode('ascii'))
432 fd.close()442 fd.close()
433 file2 = os.path.join(tempdir, 'baz.py')443 file2 = os.path.join(tempdir, 'baz.py')
434 fd = open(file2, 'wb')444 fd = open(file2, 'wb')
435 fd.write("import contraband")445 fd.write("import contraband".encode('ascii'))
436 fd.close()446 fd.close()
437 log = []447 log = []
438 reporter = LoggingReporter(log)448 reporter = LoggingReporter(log)
@@ -488,6 +498,9 @@
488 stdout=subprocess.PIPE, stderr=subprocess.PIPE)498 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
489 (stdout, stderr) = p.communicate()499 (stdout, stderr) = p.communicate()
490 rv = p.wait()500 rv = p.wait()
501 if sys.version_info >= (3,):
502 stdout = stdout.decode('utf-8')
503 stderr = stderr.decode('utf-8')
491 return (stdout, stderr, rv)504 return (stdout, stderr, rv)
492505
493506
@@ -508,7 +521,7 @@
508 and the warnings are printed to stdout.521 and the warnings are printed to stdout.
509 """522 """
510 fd = open(self.tempfilepath, 'wb')523 fd = open(self.tempfilepath, 'wb')
511 fd.write("import contraband\n")524 fd.write("import contraband\n".encode('ascii'))
512 fd.close()525 fd.close()
513 d = self.runPyflakes([self.tempfilepath])526 d = self.runPyflakes([self.tempfilepath])
514 self.assertEqual(d, ("%s\n" % UnusedImport(self.tempfilepath, 1, 'contraband'), '', 1))527 self.assertEqual(d, ("%s\n" % UnusedImport(self.tempfilepath, 1, 'contraband'), '', 1))
@@ -528,5 +541,5 @@
528 """541 """
529 If no arguments are passed to C{pyflakes} then it reads from stdin.542 If no arguments are passed to C{pyflakes} then it reads from stdin.
530 """543 """
531 d = self.runPyflakes([], stdin='import contraband')544 d = self.runPyflakes([], stdin='import contraband'.encode('ascii'))
532 self.assertEqual(d, ("%s\n" % UnusedImport('<stdin>', 1, 'contraband'), '', 1))545 self.assertEqual(d, ("%s\n" % UnusedImport('<stdin>', 1, 'contraband'), '', 1))
533546
=== modified file 'pyflakes/test/test_undefined_names.py'
--- pyflakes/test/test_undefined_names.py 2013-01-08 16:34:11 +0000
+++ pyflakes/test/test_undefined_names.py 2013-01-24 10:27:21 +0000
@@ -1,7 +1,8 @@
11
2from _ast import PyCF_ONLY_AST2from _ast import PyCF_ONLY_AST
3from sys import version_info
34
4from unittest2 import skip, TestCase5from unittest2 import skip, skipIf, TestCase
56
6from pyflakes import messages as m, checker7from pyflakes import messages as m, checker
7from pyflakes.test import harness8from pyflakes.test import harness
@@ -80,6 +81,7 @@
80 bar81 bar
81 ''', m.ImportStarUsed, m.UndefinedName)82 ''', m.ImportStarUsed, m.UndefinedName)
8283
84 @skipIf(version_info >= (3,), 'obsolete syntax')
83 def test_unpackedParameter(self):85 def test_unpackedParameter(self):
84 '''Unpacked function parameters create bindings'''86 '''Unpacked function parameters create bindings'''
85 self.flakes('''87 self.flakes('''
@@ -102,7 +104,7 @@
102 self.flakes('''104 self.flakes('''
103 global x105 global x
104 def foo():106 def foo():
105 print x107 print(x)
106 ''', m.UndefinedName)108 ''', m.UndefinedName)
107109
108 def test_del(self):110 def test_del(self):
@@ -176,8 +178,8 @@
176 def h(self):178 def h(self):
177 a = x179 a = x
178 x = None180 x = None
179 print x, a181 print(x, a)
180 print x182 print(x)
181 ''', m.UndefinedLocal)183 ''', m.UndefinedLocal)
182184
183185
@@ -246,7 +248,7 @@
246 '''star and double-star arg names are defined'''248 '''star and double-star arg names are defined'''
247 self.flakes('''249 self.flakes('''
248 def f(a, *b, **c):250 def f(a, *b, **c):
249 print a, b, c251 print(a, b, c)
250 ''')252 ''')
251253
252 def test_definedInGenExp(self):254 def test_definedInGenExp(self):
@@ -254,7 +256,8 @@
254 Using the loop variable of a generator expression results in no256 Using the loop variable of a generator expression results in no
255 warnings.257 warnings.
256 """258 """
257 self.flakes('(a for a in xrange(10) if a)')259 self.flakes('(a for a in %srange(10) if a)' %
260 ('x' if version_info < (3,) else ''))
258261
259262
260263
261264
=== modified file 'setup.py'
--- setup.py 2011-09-03 16:31:04 +0000
+++ setup.py 2013-01-24 10:27:21 +0000
@@ -24,6 +24,8 @@
24 "Intended Audience :: Developers",24 "Intended Audience :: Developers",
25 "License :: OSI Approved :: MIT License",25 "License :: OSI Approved :: MIT License",
26 "Programming Language :: Python",26 "Programming Language :: Python",
27 "Programming Language :: Python :: 2",
28 "Programming Language :: Python :: 3",
27 "Topic :: Software Development",29 "Topic :: Software Development",
28 "Topic :: Utilities",30 "Topic :: Utilities",
29 ])31 ])

Subscribers

People subscribed via source and target branches

to all changes: