gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / pylint / checkers / python3.py @ 745
History | View | Annotate | Download (24.9 KB)
1 |
# Copyright 2014 Google Inc.
|
---|---|
2 |
# This program is free software; you can redistribute it and/or modify it under
|
3 |
# the terms of the GNU General Public License as published by the Free Software
|
4 |
# Foundation; either version 2 of the License, or (at your option) any later
|
5 |
# version.
|
6 |
#
|
7 |
# This program is distributed in the hope that it will be useful, but WITHOUT
|
8 |
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
9 |
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
10 |
#
|
11 |
# You should have received a copy of the GNU General Public License along with
|
12 |
# this program; if not, write to the Free Software Foundation, Inc.,
|
13 |
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
14 |
"""Check Python 2 code for Python 2/3 source-compatible issues."""
|
15 |
from __future__ import absolute_import, print_function |
16 |
|
17 |
import re |
18 |
import tokenize |
19 |
|
20 |
import astroid |
21 |
from astroid import bases |
22 |
|
23 |
from pylint import checkers, interfaces |
24 |
from pylint.utils import WarningScope |
25 |
from pylint.checkers import utils |
26 |
|
27 |
|
28 |
_ZERO = re.compile("^0+$")
|
29 |
|
30 |
def _is_old_octal(literal): |
31 |
if _ZERO.match(literal):
|
32 |
return False |
33 |
if re.match('0\d+', literal): |
34 |
try:
|
35 |
int(literal, 8) |
36 |
except ValueError: |
37 |
return False |
38 |
return True |
39 |
|
40 |
def _check_dict_node(node): |
41 |
inferred_types = set()
|
42 |
try:
|
43 |
inferred = node.infer() |
44 |
for inferred_node in inferred: |
45 |
inferred_types.add(inferred_node) |
46 |
except (astroid.InferenceError, astroid.UnresolvableName):
|
47 |
pass
|
48 |
return (not inferred_types |
49 |
or any(isinstance(x, astroid.Dict) for x in inferred_types)) |
50 |
|
51 |
def _is_builtin(node): |
52 |
return getattr(node, 'name', None) in ('__builtin__', 'builtins') |
53 |
|
54 |
_ACCEPTS_ITERATOR = {'iter', 'list', 'tuple', 'sorted', 'set', 'sum', 'any', |
55 |
'all', 'enumerate', 'dict'} |
56 |
|
57 |
def _in_iterating_context(node): |
58 |
"""Check if the node is being used as an iterator.
|
59 |
|
60 |
Definition is taken from lib2to3.fixer_util.in_special_context().
|
61 |
"""
|
62 |
parent = node.parent |
63 |
# Since a call can't be the loop variant we only need to know if the node's
|
64 |
# parent is a 'for' loop to know it's being used as the iterator for the
|
65 |
# loop.
|
66 |
if isinstance(parent, astroid.For): |
67 |
return True |
68 |
# Need to make sure the use of the node is in the iterator part of the
|
69 |
# comprehension.
|
70 |
elif isinstance(parent, astroid.Comprehension): |
71 |
if parent.iter == node:
|
72 |
return True |
73 |
# Various built-ins can take in an iterable or list and lead to the same
|
74 |
# value.
|
75 |
elif isinstance(parent, astroid.Call): |
76 |
if isinstance(parent.func, astroid.Name): |
77 |
parent_scope = parent.func.lookup(parent.func.name)[0]
|
78 |
if _is_builtin(parent_scope) and parent.func.name in _ACCEPTS_ITERATOR: |
79 |
return True |
80 |
elif isinstance(parent.func, astroid.Attribute): |
81 |
if parent.func.attrname == 'join': |
82 |
return True |
83 |
# If the call is in an unpacking, there's no need to warn,
|
84 |
# since it can be considered iterating.
|
85 |
elif (isinstance(parent, astroid.Assign) and |
86 |
isinstance(parent.targets[0], (astroid.List, astroid.Tuple))): |
87 |
if len(parent.targets[0].elts) > 1: |
88 |
return True |
89 |
return False |
90 |
|
91 |
|
92 |
class Python3Checker(checkers.BaseChecker): |
93 |
|
94 |
__implements__ = interfaces.IAstroidChecker |
95 |
enabled = False
|
96 |
name = 'python3'
|
97 |
|
98 |
msgs = { |
99 |
# Errors for what will syntactically break in Python 3, warnings for
|
100 |
# everything else.
|
101 |
'E1601': ('print statement used', |
102 |
'print-statement',
|
103 |
'Used when a print statement is used '
|
104 |
'(`print` is a function in Python 3)',
|
105 |
{'maxversion': (3, 0)}), |
106 |
'E1602': ('Parameter unpacking specified', |
107 |
'parameter-unpacking',
|
108 |
'Used when parameter unpacking is specified for a function'
|
109 |
"(Python 3 doesn't allow it)",
|
110 |
{'maxversion': (3, 0)}), |
111 |
'E1603': ('Implicit unpacking of exceptions is not supported ' |
112 |
'in Python 3',
|
113 |
'unpacking-in-except',
|
114 |
'Python3 will not allow implicit unpacking of '
|
115 |
'exceptions in except clauses. '
|
116 |
'See http://www.python.org/dev/peps/pep-3110/',
|
117 |
{'maxversion': (3, 0), |
118 |
'old_names': [('W0712', 'unpacking-in-except')]}), |
119 |
'E1604': ('Use raise ErrorClass(args) instead of ' |
120 |
'raise ErrorClass, args.',
|
121 |
'old-raise-syntax',
|
122 |
"Used when the alternate raise syntax "
|
123 |
"'raise foo, bar' is used "
|
124 |
"instead of 'raise foo(bar)'.",
|
125 |
{'maxversion': (3, 0), |
126 |
'old_names': [('W0121', 'old-raise-syntax')]}), |
127 |
'E1605': ('Use of the `` operator', |
128 |
'backtick',
|
129 |
'Used when the deprecated "``" (backtick) operator is used '
|
130 |
'instead of the str() function.',
|
131 |
{'scope': WarningScope.NODE,
|
132 |
'maxversion': (3, 0), |
133 |
'old_names': [('W0333', 'backtick')]}), |
134 |
'E1609': ('Import * only allowed at module level', |
135 |
'import-star-module-level',
|
136 |
'Used when the import star syntax is used somewhere '
|
137 |
'else than the module level.',
|
138 |
{'maxversion': (3, 0)}), |
139 |
'W1601': ('apply built-in referenced', |
140 |
'apply-builtin',
|
141 |
'Used when the apply built-in function is referenced '
|
142 |
'(missing from Python 3)',
|
143 |
{'maxversion': (3, 0)}), |
144 |
'W1602': ('basestring built-in referenced', |
145 |
'basestring-builtin',
|
146 |
'Used when the basestring built-in function is referenced '
|
147 |
'(missing from Python 3)',
|
148 |
{'maxversion': (3, 0)}), |
149 |
'W1603': ('buffer built-in referenced', |
150 |
'buffer-builtin',
|
151 |
'Used when the buffer built-in function is referenced '
|
152 |
'(missing from Python 3)',
|
153 |
{'maxversion': (3, 0)}), |
154 |
'W1604': ('cmp built-in referenced', |
155 |
'cmp-builtin',
|
156 |
'Used when the cmp built-in function is referenced '
|
157 |
'(missing from Python 3)',
|
158 |
{'maxversion': (3, 0)}), |
159 |
'W1605': ('coerce built-in referenced', |
160 |
'coerce-builtin',
|
161 |
'Used when the coerce built-in function is referenced '
|
162 |
'(missing from Python 3)',
|
163 |
{'maxversion': (3, 0)}), |
164 |
'W1606': ('execfile built-in referenced', |
165 |
'execfile-builtin',
|
166 |
'Used when the execfile built-in function is referenced '
|
167 |
'(missing from Python 3)',
|
168 |
{'maxversion': (3, 0)}), |
169 |
'W1607': ('file built-in referenced', |
170 |
'file-builtin',
|
171 |
'Used when the file built-in function is referenced '
|
172 |
'(missing from Python 3)',
|
173 |
{'maxversion': (3, 0)}), |
174 |
'W1608': ('long built-in referenced', |
175 |
'long-builtin',
|
176 |
'Used when the long built-in function is referenced '
|
177 |
'(missing from Python 3)',
|
178 |
{'maxversion': (3, 0)}), |
179 |
'W1609': ('raw_input built-in referenced', |
180 |
'raw_input-builtin',
|
181 |
'Used when the raw_input built-in function is referenced '
|
182 |
'(missing from Python 3)',
|
183 |
{'maxversion': (3, 0)}), |
184 |
'W1610': ('reduce built-in referenced', |
185 |
'reduce-builtin',
|
186 |
'Used when the reduce built-in function is referenced '
|
187 |
'(missing from Python 3)',
|
188 |
{'maxversion': (3, 0)}), |
189 |
'W1611': ('StandardError built-in referenced', |
190 |
'standarderror-builtin',
|
191 |
'Used when the StandardError built-in function is referenced '
|
192 |
'(missing from Python 3)',
|
193 |
{'maxversion': (3, 0)}), |
194 |
'W1612': ('unicode built-in referenced', |
195 |
'unicode-builtin',
|
196 |
'Used when the unicode built-in function is referenced '
|
197 |
'(missing from Python 3)',
|
198 |
{'maxversion': (3, 0)}), |
199 |
'W1613': ('xrange built-in referenced', |
200 |
'xrange-builtin',
|
201 |
'Used when the xrange built-in function is referenced '
|
202 |
'(missing from Python 3)',
|
203 |
{'maxversion': (3, 0)}), |
204 |
'W1614': ('__coerce__ method defined', |
205 |
'coerce-method',
|
206 |
'Used when a __coerce__ method is defined '
|
207 |
'(method is not used by Python 3)',
|
208 |
{'maxversion': (3, 0)}), |
209 |
'W1615': ('__delslice__ method defined', |
210 |
'delslice-method',
|
211 |
'Used when a __delslice__ method is defined '
|
212 |
'(method is not used by Python 3)',
|
213 |
{'maxversion': (3, 0)}), |
214 |
'W1616': ('__getslice__ method defined', |
215 |
'getslice-method',
|
216 |
'Used when a __getslice__ method is defined '
|
217 |
'(method is not used by Python 3)',
|
218 |
{'maxversion': (3, 0)}), |
219 |
'W1617': ('__setslice__ method defined', |
220 |
'setslice-method',
|
221 |
'Used when a __setslice__ method is defined '
|
222 |
'(method is not used by Python 3)',
|
223 |
{'maxversion': (3, 0)}), |
224 |
'W1618': ('import missing `from __future__ import absolute_import`', |
225 |
'no-absolute-import',
|
226 |
'Used when an import is not accompanied by '
|
227 |
'``from __future__ import absolute_import`` '
|
228 |
'(default behaviour in Python 3)',
|
229 |
{'maxversion': (3, 0)}), |
230 |
'W1619': ('division w/o __future__ statement', |
231 |
'old-division',
|
232 |
'Used for non-floor division w/o a float literal or '
|
233 |
'``from __future__ import division`` '
|
234 |
'(Python 3 returns a float for int division unconditionally)',
|
235 |
{'maxversion': (3, 0)}), |
236 |
'W1620': ('Calling a dict.iter*() method', |
237 |
'dict-iter-method',
|
238 |
'Used for calls to dict.iterkeys(), itervalues() or iteritems() '
|
239 |
'(Python 3 lacks these methods)',
|
240 |
{'maxversion': (3, 0)}), |
241 |
'W1621': ('Calling a dict.view*() method', |
242 |
'dict-view-method',
|
243 |
'Used for calls to dict.viewkeys(), viewvalues() or viewitems() '
|
244 |
'(Python 3 lacks these methods)',
|
245 |
{'maxversion': (3, 0)}), |
246 |
'W1622': ('Called a next() method on an object', |
247 |
'next-method-called',
|
248 |
"Used when an object's next() method is called "
|
249 |
'(Python 3 uses the next() built-in function)',
|
250 |
{'maxversion': (3, 0)}), |
251 |
'W1623': ("Assigning to a class's __metaclass__ attribute", |
252 |
'metaclass-assignment',
|
253 |
"Used when a metaclass is specified by assigning to __metaclass__ "
|
254 |
'(Python 3 specifies the metaclass as a class statement argument)',
|
255 |
{'maxversion': (3, 0)}), |
256 |
'W1624': ('Indexing exceptions will not work on Python 3', |
257 |
'indexing-exception',
|
258 |
'Indexing exceptions will not work on Python 3. Use '
|
259 |
'`exception.args[index]` instead.',
|
260 |
{'maxversion': (3, 0), |
261 |
'old_names': [('W0713', 'indexing-exception')]}), |
262 |
'W1625': ('Raising a string exception', |
263 |
'raising-string',
|
264 |
'Used when a string exception is raised. This will not '
|
265 |
'work on Python 3.',
|
266 |
{'maxversion': (3, 0), |
267 |
'old_names': [('W0701', 'raising-string')]}), |
268 |
'W1626': ('reload built-in referenced', |
269 |
'reload-builtin',
|
270 |
'Used when the reload built-in function is referenced '
|
271 |
'(missing from Python 3). You can use instead imp.reload '
|
272 |
'or importlib.reload.',
|
273 |
{'maxversion': (3, 0)}), |
274 |
'W1627': ('__oct__ method defined', |
275 |
'oct-method',
|
276 |
'Used when a __oct__ method is defined '
|
277 |
'(method is not used by Python 3)',
|
278 |
{'maxversion': (3, 0)}), |
279 |
'W1628': ('__hex__ method defined', |
280 |
'hex-method',
|
281 |
'Used when a __hex__ method is defined '
|
282 |
'(method is not used by Python 3)',
|
283 |
{'maxversion': (3, 0)}), |
284 |
'W1629': ('__nonzero__ method defined', |
285 |
'nonzero-method',
|
286 |
'Used when a __nonzero__ method is defined '
|
287 |
'(method is not used by Python 3)',
|
288 |
{'maxversion': (3, 0)}), |
289 |
'W1630': ('__cmp__ method defined', |
290 |
'cmp-method',
|
291 |
'Used when a __cmp__ method is defined '
|
292 |
'(method is not used by Python 3)',
|
293 |
{'maxversion': (3, 0)}), |
294 |
# 'W1631': replaced by W1636
|
295 |
'W1632': ('input built-in referenced', |
296 |
'input-builtin',
|
297 |
'Used when the input built-in is referenced '
|
298 |
'(backwards-incompatible semantics in Python 3)',
|
299 |
{'maxversion': (3, 0)}), |
300 |
'W1633': ('round built-in referenced', |
301 |
'round-builtin',
|
302 |
'Used when the round built-in is referenced '
|
303 |
'(backwards-incompatible semantics in Python 3)',
|
304 |
{'maxversion': (3, 0)}), |
305 |
'W1634': ('intern built-in referenced', |
306 |
'intern-builtin',
|
307 |
'Used when the intern built-in is referenced '
|
308 |
'(Moved to sys.intern in Python 3)',
|
309 |
{'maxversion': (3, 0)}), |
310 |
'W1635': ('unichr built-in referenced', |
311 |
'unichr-builtin',
|
312 |
'Used when the unichr built-in is referenced '
|
313 |
'(Use chr in Python 3)',
|
314 |
{'maxversion': (3, 0)}), |
315 |
'W1636': ('map built-in referenced when not iterating', |
316 |
'map-builtin-not-iterating',
|
317 |
'Used when the map built-in is referenced in a non-iterating '
|
318 |
'context (returns an iterator in Python 3)',
|
319 |
{'maxversion': (3, 0), |
320 |
'old_names': [('W1631', 'implicit-map-evaluation')]}), |
321 |
'W1637': ('zip built-in referenced when not iterating', |
322 |
'zip-builtin-not-iterating',
|
323 |
'Used when the zip built-in is referenced in a non-iterating '
|
324 |
'context (returns an iterator in Python 3)',
|
325 |
{'maxversion': (3, 0)}), |
326 |
'W1638': ('range built-in referenced when not iterating', |
327 |
'range-builtin-not-iterating',
|
328 |
'Used when the range built-in is referenced in a non-iterating '
|
329 |
'context (returns an iterator in Python 3)',
|
330 |
{'maxversion': (3, 0)}), |
331 |
'W1639': ('filter built-in referenced when not iterating', |
332 |
'filter-builtin-not-iterating',
|
333 |
'Used when the filter built-in is referenced in a non-iterating '
|
334 |
'context (returns an iterator in Python 3)',
|
335 |
{'maxversion': (3, 0)}), |
336 |
'W1640': ('Using the cmp argument for list.sort / sorted', |
337 |
'using-cmp-argument',
|
338 |
'Using the cmp argument for list.sort or the sorted '
|
339 |
'builtin should be avoided, since it was removed in '
|
340 |
'Python 3. Using either `key` or `functools.cmp_to_key` '
|
341 |
'should be preferred.',
|
342 |
{'maxversion': (3, 0)}), |
343 |
} |
344 |
|
345 |
_bad_builtins = frozenset([
|
346 |
'apply',
|
347 |
'basestring',
|
348 |
'buffer',
|
349 |
'cmp',
|
350 |
'coerce',
|
351 |
'execfile',
|
352 |
'file',
|
353 |
'input', # Not missing, but incompatible semantics |
354 |
'intern',
|
355 |
'long',
|
356 |
'raw_input',
|
357 |
'reduce',
|
358 |
'round', # Not missing, but incompatible semantics |
359 |
'StandardError',
|
360 |
'unichr',
|
361 |
'unicode',
|
362 |
'xrange',
|
363 |
'reload',
|
364 |
]) |
365 |
|
366 |
_unused_magic_methods = frozenset([
|
367 |
'__coerce__',
|
368 |
'__delslice__',
|
369 |
'__getslice__',
|
370 |
'__setslice__',
|
371 |
'__oct__',
|
372 |
'__hex__',
|
373 |
'__nonzero__',
|
374 |
'__cmp__',
|
375 |
]) |
376 |
|
377 |
def __init__(self, *args, **kwargs): |
378 |
self._future_division = False |
379 |
self._future_absolute_import = False |
380 |
super(Python3Checker, self).__init__(*args, **kwargs) |
381 |
|
382 |
def visit_module(self, node): # pylint: disable=unused-argument |
383 |
"""Clear checker state after previous module."""
|
384 |
self._future_division = False |
385 |
self._future_absolute_import = False |
386 |
|
387 |
def visit_functiondef(self, node): |
388 |
if node.is_method() and node.name in self._unused_magic_methods: |
389 |
method_name = node.name |
390 |
if node.name.startswith('__'): |
391 |
method_name = node.name[2:-2] |
392 |
self.add_message(method_name + '-method', node=node) |
393 |
|
394 |
@utils.check_messages('parameter-unpacking') |
395 |
def visit_arguments(self, node): |
396 |
for arg in node.args: |
397 |
if isinstance(arg, astroid.Tuple): |
398 |
self.add_message('parameter-unpacking', node=arg) |
399 |
|
400 |
def visit_name(self, node): |
401 |
"""Detect when a "bad" built-in is referenced."""
|
402 |
found_node = node.lookup(node.name)[0]
|
403 |
if _is_builtin(found_node):
|
404 |
if node.name in self._bad_builtins: |
405 |
message = node.name.lower() + '-builtin'
|
406 |
self.add_message(message, node=node)
|
407 |
|
408 |
@utils.check_messages('print-statement') |
409 |
def visit_print(self, node): |
410 |
self.add_message('print-statement', node=node) |
411 |
|
412 |
@utils.check_messages('no-absolute-import', 'import-star-module-level') |
413 |
def visit_importfrom(self, node): |
414 |
if node.modname == '__future__': |
415 |
for name, _ in node.names: |
416 |
if name == 'division': |
417 |
self._future_division = True |
418 |
elif name == 'absolute_import': |
419 |
self._future_absolute_import = True |
420 |
elif not self._future_absolute_import: |
421 |
self.add_message('no-absolute-import', node=node) |
422 |
if node.names[0][0] == '*': |
423 |
if not isinstance(node.scope(), astroid.Module): |
424 |
self.add_message('import-star-module-level', node=node) |
425 |
|
426 |
@utils.check_messages('no-absolute-import') |
427 |
def visit_import(self, node): |
428 |
if not self._future_absolute_import: |
429 |
self.add_message('no-absolute-import', node=node) |
430 |
|
431 |
@utils.check_messages('metaclass-assignment') |
432 |
def visit_classdef(self, node): |
433 |
if '__metaclass__' in node.locals: |
434 |
self.add_message('metaclass-assignment', node=node) |
435 |
|
436 |
@utils.check_messages('old-division') |
437 |
def visit_binop(self, node): |
438 |
if not self._future_division and node.op == '/': |
439 |
for arg in (node.left, node.right): |
440 |
if isinstance(arg, astroid.Const) and isinstance(arg.value, float): |
441 |
break
|
442 |
else:
|
443 |
self.add_message('old-division', node=node) |
444 |
|
445 |
def _check_cmp_argument(self, node): |
446 |
# Check that the `cmp` argument is used
|
447 |
kwargs = [] |
448 |
if (isinstance(node.func, astroid.Attribute) |
449 |
and node.func.attrname == 'sort'): |
450 |
inferred = utils.safe_infer(node.func.expr) |
451 |
if not inferred: |
452 |
return
|
453 |
|
454 |
builtins_list = "{}.list".format(bases.BUILTINS)
|
455 |
if (isinstance(inferred, astroid.List) |
456 |
or inferred.qname() == builtins_list):
|
457 |
kwargs = node.keywords |
458 |
|
459 |
elif (isinstance(node.func, astroid.Name) |
460 |
and node.func.name == 'sorted'): |
461 |
inferred = utils.safe_infer(node.func) |
462 |
if not inferred: |
463 |
return
|
464 |
|
465 |
builtins_sorted = "{}.sorted".format(bases.BUILTINS)
|
466 |
if inferred.qname() == builtins_sorted:
|
467 |
kwargs = node.keywords |
468 |
|
469 |
for kwarg in kwargs or []: |
470 |
if kwarg.arg == 'cmp': |
471 |
self.add_message('using-cmp-argument', node=node) |
472 |
return
|
473 |
|
474 |
def visit_call(self, node): |
475 |
self._check_cmp_argument(node)
|
476 |
|
477 |
if isinstance(node.func, astroid.Attribute): |
478 |
if any([node.args, node.keywords]): |
479 |
return
|
480 |
if node.func.attrname == 'next': |
481 |
self.add_message('next-method-called', node=node) |
482 |
else:
|
483 |
if _check_dict_node(node.func.expr):
|
484 |
if node.func.attrname in ('iterkeys', 'itervalues', 'iteritems'): |
485 |
self.add_message('dict-iter-method', node=node) |
486 |
elif node.func.attrname in ('viewkeys', 'viewvalues', 'viewitems'): |
487 |
self.add_message('dict-view-method', node=node) |
488 |
elif isinstance(node.func, astroid.Name): |
489 |
found_node = node.func.lookup(node.func.name)[0]
|
490 |
if _is_builtin(found_node):
|
491 |
if node.func.name in ('filter', 'map', 'range', 'zip'): |
492 |
if not _in_iterating_context(node): |
493 |
checker = '{}-builtin-not-iterating'.format(node.func.name)
|
494 |
self.add_message(checker, node=node)
|
495 |
|
496 |
|
497 |
@utils.check_messages('indexing-exception') |
498 |
def visit_subscript(self, node): |
499 |
""" Look for indexing exceptions. """
|
500 |
try:
|
501 |
for infered in node.value.infer(): |
502 |
if not isinstance(infered, astroid.Instance): |
503 |
continue
|
504 |
if utils.inherit_from_std_ex(infered):
|
505 |
self.add_message('indexing-exception', node=node) |
506 |
except astroid.InferenceError:
|
507 |
return
|
508 |
|
509 |
@utils.check_messages('unpacking-in-except') |
510 |
def visit_excepthandler(self, node): |
511 |
"""Visit an except handler block and check for exception unpacking."""
|
512 |
if isinstance(node.name, (astroid.Tuple, astroid.List)): |
513 |
self.add_message('unpacking-in-except', node=node) |
514 |
|
515 |
@utils.check_messages('backtick') |
516 |
def visit_repr(self, node): |
517 |
self.add_message('backtick', node=node) |
518 |
|
519 |
@utils.check_messages('raising-string', 'old-raise-syntax') |
520 |
def visit_raise(self, node): |
521 |
"""Visit a raise statement and check for raising
|
522 |
strings or old-raise-syntax.
|
523 |
"""
|
524 |
if (node.exc is not None and |
525 |
node.inst is not None and |
526 |
node.tback is None): |
527 |
self.add_message('old-raise-syntax', node=node) |
528 |
|
529 |
# Ignore empty raise.
|
530 |
if node.exc is None: |
531 |
return
|
532 |
expr = node.exc |
533 |
if self._check_raise_value(node, expr): |
534 |
return
|
535 |
else:
|
536 |
try:
|
537 |
value = next(astroid.unpack_infer(expr))
|
538 |
except astroid.InferenceError:
|
539 |
return
|
540 |
self._check_raise_value(node, value)
|
541 |
|
542 |
def _check_raise_value(self, node, expr): |
543 |
if isinstance(expr, astroid.Const): |
544 |
value = expr.value |
545 |
if isinstance(value, str): |
546 |
self.add_message('raising-string', node=node) |
547 |
return True |
548 |
|
549 |
|
550 |
class Python3TokenChecker(checkers.BaseTokenChecker): |
551 |
__implements__ = interfaces.ITokenChecker |
552 |
name = 'python3'
|
553 |
enabled = False
|
554 |
|
555 |
msgs = { |
556 |
'E1606': ('Use of long suffix', |
557 |
'long-suffix',
|
558 |
'Used when "l" or "L" is used to mark a long integer. '
|
559 |
'This will not work in Python 3, since `int` and `long` '
|
560 |
'types have merged.',
|
561 |
{'maxversion': (3, 0)}), |
562 |
'E1607': ('Use of the <> operator', |
563 |
'old-ne-operator',
|
564 |
'Used when the deprecated "<>" operator is used instead '
|
565 |
'of "!=". This is removed in Python 3.',
|
566 |
{'maxversion': (3, 0), |
567 |
'old_names': [('W0331', 'old-ne-operator')]}), |
568 |
'E1608': ('Use of old octal literal', |
569 |
'old-octal-literal',
|
570 |
'Usen when encountering the old octal syntax, '
|
571 |
'removed in Python 3. To use the new syntax, '
|
572 |
'prepend 0o on the number.',
|
573 |
{'maxversion': (3, 0)}), |
574 |
} |
575 |
|
576 |
def process_tokens(self, tokens): |
577 |
for idx, (tok_type, token, start, _, _) in enumerate(tokens): |
578 |
if tok_type == tokenize.NUMBER:
|
579 |
if token.lower().endswith('l'): |
580 |
# This has a different semantic than lowercase-l-suffix.
|
581 |
self.add_message('long-suffix', line=start[0]) |
582 |
elif _is_old_octal(token):
|
583 |
self.add_message('old-octal-literal', line=start[0]) |
584 |
if tokens[idx][1] == '<>': |
585 |
self.add_message('old-ne-operator', line=tokens[idx][2][0]) |
586 |
|
587 |
|
588 |
def register(linter): |
589 |
linter.register_checker(Python3Checker(linter)) |
590 |
linter.register_checker(Python3TokenChecker(linter)) |