Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

UTF-8 bug fix, KeyError bug fix in errorMessages. David Cramer's vers…

…ion of pyflakes fails to work, though it works with standard pyflakes.
  • Loading branch information...
commit f1f81141f81e751fae6c7a235dcf6f74cb5e10b5 1 parent cd142ed
Miguel Araujo authored February 07, 2011

Showing 1 changed file with 256 additions and 255 deletions. Show diff stats Hide diff stats

  1. 511  sublimeflakes.py
511  sublimeflakes.py
@@ -6,216 +6,217 @@
6 6
 drawType = (sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
7 7
 
8 8
 class OffsetError(messages.Message):
9  
-	message = '%r at offset %r'
10  
-	def __init__(self, filename, lineno, text, offset):
11  
-		messages.Message.__init__(self, filename, lineno)
12  
-		self.offset = offset
13  
-		self.message_args = (text, offset)
  9
+    message = '%r at offset %r'
  10
+    def __init__(self, filename, lineno, text, offset):
  11
+        messages.Message.__init__(self, filename, lineno)
  12
+        self.offset = offset
  13
+        self.message_args = (text, offset)
14 14
 
15 15
 class PythonError(messages.Message):
16  
-	message = '%r'
17  
-	def __init__(self, filename, lineno, text):
18  
-		messages.Message.__init__(self, filename, lineno)
19  
-		self.message_args = (text,)
  16
+    message = '%r'
  17
+    def __init__(self, filename, lineno, text):
  18
+        messages.Message.__init__(self, filename, lineno)
  19
+        self.message_args = (text,)
20 20
 
21 21
 def check(codeString, filename):
22  
-	codeString = codeString.rstrip()
23  
-	try:
24  
-		try:
25  
-			compile(codeString, filename, "exec")
26  
-		except MemoryError:
27  
-			# Python 2.4 will raise MemoryError if the source can't be
28  
-			# decoded.
29  
-			if sys.version_info[:2] == (2, 4):
30  
-				raise SyntaxError(None)
31  
-			raise
32  
-	except (SyntaxError, IndentationError), value:
33  
-		# print traceback.format_exc() # helps debug new cases
34  
-		msg = value.args[0]
35  
-
36  
-		lineno, offset, text = value.lineno, value.offset, value.text
37  
-
38  
-		# If there's an encoding problem with the file, the text is None.
39  
-		if text is None:
40  
-			# Avoid using msg, since for the only known case, it contains a
41  
-			# bogus message that claims the encoding the file declared was
42  
-			# unknown.
43  
-			if msg.startswith('duplicate argument'):
44  
-				arg = msg.split('duplicate argument ',1)[1].split(' ',1)[0].strip('\'"')
45  
-				error = messages.DuplicateArgument(filename, lineno, arg)
46  
-			else:
47  
-				error = PythonError(filename, lineno, msg)
48  
-		else:
49  
-			line = text.splitlines()[-1]
50  
-
51  
-			if offset is not None:
52  
-				offset = offset - (len(text) - len(line))
53  
-
54  
-			if offset is not None:
55  
-				error = OffsetError(filename, lineno, msg, offset)
56  
-			else:
57  
-				error = PythonError(filename, lineno, msg)
58  
-
59  
-		return [error]
60  
-	else:
61  
-		# Okay, it's syntactically valid.  Now parse it into an ast and check
62  
-		# it.
63  
-		tree = compiler.parse(codeString)
64  
-		w = checker.Checker(tree, filename)
65  
-		w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
66  
-		return w.messages
  22
+    codeString = codeString.rstrip()
  23
+    try:
  24
+        try:
  25
+            compile(codeString, filename, "exec")
  26
+        except MemoryError:
  27
+            # Python 2.4 will raise MemoryError if the source can't be
  28
+            # decoded.
  29
+            if sys.version_info[:2] == (2, 4):
  30
+                raise SyntaxError(None)
  31
+            raise
  32
+    except (SyntaxError, IndentationError), value:
  33
+        # print traceback.format_exc() # helps debug new cases
  34
+        msg = value.args[0]
  35
+
  36
+        lineno, offset, text = value.lineno, value.offset, value.text
  37
+
  38
+        # If there's an encoding problem with the file, the text is None.
  39
+        if text is None:
  40
+            # Avoid using msg, since for the only known case, it contains a
  41
+            # bogus message that claims the encoding the file declared was
  42
+            # unknown.
  43
+            if msg.startswith('duplicate argument'):
  44
+                arg = msg.split('duplicate argument ',1)[1].split(' ',1)[0].strip('\'"')
  45
+                error = messages.DuplicateArgument(filename, lineno, arg)
  46
+            else:
  47
+                error = PythonError(filename, lineno, msg)
  48
+        else:
  49
+            line = text.splitlines()[-1]
  50
+
  51
+            if offset is not None:
  52
+                offset = offset - (len(text) - len(line))
  53
+
  54
+            if offset is not None:
  55
+                error = OffsetError(filename, lineno, msg, offset)
  56
+            else:
  57
+                error = PythonError(filename, lineno, msg)
  58
+
  59
+        return [error]
  60
+    else:
  61
+        # Okay, it's syntactically valid.  Now parse it into an ast and check
  62
+        # it.
  63
+        ucodeString = unicode(codeString).encode('utf-8')
  64
+        tree = compiler.parse(codeString)
  65
+        w = checker.Checker(tree, filename)
  66
+        w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
  67
+        return w.messages
67 68
 
68 69
 def printf(*args): print '"' + ' '.join(args) + '"'
69 70
 
70 71
 global lineMessages
71 72
 lineMessages = {}
72 73
 def validate(view):
73  
-	global lineMessages
74  
-	vid = view.id()
75  
-
76  
-	text = view.substr(sublime.Region(0, view.size()))
77  
-
78  
-	stripped_lines = []
79  
-	good_lines = []
80  
-	lines = text.split('\n')
81  
-	for i in xrange(len(lines)):
82  
-		line = lines[i]
83  
-		if not line.strip() or line.strip().startswith('#'):
84  
-			stripped_lines.append(i)
85  
-		else:
86  
-			good_lines.append(line)
87  
-
88  
-	text = '\n'.join(good_lines)
89  
-	if view.file_name(): filename = os.path.split(view.file_name())[-1]
90  
-	else: filename = 'untitled'
91  
-
92  
-	errors = check(text, filename)
93  
-
94  
-	lines = set()
95  
-	underline = []
96  
-
97  
-	def underlineRange(lineno, position, length=1):
98  
-		line = view.full_line(view.text_point(lineno, 0))
99  
-		position += line.begin()
100  
-
101  
-		for i in xrange(length):
102  
-			underline.append(sublime.Region(position + i))
103  
-
104  
-	def underlineRegex(lineno, regex, wordmatch=None, linematch=None):
105  
-		lines.add(lineno)
106  
-		offset = 0
107  
-
108  
-		line = view.full_line(view.text_point(lineno, 0))
109  
-		lineText = view.substr(line)
110  
-		if linematch:
111  
-			match = re.match(linematch, lineText)
112  
-			if match:
113  
-				lineText = match.group('match')
114  
-				offset = match.start('match')
115  
-			else:
116  
-				return
117  
-
118  
-		iters = re.finditer(regex, lineText)
119  
-		results = [(result.start('underline'), result.end('underline')) for result in iters if
120  
-											not wordmatch or result.group('underline') == wordmatch]
121  
-
122  
-		for start, end in results:
123  
-			underlineRange(lineno, start+offset, end-start)
124  
-
125  
-	def underlineWord(lineno, word):
126  
-		regex = '((and|or|not|if|elif|while|in)\s+|[+\-*^%%<>=({[])*\s*(?P<underline>[\w]*%s[\w]*)' % (word)
127  
-		underlineRegex(lineno, regex, word)
128  
-
129  
-	def underlineImport(lineno, word):
130  
-		linematch = 'import\s+(?P<match>[^#;]+)'
131  
-		regex = '(\s+|,\s*|as\s+)(?P<underline>[\w]*%s[\w]*)' % word
132  
-		underlineRegex(lineno, regex, word, linematch)
133  
-
134  
-	def underlineForVar(lineno, word):
135  
-		regex = 'for\s+(?P<underline>[\w]*%s[\w*])' % word
136  
-		underlineRegex(lineno, regex, word)
137  
-
138  
-	def underlineDuplicateArgument(lineno, word):
139  
-		regex = 'def [\w_]+\(.*?(?P<underline>[\w]*%s[\w]*)' % word
140  
-		underlineRegex(lineno, regex, word)
141  
-
142  
-	errorMessages = {}
143  
-	def addMessage(lineno, message):
144  
-		message = str(message)
145  
-		if lineno in lineMessages:
146  
-			errorMessages[lineno].append(message)
147  
-		else:
148  
-			errorMessages[lineno] = [message]
149  
-
150  
-	view.erase_regions('pyflakes-syntax')
151  
-	view.erase_regions('pyflakes-syntax-underline')
152  
-	view.erase_regions('pyflakes-underline')
153  
-	for error in errors:
154  
-		error.lineno -= 1
155  
-		for i in stripped_lines:
156  
-			if error.lineno >= i:
157  
-				error.lineno += 1
158  
-
159  
-		lines.add(error.lineno)
160  
-		addMessage(error.lineno, error)
161  
-		if isinstance(error, OffsetError):
162  
-			underlineRange(error.lineno, error.offset)
163  
-			if len(errors) == 1 and False:
164  
-				outlines = [view.full_line(view.text_point(error.lineno, 0)) for lineno in lines]
165  
-				view.add_regions('pyflakes-syntax', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
166  
-				view.add_regions('pyflakes-syntax-underline', underline, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
167  
-				return
168  
-
169  
-		elif isinstance(error, PythonError):
170  
-			if len(errors) == 1 and False:
171  
-				outlines = [view.full_line(view.text_point(error.lineno, 0)) for lineno in lines]
172  
-				view.add_regions('pyflakes-syntax', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
173  
-				return
174  
-
175  
-		elif isinstance(error, messages.UnusedImport):
176  
-			underlineImport(error.lineno, error.name)
177  
-
178  
-		elif isinstance(error, messages.RedefinedWhileUnused):
179  
-			underlineWord(error.lineno, error.name)
180  
-
181  
-		elif isinstance(error, messages.ImportShadowedByLoopVar):
182  
-			underlineForVar(error.lineno, error.name)
183  
-
184  
-		elif isinstance(error, messages.ImportStarUsed):
185  
-			underlineImport(error.lineno, '\*')
  74
+    global lineMessages
  75
+    vid = view.id()
  76
+
  77
+    text = view.substr(sublime.Region(0, view.size()))
  78
+
  79
+    stripped_lines = []
  80
+    good_lines = []
  81
+    lines = text.split('\n')
  82
+    for i in xrange(len(lines)):
  83
+        line = lines[i]
  84
+        if not line.strip() or line.strip().startswith('#'):
  85
+            stripped_lines.append(i)
  86
+        else:
  87
+            good_lines.append(line)
  88
+
  89
+    text = '\n'.join(good_lines)
  90
+    if view.file_name(): filename = os.path.split(view.file_name())[-1]
  91
+    else: filename = 'untitled'
  92
+
  93
+    errors = check(text, filename)
  94
+
  95
+    lines = set()
  96
+    underline = []
  97
+
  98
+    def underlineRange(lineno, position, length=1):
  99
+        line = view.full_line(view.text_point(lineno, 0))
  100
+        position += line.begin()
  101
+
  102
+        for i in xrange(length):
  103
+            underline.append(sublime.Region(position + i))
  104
+
  105
+    def underlineRegex(lineno, regex, wordmatch=None, linematch=None):
  106
+        lines.add(lineno)
  107
+        offset = 0
  108
+
  109
+        line = view.full_line(view.text_point(lineno, 0))
  110
+        lineText = view.substr(line)
  111
+        if linematch:
  112
+            match = re.match(linematch, lineText)
  113
+            if match:
  114
+                lineText = match.group('match')
  115
+                offset = match.start('match')
  116
+            else:
  117
+                return
  118
+
  119
+        iters = re.finditer(regex, lineText)
  120
+        results = [(result.start('underline'), result.end('underline')) for result in iters if
  121
+                                            not wordmatch or result.group('underline') == wordmatch]
  122
+
  123
+        for start, end in results:
  124
+            underlineRange(lineno, start+offset, end-start)
  125
+
  126
+    def underlineWord(lineno, word):
  127
+        regex = '((and|or|not|if|elif|while|in)\s+|[+\-*^%%<>=({[])*\s*(?P<underline>[\w]*%s[\w]*)' % (word)
  128
+        underlineRegex(lineno, regex, word)
  129
+
  130
+    def underlineImport(lineno, word):
  131
+        linematch = 'import\s+(?P<match>[^#;]+)'
  132
+        regex = '(\s+|,\s*|as\s+)(?P<underline>[\w]*%s[\w]*)' % word
  133
+        underlineRegex(lineno, regex, word, linematch)
  134
+
  135
+    def underlineForVar(lineno, word):
  136
+        regex = 'for\s+(?P<underline>[\w]*%s[\w*])' % word
  137
+        underlineRegex(lineno, regex, word)
  138
+
  139
+    def underlineDuplicateArgument(lineno, word):
  140
+        regex = 'def [\w_]+\(.*?(?P<underline>[\w]*%s[\w]*)' % word
  141
+        underlineRegex(lineno, regex, word)
  142
+
  143
+    errorMessages = {}
  144
+    def addMessage(lineno, message):
  145
+        message = str(message)
  146
+        if lineno in errorMessages:
  147
+            errorMessages[lineno].append(message)
  148
+        else:
  149
+            errorMessages[lineno] = [message]
  150
+
  151
+    view.erase_regions('pyflakes-syntax')
  152
+    view.erase_regions('pyflakes-syntax-underline')
  153
+    view.erase_regions('pyflakes-underline')
  154
+    for error in errors:
  155
+        error.lineno -= 1
  156
+        for i in stripped_lines:
  157
+            if error.lineno >= i:
  158
+                error.lineno += 1
  159
+
  160
+        lines.add(error.lineno)
  161
+        addMessage(error.lineno, error)
  162
+        if isinstance(error, OffsetError):
  163
+            underlineRange(error.lineno, error.offset)
  164
+            if len(errors) == 1 and False:
  165
+                outlines = [view.full_line(view.text_point(error.lineno, 0)) for lineno in lines]
  166
+                view.add_regions('pyflakes-syntax', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
  167
+                view.add_regions('pyflakes-syntax-underline', underline, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
  168
+                return
  169
+
  170
+        elif isinstance(error, PythonError):
  171
+            if len(errors) == 1 and False:
  172
+                outlines = [view.full_line(view.text_point(error.lineno, 0)) for lineno in lines]
  173
+                view.add_regions('pyflakes-syntax', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
  174
+                return
  175
+
  176
+        elif isinstance(error, messages.UnusedImport):
  177
+            underlineImport(error.lineno, error.name)
  178
+
  179
+        elif isinstance(error, messages.RedefinedWhileUnused):
  180
+            underlineWord(error.lineno, error.name)
  181
+
  182
+        elif isinstance(error, messages.ImportShadowedByLoopVar):
  183
+            underlineForVar(error.lineno, error.name)
  184
+
  185
+        elif isinstance(error, messages.ImportStarUsed):
  186
+            underlineImport(error.lineno, '\*')
186 187
 
187  
-		elif isinstance(error, messages.UndefinedName):
188  
-			underlineWord(error.lineno, error.name)
  188
+        elif isinstance(error, messages.UndefinedName):
  189
+            underlineWord(error.lineno, error.name)
189 190
 
190  
-		elif isinstance(error, messages.UndefinedExport):
191  
-			underlineWord(error.lineno, error.name)
192  
-
193  
-		elif isinstance(error, messages.UndefinedLocal):
194  
-			underlineWord(error.lineno, error.name)
195  
-
196  
-		elif isinstance(error, messages.DuplicateArgument):
197  
-			underlineDuplicateArgument(error.lineno, error.name)
198  
-
199  
-		elif isinstance(error, messages.RedefinedFunction):
200  
-			underlineWord(error.lineno, error.name)
201  
-
202  
-		elif isinstance(error, messages.LateFutureImport):
203  
-			pass
204  
-
205  
-		elif isinstance(error, messages.UnusedVariable):
206  
-			underlineWord(error.lineno, error.name)
207  
-
208  
-		else:
209  
-			print 'Oops, we missed an error type!'
210  
-
211  
-	view.erase_regions('pyflakes-outlines')
212  
-	if underline or lines:
213  
-		outlines = [view.full_line(view.text_point(lineno, 0)) for lineno in lines]
  191
+        elif isinstance(error, messages.UndefinedExport):
  192
+            underlineWord(error.lineno, error.name)
  193
+
  194
+        elif isinstance(error, messages.UndefinedLocal):
  195
+            underlineWord(error.lineno, error.name)
  196
+
  197
+        elif isinstance(error, messages.DuplicateArgument):
  198
+            underlineDuplicateArgument(error.lineno, error.name)
  199
+
  200
+        elif isinstance(error, messages.RedefinedFunction):
  201
+            underlineWord(error.lineno, error.name)
  202
+
  203
+        elif isinstance(error, messages.LateFutureImport):
  204
+            pass
  205
+
  206
+        elif isinstance(error, messages.UnusedVariable):
  207
+            underlineWord(error.lineno, error.name)
  208
+
  209
+        else:
  210
+            print 'Oops, we missed an error type!'
  211
+
  212
+    view.erase_regions('pyflakes-outlines')
  213
+    if underline or lines:
  214
+        outlines = [view.full_line(view.text_point(lineno, 0)) for lineno in lines]
214 215
 
215  
-		view.add_regions('pyflakes-underline', underline, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
216  
-		view.add_regions('pyflakes-outlines', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
  216
+        view.add_regions('pyflakes-underline', underline, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
  217
+        view.add_regions('pyflakes-outlines', outlines, 'keyword', drawType)#sublime.DRAW_EMPTY_AS_OVERWRITE | sublime.DRAW_OUTLINED)
217 218
 
218  
-	lineMessages[vid] = errorMessages
  219
+    lineMessages[vid] = errorMessages
219 220
 
220 221
 import time, thread
221 222
 global queue, lookup
@@ -223,70 +224,70 @@ def addMessage(lineno, message):
223 224
 lookup = {}
224 225
 
225 226
 def validate_runner(): # this threaded runner keeps it from slowing down UI while you type
226  
-	global queue, lookup
227  
-	while True:
228  
-		time.sleep(0.5)
229  
-		for vid in dict(queue):
230  
-			if vid not in queue:
231  
-				return
232  
-			if queue[vid] == 0:
233  
-				validate(lookup[vid])
234  
-				try: del queue[vid]
235  
-				except: pass
236  
-				try: del lookup[vid]
237  
-				except: pass
238  
-			else:
239  
-				queue[vid] = 0
  227
+    global queue, lookup
  228
+    while True:
  229
+        time.sleep(0.5)
  230
+        for vid in dict(queue):
  231
+            if vid not in queue:
  232
+                return
  233
+            if queue[vid] == 0:
  234
+                validate(lookup[vid])
  235
+                try: del queue[vid]
  236
+                except: pass
  237
+                try: del lookup[vid]
  238
+                except: pass
  239
+            else:
  240
+                queue[vid] = 0
240 241
 
241 242
 def validate_hit(view):
242  
-	global lookup
243  
-	global queue
  243
+    global lookup
  244
+    global queue
244 245
 
245  
-	if not 'Python' in view.settings().get("syntax"):
246  
-		view.erase_regions('pyflakes-syntax')
247  
-		view.erase_regions('pyflakes-syntax-underline')
248  
-		view.erase_regions('pyflakes-underline')
249  
-		view.erase_regions('pyflakes-outlines')
250  
-		return
  246
+    if not 'Python' in view.settings().get("syntax"):
  247
+        view.erase_regions('pyflakes-syntax')
  248
+        view.erase_regions('pyflakes-syntax-underline')
  249
+        view.erase_regions('pyflakes-underline')
  250
+        view.erase_regions('pyflakes-outlines')
  251
+        return
251 252
 
252  
-	vid = view.id()
253  
-	lookup[vid] = view
254  
-	queue[vid] = 1
  253
+    vid = view.id()
  254
+    lookup[vid] = view
  255
+    queue[vid] = 1
255 256
 
256 257
 thread.start_new_thread(validate_runner, ())
257 258
 
258 259
 class pyflakes(sublime_plugin.EventListener):
259  
-	def __init__(self, *args, **kwargs):
260  
-		sublime_plugin.EventListener.__init__(self, *args, **kwargs)
261  
-		self.lastCount = {}
262  
-
263  
-	def on_modified(self, view):
264  
-		validate_hit(view)
265  
-		return
266  
-
267  
-		# alternate method which works alright when we don't have threads/set_timeout
268  
-		# from when I ported to early X beta :P
269  
-		text = view.substr(sublime.Region(0, view.size()))
270  
-		count = text.count('\n')
271  
-		if count > 500: return
272  
-		bid = view.buffer_id()
273  
-
274  
-		if bid in self.lastCount:
275  
-			if self.lastCount[bid] != count:
276  
-				validate(view)
277  
-
278  
-		self.lastCount[bid] = count
279  
-
280  
-	def on_load(self, view):
281  
-		validate_hit(view)
282  
-
283  
-	def on_post_save(self, view):
284  
-		validate_hit(view)
285  
-
286  
-	def on_selection_modified(self, view):
287  
-		vid = view.id()
288  
-		lineno = view.rowcol(view.sel()[0].end())[0]
289  
-		if vid in lineMessages and lineno in lineMessages[vid]:
290  
-			view.set_status('pyflakes', '; '.join(lineMessages[vid][lineno]))
291  
-		else:
292  
-			view.erase_status('pyflakes')
  260
+    def __init__(self, *args, **kwargs):
  261
+        sublime_plugin.EventListener.__init__(self, *args, **kwargs)
  262
+        self.lastCount = {}
  263
+
  264
+    def on_modified(self, view):
  265
+        validate_hit(view)
  266
+        return
  267
+
  268
+        # alternate method which works alright when we don't have threads/set_timeout
  269
+        # from when I ported to early X beta :P
  270
+        text = view.substr(sublime.Region(0, view.size()))
  271
+        count = text.count('\n')
  272
+        if count > 500: return
  273
+        bid = view.buffer_id()
  274
+
  275
+        if bid in self.lastCount:
  276
+            if self.lastCount[bid] != count:
  277
+                validate(view)
  278
+
  279
+        self.lastCount[bid] = count
  280
+
  281
+    def on_load(self, view):
  282
+        validate_hit(view)
  283
+
  284
+    def on_post_save(self, view):
  285
+        validate_hit(view)
  286
+
  287
+    def on_selection_modified(self, view):
  288
+        vid = view.id()
  289
+        lineno = view.rowcol(view.sel()[0].end())[0]
  290
+        if vid in lineMessages and lineno in lineMessages[vid]:
  291
+            view.set_status('pyflakes', '; '.join(lineMessages[vid][lineno]))
  292
+        else:
  293
+            view.erase_status('pyflakes')

0 notes on commit f1f8114

Please sign in to comment.
Something went wrong with that request. Please try again.