Merge lp:~pyflakes-dev/pyflakes/1172130-doctest-syntax-error into lp:pyflakes

Proposed by Florent
Status: Merged
Merged at revision: 98
Proposed branch: lp:~pyflakes-dev/pyflakes/1172130-doctest-syntax-error
Merge into: lp:pyflakes
Diff against target: 203 lines (+80/-20) (has conflicts)
5 files modified
NEWS.txt (+12/-1)
pyflakes/__init__.py (+4/-0)
pyflakes/checker.py (+24/-12)
pyflakes/messages.py (+3/-1)
pyflakes/test/test_doctests.py (+37/-6)
Text conflict in NEWS.txt
Text conflict in pyflakes/__init__.py
To merge this branch: bzr merge lp:~pyflakes-dev/pyflakes/1172130-doctest-syntax-error
Reviewer Review Type Date Requested Status
Pyflakes Dev Pending
Review via email: mp+160567@code.launchpad.net

Description of the change

Fixes the regression in 0.7
Needs tests.

To post a comment you must log in.
99. By Florent

Add boolean attribute Checker.withDoctest to ignore doctests

100. By Florent

Add environment variables PYFLAKES_NODOCTEST and PYFLAKES_BUILTINS

101. By Florent

Add tests for DoctestSyntaxError lineno and col

102. By Florent

More tests for doctest (lineno, col) calculation

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.txt'
2--- NEWS.txt 2013-04-23 07:17:03 +0000
3+++ NEWS.txt 2013-04-24 12:04:24 +0000
4@@ -1,4 +1,15 @@
5-0.7.1 (2013-04-23):
6+<<<<<<< TREE
7+0.7.1 (2013-04-23):
8+=======
9+0.7.x (unreleased):
10+ - Fix computation of `DoctestSyntaxError.lineno` and `col`.
11+ - Add boolean attribute `Checker.withDoctest` to ignore doctests.
12+ - If environment variable `PYFLAKES_NODOCTEST` is set, skip doctests.
13+ - Environment variable `PYFLAKES_BUILTINS` accepts a comma-separated
14+ list of additional built-in names.
15+
16+0.7.1 (2013-04-23):
17+>>>>>>> MERGE-SOURCE
18 - File `bin/pyflakes` was missing in tarball generated with distribute.
19 - Fix reporting errors in non-ASCII filenames (Python 2.x).
20
21
22=== modified file 'pyflakes/__init__.py'
23--- pyflakes/__init__.py 2013-04-23 07:17:03 +0000
24+++ pyflakes/__init__.py 2013-04-24 12:04:24 +0000
25@@ -1,2 +1,6 @@
26
27+<<<<<<< TREE
28 __version__ = '0.7.1'
29+=======
30+__version__ = '0.7.2a0'
31+>>>>>>> MERGE-SOURCE
32
33=== modified file 'pyflakes/checker.py'
34--- pyflakes/checker.py 2013-04-21 16:07:22 +0000
35+++ pyflakes/checker.py 2013-04-24 12:04:24 +0000
36@@ -5,7 +5,7 @@
37 Also, it models the Bindings and Scopes.
38 """
39 import doctest
40-import os.path
41+import os
42 import sys
43 try:
44 builtin_vars = dir(__import__('builtins'))
45@@ -225,7 +225,13 @@
46 nodeDepth = 0
47 offset = None
48 traceTree = False
49+ withDoctest = ('PYFLAKES_NODOCTEST' not in os.environ)
50+
51 builtIns = set(builtin_vars).union(_MAGIC_GLOBALS)
52+ _customBuiltIns = os.environ.get('PYFLAKES_BUILTINS')
53+ if _customBuiltIns:
54+ builtIns.update(_customBuiltIns.split(','))
55+ del _customBuiltIns
56
57 def __init__(self, tree, filename='(none)', builtins=None):
58 self._nodeHandlers = {}
59@@ -523,7 +529,11 @@
60 def getDocstring(self, node):
61 if isinstance(node, ast.Expr):
62 node = node.value
63- return node.s if isinstance(node, ast.Str) else None
64+ if not isinstance(node, ast.Str):
65+ return (None, None)
66+ # Computed incorrectly if the docstring has backslash
67+ doctest_lineno = node.lineno - node.s.count('\n') - 1
68+ return (node.s, doctest_lineno)
69
70 def handleNode(self, node, parent):
71 if node is None:
72@@ -550,12 +560,12 @@
73 _getDoctestExamples = doctest.DocTestParser().get_examples
74
75 def handleDoctests(self, node):
76- docstring = node.body and self.getDocstring(node.body[0])
77- if not docstring:
78- return
79 try:
80+ docstring, node_lineno = self.getDocstring(node.body[0])
81+ if not docstring:
82+ return
83 examples = self._getDoctestExamples(docstring)
84- except ValueError:
85+ except (ValueError, IndexError):
86 # e.g. line 6 of the docstring for <string> has inconsistent
87 # leading whitespace: ...
88 return
89@@ -566,11 +576,11 @@
90 tree = compile(example.source, "<doctest>", "exec", ast.PyCF_ONLY_AST)
91 except SyntaxError:
92 e = sys.exc_info()[1]
93- node.lineno += example.lineno + e.lineno
94- node.col_offset += example.indent + 4 + e.offset
95- self.report(messages.DoctestSyntaxError, node)
96+ position = (node_lineno + example.lineno + e.lineno,
97+ example.indent + 4 + e.offset)
98+ self.report(messages.DoctestSyntaxError, node, position)
99 else:
100- self.offset = (node_offset[0] + node.lineno + example.lineno,
101+ self.offset = (node_offset[0] + node_lineno + example.lineno,
102 node_offset[1] + example.indent + 4)
103 self.handleChildren(tree)
104 self.offset = node_offset
105@@ -689,7 +699,8 @@
106 self.handleNode(deco, node)
107 self.addBinding(node, FunctionDefinition(node.name, node))
108 self.LAMBDA(node)
109- self.deferFunction(lambda: self.handleDoctests(node))
110+ if self.withDoctest:
111+ self.deferFunction(lambda: self.handleDoctests(node))
112
113 def LAMBDA(self, node):
114 args = []
115@@ -767,7 +778,8 @@
116 for keywordNode in node.keywords:
117 self.handleNode(keywordNode, node)
118 self.pushClassScope()
119- self.deferFunction(lambda: self.handleDoctests(node))
120+ if self.withDoctest:
121+ self.deferFunction(lambda: self.handleDoctests(node))
122 for stmt in node.body:
123 self.handleNode(stmt, node)
124 self.popScope()
125
126=== modified file 'pyflakes/messages.py'
127--- pyflakes/messages.py 2013-04-21 15:32:22 +0000
128+++ pyflakes/messages.py 2013-04-24 12:04:24 +0000
129@@ -68,8 +68,10 @@
130 class DoctestSyntaxError(Message):
131 message = 'syntax error in doctest'
132
133- def __init__(self, filename, loc):
134+ def __init__(self, filename, loc, position=None):
135 Message.__init__(self, filename, loc)
136+ if position:
137+ (self.lineno, self.col) = position
138 self.message_args = ()
139
140
141
142=== modified file 'pyflakes/test/test_doctests.py'
143--- pyflakes/test/test_doctests.py 2013-04-04 23:04:43 +0000
144+++ pyflakes/test/test_doctests.py 2013-04-24 12:04:24 +0000
145@@ -138,14 +138,27 @@
146 self.assertEqual(exc.col, 0)
147
148 def test_syntaxErrorInDoctest(self):
149- exc = super(Test, self).flakes('''
150- def doctest_stuff():
151- """
152- >>> from # line 4
153- """
154- ''', m.DoctestSyntaxError).messages[0]
155+ exceptions = super(Test, self).flakes(
156+ '''
157+ def doctest_stuff():
158+ """
159+ >>> from # line 4
160+ >>> fortytwo = 42
161+ >>> except Exception:
162+ """
163+ ''',
164+ m.DoctestSyntaxError,
165+ m.DoctestSyntaxError,
166+ m.DoctestSyntaxError).messages
167+ exc = exceptions[0]
168 self.assertEqual(exc.lineno, 4)
169 self.assertEqual(exc.col, 26)
170+ exc = exceptions[1]
171+ self.assertEqual(exc.lineno, 5)
172+ self.assertEqual(exc.col, 16)
173+ exc = exceptions[2]
174+ self.assertEqual(exc.lineno, 6)
175+ self.assertEqual(exc.col, 18)
176
177 def test_indentationErrorInDoctest(self):
178 exc = super(Test, self).flakes('''
179@@ -158,6 +171,24 @@
180 self.assertEqual(exc.lineno, 5)
181 self.assertEqual(exc.col, 16)
182
183+ def test_offsetWithMultiLineArgs(self):
184+ (exc1, exc2) = super(Test, self).flakes(
185+ '''
186+ def doctest_stuff(arg1,
187+ arg2,
188+ arg3):
189+ """
190+ >>> assert
191+ >>> this
192+ """
193+ ''',
194+ m.DoctestSyntaxError,
195+ m.UndefinedName).messages
196+ self.assertEqual(exc1.lineno, 6)
197+ self.assertEqual(exc1.col, 19)
198+ self.assertEqual(exc2.lineno, 7)
199+ self.assertEqual(exc2.col, 12)
200+
201 def test_doctestCanReferToFunction(self):
202 super(Test, self).flakes("""
203 def foo():

Subscribers

People subscribed via source and target branches

to all changes: