PageRenderTime 50ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/pymode/libs/pylint/checkers/python3.py

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