Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

python3.py 47KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2014-2018 Claudiu Popa <pcmanticore@gmail.com>
  3. # Copyright (c) 2014-2015 Brett Cannon <brett@python.org>
  4. # Copyright (c) 2015 Simu Toni <simutoni@gmail.com>
  5. # Copyright (c) 2015 Pavel Roskin <proski@gnu.org>
  6. # Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
  7. # Copyright (c) 2015 Cosmin Poieana <cmin@ropython.org>
  8. # Copyright (c) 2015 Viorel Stirbu <viorels@gmail.com>
  9. # Copyright (c) 2016-2017 Roy Williams <roy.williams.iii@gmail.com>
  10. # Copyright (c) 2016 Roy Williams <rwilliams@lyft.com>
  11. # Copyright (c) 2016 Łukasz Rogalski <rogalski.91@gmail.com>
  12. # Copyright (c) 2016 Erik <erik.eriksson@yahoo.com>
  13. # Copyright (c) 2016 Jakub Wilk <jwilk@jwilk.net>
  14. # Copyright (c) 2017 Daniel Miller <millerdev@gmail.com>
  15. # Copyright (c) 2017 hippo91 <guillaume.peillex@gmail.com>
  16. # Copyright (c) 2017 ahirnish <ahirnish@gmail.com>
  17. # Copyright (c) 2017 Ville Skyttä <ville.skytta@iki.fi>
  18. # Copyright (c) 2018 Sushobhit <31987769+sushobhit27@users.noreply.github.com>
  19. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. # For details: https://github.com/PyCQA/pylint/blob/master/COPYING
  21. """Check Python 2 code for Python 2/3 source-compatible issues."""
  22. from __future__ import absolute_import, print_function
  23. from collections import namedtuple
  24. import re
  25. import sys
  26. import tokenize
  27. import astroid
  28. from astroid import bases
  29. import six
  30. from pylint import checkers, interfaces
  31. from pylint.interfaces import INFERENCE_FAILURE, INFERENCE
  32. from pylint.utils import WarningScope
  33. from pylint.checkers import utils
  34. _ZERO = re.compile("^0+$")
  35. def _is_old_octal(literal):
  36. if _ZERO.match(literal):
  37. return False
  38. if re.match(r'0\d+', literal):
  39. try:
  40. int(literal, 8)
  41. except ValueError:
  42. return False
  43. return True
  44. return None
  45. def _inferred_value_is_dict(value):
  46. if isinstance(value, astroid.Dict):
  47. return True
  48. return isinstance(value, astroid.Instance) and 'dict' in value.basenames
  49. def _check_dict_node(node):
  50. inferred_types = set()
  51. try:
  52. inferred = node.infer()
  53. if inferred is not astroid.Uninferable:
  54. for inferred_node in inferred:
  55. inferred_types.add(inferred_node)
  56. except astroid.InferenceError:
  57. pass
  58. if not inferred_types:
  59. return True
  60. return any(_inferred_value_is_dict(value) for value in inferred_types)
  61. def _is_builtin(node):
  62. return getattr(node, 'name', None) in ('__builtin__', 'builtins')
  63. _ACCEPTS_ITERATOR = {'iter', 'list', 'tuple', 'sorted', 'set', 'sum', 'any',
  64. 'all', 'enumerate', 'dict', 'filter', 'reversed'}
  65. DICT_METHODS = {'items', 'keys', 'values'}
  66. def _in_iterating_context(node):
  67. """Check if the node is being used as an iterator.
  68. Definition is taken from lib2to3.fixer_util.in_special_context().
  69. """
  70. parent = node.parent
  71. # Since a call can't be the loop variant we only need to know if the node's
  72. # parent is a 'for' loop to know it's being used as the iterator for the
  73. # loop.
  74. if isinstance(parent, astroid.For):
  75. return True
  76. # Need to make sure the use of the node is in the iterator part of the
  77. # comprehension.
  78. if isinstance(parent, astroid.Comprehension):
  79. if parent.iter == node:
  80. return True
  81. # Various built-ins can take in an iterable or list and lead to the same
  82. # value.
  83. elif isinstance(parent, astroid.Call):
  84. if isinstance(parent.func, astroid.Name):
  85. parent_scope = parent.func.lookup(parent.func.name)[0]
  86. if _is_builtin(parent_scope) and parent.func.name in _ACCEPTS_ITERATOR:
  87. return True
  88. elif isinstance(parent.func, astroid.Attribute):
  89. if parent.func.attrname == 'join':
  90. return True
  91. # If the call is in an unpacking, there's no need to warn,
  92. # since it can be considered iterating.
  93. elif (isinstance(parent, astroid.Assign) and
  94. isinstance(parent.targets[0], (astroid.List, astroid.Tuple))):
  95. if len(parent.targets[0].elts) > 1:
  96. return True
  97. return False
  98. def _is_conditional_import(node):
  99. """Checks if an import node is in the context of a conditional.
  100. """
  101. parent = node.parent
  102. return isinstance(parent, (astroid.TryExcept, astroid.ExceptHandler,
  103. astroid.If, astroid.IfExp))
  104. Branch = namedtuple('Branch', ['node', 'is_py2_only'])
  105. class Python3Checker(checkers.BaseChecker):
  106. __implements__ = interfaces.IAstroidChecker
  107. enabled = False
  108. name = 'python3'
  109. msgs = {
  110. # Errors for what will syntactically break in Python 3, warnings for
  111. # everything else.
  112. 'E1601': ('print statement used',
  113. 'print-statement',
  114. 'Used when a print statement is used '
  115. '(`print` is a function in Python 3)'),
  116. 'E1602': ('Parameter unpacking specified',
  117. 'parameter-unpacking',
  118. 'Used when parameter unpacking is specified for a function'
  119. "(Python 3 doesn't allow it)"),
  120. 'E1603': ('Implicit unpacking of exceptions is not supported '
  121. 'in Python 3',
  122. 'unpacking-in-except',
  123. 'Python3 will not allow implicit unpacking of '
  124. 'exceptions in except clauses. '
  125. 'See http://www.python.org/dev/peps/pep-3110/',
  126. {'old_names': [('W0712', 'unpacking-in-except')]}),
  127. 'E1604': ('Use raise ErrorClass(args) instead of '
  128. 'raise ErrorClass, args.',
  129. 'old-raise-syntax',
  130. "Used when the alternate raise syntax "
  131. "'raise foo, bar' is used "
  132. "instead of 'raise foo(bar)'.",
  133. {'old_names': [('W0121', 'old-raise-syntax')]}),
  134. 'E1605': ('Use of the `` operator',
  135. 'backtick',
  136. 'Used when the deprecated "``" (backtick) operator is used '
  137. 'instead of the str() function.',
  138. {'scope': WarningScope.NODE,
  139. 'old_names': [('W0333', 'backtick')]}),
  140. 'E1609': ('Import * only allowed at module level',
  141. 'import-star-module-level',
  142. 'Used when the import star syntax is used somewhere '
  143. 'else than the module level.',
  144. {'maxversion': (3, 0)}),
  145. 'W1601': ('apply built-in referenced',
  146. 'apply-builtin',
  147. 'Used when the apply built-in function is referenced '
  148. '(missing from Python 3)'),
  149. 'W1602': ('basestring built-in referenced',
  150. 'basestring-builtin',
  151. 'Used when the basestring built-in function is referenced '
  152. '(missing from Python 3)'),
  153. 'W1603': ('buffer built-in referenced',
  154. 'buffer-builtin',
  155. 'Used when the buffer built-in function is referenced '
  156. '(missing from Python 3)'),
  157. 'W1604': ('cmp built-in referenced',
  158. 'cmp-builtin',
  159. 'Used when the cmp built-in function is referenced '
  160. '(missing from Python 3)'),
  161. 'W1605': ('coerce built-in referenced',
  162. 'coerce-builtin',
  163. 'Used when the coerce built-in function is referenced '
  164. '(missing from Python 3)'),
  165. 'W1606': ('execfile built-in referenced',
  166. 'execfile-builtin',
  167. 'Used when the execfile built-in function is referenced '
  168. '(missing from Python 3)'),
  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. 'W1608': ('long built-in referenced',
  174. 'long-builtin',
  175. 'Used when the long built-in function is referenced '
  176. '(missing from Python 3)'),
  177. 'W1609': ('raw_input built-in referenced',
  178. 'raw_input-builtin',
  179. 'Used when the raw_input built-in function is referenced '
  180. '(missing from Python 3)'),
  181. 'W1610': ('reduce built-in referenced',
  182. 'reduce-builtin',
  183. 'Used when the reduce built-in function is referenced '
  184. '(missing from Python 3)'),
  185. 'W1611': ('StandardError built-in referenced',
  186. 'standarderror-builtin',
  187. 'Used when the StandardError built-in function is referenced '
  188. '(missing from Python 3)'),
  189. 'W1612': ('unicode built-in referenced',
  190. 'unicode-builtin',
  191. 'Used when the unicode built-in function is referenced '
  192. '(missing from Python 3)'),
  193. 'W1613': ('xrange built-in referenced',
  194. 'xrange-builtin',
  195. 'Used when the xrange built-in function is referenced '
  196. '(missing from Python 3)'),
  197. 'W1614': ('__coerce__ method defined',
  198. 'coerce-method',
  199. 'Used when a __coerce__ method is defined '
  200. '(method is not used by Python 3)'),
  201. 'W1615': ('__delslice__ method defined',
  202. 'delslice-method',
  203. 'Used when a __delslice__ method is defined '
  204. '(method is not used by Python 3)'),
  205. 'W1616': ('__getslice__ method defined',
  206. 'getslice-method',
  207. 'Used when a __getslice__ method is defined '
  208. '(method is not used by Python 3)'),
  209. 'W1617': ('__setslice__ method defined',
  210. 'setslice-method',
  211. 'Used when a __setslice__ method is defined '
  212. '(method is not used by Python 3)'),
  213. 'W1618': ('import missing `from __future__ import absolute_import`',
  214. 'no-absolute-import',
  215. 'Used when an import is not accompanied by '
  216. '``from __future__ import absolute_import`` '
  217. '(default behaviour in Python 3)'),
  218. 'W1619': ('division w/o __future__ statement',
  219. 'old-division',
  220. 'Used for non-floor division w/o a float literal or '
  221. '``from __future__ import division`` '
  222. '(Python 3 returns a float for int division unconditionally)'),
  223. 'W1620': ('Calling a dict.iter*() method',
  224. 'dict-iter-method',
  225. 'Used for calls to dict.iterkeys(), itervalues() or iteritems() '
  226. '(Python 3 lacks these methods)'),
  227. 'W1621': ('Calling a dict.view*() method',
  228. 'dict-view-method',
  229. 'Used for calls to dict.viewkeys(), viewvalues() or viewitems() '
  230. '(Python 3 lacks these methods)'),
  231. 'W1622': ('Called a next() method on an object',
  232. 'next-method-called',
  233. "Used when an object's next() method is called "
  234. '(Python 3 uses the next() built-in function)'),
  235. 'W1623': ("Assigning to a class's __metaclass__ attribute",
  236. 'metaclass-assignment',
  237. "Used when a metaclass is specified by assigning to __metaclass__ "
  238. '(Python 3 specifies the metaclass as a class statement argument)'),
  239. 'W1624': ('Indexing exceptions will not work on Python 3',
  240. 'indexing-exception',
  241. 'Indexing exceptions will not work on Python 3. Use '
  242. '`exception.args[index]` instead.',
  243. {'old_names': [('W0713', 'indexing-exception')]}),
  244. 'W1625': ('Raising a string exception',
  245. 'raising-string',
  246. 'Used when a string exception is raised. This will not '
  247. 'work on Python 3.',
  248. {'old_names': [('W0701', 'raising-string')]}),
  249. 'W1626': ('reload built-in referenced',
  250. 'reload-builtin',
  251. 'Used when the reload built-in function is referenced '
  252. '(missing from Python 3). You can use instead imp.reload '
  253. 'or importlib.reload.'),
  254. 'W1627': ('__oct__ method defined',
  255. 'oct-method',
  256. 'Used when an __oct__ method is defined '
  257. '(method is not used by Python 3)'),
  258. 'W1628': ('__hex__ method defined',
  259. 'hex-method',
  260. 'Used when a __hex__ method is defined '
  261. '(method is not used by Python 3)'),
  262. 'W1629': ('__nonzero__ method defined',
  263. 'nonzero-method',
  264. 'Used when a __nonzero__ method is defined '
  265. '(method is not used by Python 3)'),
  266. 'W1630': ('__cmp__ method defined',
  267. 'cmp-method',
  268. 'Used when a __cmp__ method is defined '
  269. '(method is not used by Python 3)'),
  270. # 'W1631': replaced by W1636
  271. 'W1632': ('input built-in referenced',
  272. 'input-builtin',
  273. 'Used when the input built-in is referenced '
  274. '(backwards-incompatible semantics in Python 3)'),
  275. 'W1633': ('round built-in referenced',
  276. 'round-builtin',
  277. 'Used when the round built-in is referenced '
  278. '(backwards-incompatible semantics in Python 3)'),
  279. 'W1634': ('intern built-in referenced',
  280. 'intern-builtin',
  281. 'Used when the intern built-in is referenced '
  282. '(Moved to sys.intern in Python 3)'),
  283. 'W1635': ('unichr built-in referenced',
  284. 'unichr-builtin',
  285. 'Used when the unichr built-in is referenced '
  286. '(Use chr in Python 3)'),
  287. 'W1636': ('map built-in referenced when not iterating',
  288. 'map-builtin-not-iterating',
  289. 'Used when the map built-in is referenced in a non-iterating '
  290. 'context (returns an iterator in Python 3)',
  291. {'old_names': [('W1631', 'implicit-map-evaluation')]}),
  292. 'W1637': ('zip built-in referenced when not iterating',
  293. 'zip-builtin-not-iterating',
  294. 'Used when the zip built-in is referenced in a non-iterating '
  295. 'context (returns an iterator in Python 3)'),
  296. 'W1638': ('range built-in referenced when not iterating',
  297. 'range-builtin-not-iterating',
  298. 'Used when the range built-in is referenced in a non-iterating '
  299. 'context (returns an iterator in Python 3)'),
  300. 'W1639': ('filter built-in referenced when not iterating',
  301. 'filter-builtin-not-iterating',
  302. 'Used when the filter built-in is referenced in a non-iterating '
  303. 'context (returns an iterator in Python 3)'),
  304. 'W1640': ('Using the cmp argument for list.sort / sorted',
  305. 'using-cmp-argument',
  306. 'Using the cmp argument for list.sort or the sorted '
  307. 'builtin should be avoided, since it was removed in '
  308. 'Python 3. Using either `key` or `functools.cmp_to_key` '
  309. 'should be preferred.'),
  310. 'W1641': ('Implementing __eq__ without also implementing __hash__',
  311. 'eq-without-hash',
  312. 'Used when a class implements __eq__ but not __hash__. In Python 2, objects '
  313. 'get object.__hash__ as the default implementation, in Python 3 objects get '
  314. 'None as their default __hash__ implementation if they also implement __eq__.'),
  315. 'W1642': ('__div__ method defined',
  316. 'div-method',
  317. 'Used when a __div__ method is defined. Using `__truediv__` and setting'
  318. '__div__ = __truediv__ should be preferred.'
  319. '(method is not used by Python 3)'),
  320. 'W1643': ('__idiv__ method defined',
  321. 'idiv-method',
  322. 'Used when an __idiv__ method is defined. Using `__itruediv__` and setting'
  323. '__idiv__ = __itruediv__ should be preferred.'
  324. '(method is not used by Python 3)'),
  325. 'W1644': ('__rdiv__ method defined',
  326. 'rdiv-method',
  327. 'Used when a __rdiv__ method is defined. Using `__rtruediv__` and setting'
  328. '__rdiv__ = __rtruediv__ should be preferred.'
  329. '(method is not used by Python 3)'),
  330. 'W1645': ('Exception.message removed in Python 3',
  331. 'exception-message-attribute',
  332. 'Used when the message attribute is accessed on an Exception. Use '
  333. 'str(exception) instead.'),
  334. 'W1646': ('non-text encoding used in str.decode',
  335. 'invalid-str-codec',
  336. 'Used when using str.encode or str.decode with a non-text encoding. Use '
  337. 'codecs module to handle arbitrary codecs.'),
  338. 'W1647': ('sys.maxint removed in Python 3',
  339. 'sys-max-int',
  340. 'Used when accessing sys.maxint. Use sys.maxsize instead.'),
  341. 'W1648': ('Module moved in Python 3',
  342. 'bad-python3-import',
  343. 'Used when importing a module that no longer exists in Python 3.'),
  344. 'W1649': ('Accessing a deprecated function on the string module',
  345. 'deprecated-string-function',
  346. 'Used when accessing a string function that has been deprecated in Python 3.'),
  347. 'W1650': ('Using str.translate with deprecated deletechars parameters',
  348. 'deprecated-str-translate-call',
  349. 'Used when using the deprecated deletechars parameters from str.translate. Use '
  350. 're.sub to remove the desired characters '),
  351. 'W1651': ('Accessing a deprecated function on the itertools module',
  352. 'deprecated-itertools-function',
  353. 'Used when accessing a function on itertools that has been removed in Python 3.'),
  354. 'W1652': ('Accessing a deprecated fields on the types module',
  355. 'deprecated-types-field',
  356. 'Used when accessing a field on types that has been removed in Python 3.'),
  357. 'W1653': ('next method defined',
  358. 'next-method-defined',
  359. 'Used when a next method is defined that would be an iterator in Python 2 but '
  360. 'is treated as a normal function in Python 3.',),
  361. 'W1654': ('dict.items referenced when not iterating',
  362. 'dict-items-not-iterating',
  363. 'Used when dict.items is referenced in a non-iterating '
  364. 'context (returns an iterator in Python 3)',),
  365. 'W1655': ('dict.keys referenced when not iterating',
  366. 'dict-keys-not-iterating',
  367. 'Used when dict.keys is referenced in a non-iterating '
  368. 'context (returns an iterator in Python 3)',),
  369. 'W1656': ('dict.values referenced when not iterating',
  370. 'dict-values-not-iterating',
  371. 'Used when dict.values is referenced in a non-iterating '
  372. 'context (returns an iterator in Python 3)',),
  373. 'W1657': ('Accessing a removed attribute on the operator module',
  374. 'deprecated-operator-function',
  375. 'Used when accessing a field on operator module that has been '
  376. 'removed in Python 3.',),
  377. 'W1658': ('Accessing a removed attribute on the urllib module',
  378. 'deprecated-urllib-function',
  379. 'Used when accessing a field on urllib module that has been '
  380. 'removed or moved in Python 3.',),
  381. 'W1659': ('Accessing a removed xreadlines attribute',
  382. 'xreadlines-attribute',
  383. 'Used when accessing the xreadlines() function on a file stream, '
  384. 'removed in Python 3.',),
  385. 'W1660': ('Accessing a removed attribute on the sys module',
  386. 'deprecated-sys-function',
  387. 'Used when accessing a field on sys module that has been '
  388. 'removed in Python 3.',),
  389. 'W1661': ('Using an exception object that was bound by an except handler',
  390. 'exception-escape',
  391. 'Emitted when using an exception, that was bound in an except '
  392. 'handler, outside of the except handler. On Python 3 these '
  393. 'exceptions will be deleted once they get out '
  394. 'of the except handler.'),
  395. 'W1662': ('Using a variable that was bound inside a comprehension',
  396. 'comprehension-escape',
  397. 'Emitted when using a variable, that was bound in a comprehension '
  398. 'handler, outside of the comprehension itself. On Python 3 these '
  399. 'variables will be deleted outside of the '
  400. 'comprehension.'),
  401. }
  402. _bad_builtins = frozenset([
  403. 'apply',
  404. 'basestring',
  405. 'buffer',
  406. 'cmp',
  407. 'coerce',
  408. 'execfile',
  409. 'file',
  410. 'input', # Not missing, but incompatible semantics
  411. 'intern',
  412. 'long',
  413. 'raw_input',
  414. 'reduce',
  415. 'round', # Not missing, but incompatible semantics
  416. 'StandardError',
  417. 'unichr',
  418. 'unicode',
  419. 'xrange',
  420. 'reload',
  421. ])
  422. _unused_magic_methods = frozenset([
  423. '__coerce__',
  424. '__delslice__',
  425. '__getslice__',
  426. '__setslice__',
  427. '__oct__',
  428. '__hex__',
  429. '__nonzero__',
  430. '__cmp__',
  431. '__div__',
  432. '__idiv__',
  433. '__rdiv__',
  434. ])
  435. _invalid_encodings = frozenset([
  436. 'base64_codec',
  437. 'base64',
  438. 'base_64',
  439. 'bz2_codec',
  440. 'bz2',
  441. 'hex_codec',
  442. 'hex',
  443. 'quopri_codec',
  444. 'quopri',
  445. 'quotedprintable',
  446. 'quoted_printable',
  447. 'uu_codec',
  448. 'uu',
  449. 'zlib_codec',
  450. 'zlib',
  451. 'zip',
  452. 'rot13',
  453. 'rot_13',
  454. ])
  455. _bad_python3_module_map = {
  456. 'sys-max-int': {
  457. 'sys': frozenset(['maxint'])
  458. },
  459. 'deprecated-itertools-function': {
  460. 'itertools': frozenset(['izip', 'ifilter', 'imap', 'izip_longest', 'ifilterfalse'])
  461. },
  462. 'deprecated-types-field': {
  463. 'types': frozenset([
  464. 'EllipsisType', 'XRangeType', 'ComplexType', 'StringType',
  465. 'TypeType', 'LongType', 'UnicodeType', 'ClassType',
  466. 'BufferType', 'StringTypes', 'NotImplementedType', 'NoneType',
  467. 'InstanceType', 'FloatType', 'SliceType', 'UnboundMethodType',
  468. 'ObjectType', 'IntType', 'TupleType', 'ListType', 'DictType',
  469. 'FileType', 'DictionaryType', 'BooleanType', 'DictProxyType'
  470. ])
  471. },
  472. 'bad-python3-import': frozenset([
  473. 'anydbm', 'BaseHTTPServer', '__builtin__', 'CGIHTTPServer', 'ConfigParser', 'copy_reg',
  474. 'cPickle', 'cStringIO', 'Cookie', 'cookielib', 'dbhash', 'dbm', 'dumbdbm',
  475. 'dumbdb', 'Dialog', 'DocXMLRPCServer', 'FileDialog', 'FixTk', 'gdbm', 'htmlentitydefs',
  476. 'HTMLParser', 'httplib', 'markupbase', 'Queue', 'repr', 'robotparser', 'ScrolledText',
  477. 'SimpleDialog', 'SimpleHTTPServer', 'SimpleXMLRPCServer', 'StringIO', 'dummy_thread',
  478. 'SocketServer', 'test.test_support', 'Tkinter', 'Tix', 'Tkconstants', 'tkColorChooser',
  479. 'tkCommonDialog', 'Tkdnd', 'tkFileDialog', 'tkFont', 'tkMessageBox', 'tkSimpleDialog',
  480. 'turtle', 'UserList', 'UserString', 'whichdb', '_winreg', 'xmlrpclib', 'audiodev',
  481. 'Bastion', 'bsddb185', 'bsddb3', 'Canvas', 'cfmfile', 'cl', 'commands', 'compiler',
  482. 'dircache', 'dl', 'exception', 'fpformat', 'htmllib', 'ihooks', 'imageop', 'imputil',
  483. 'linuxaudiodev', 'md5', 'mhlib', 'mimetools', 'MimeWriter', 'mimify', 'multifile',
  484. 'mutex', 'new', 'popen2', 'posixfile', 'pure', 'rexec', 'rfc822', 'sets', 'sha',
  485. 'sgmllib', 'sre', 'stringold', 'sunaudio', 'sv', 'test.testall', 'thread', 'timing',
  486. 'toaiff', 'user', 'urllib2', 'urlparse'
  487. ]),
  488. 'deprecated-string-function': {
  489. 'string': frozenset([
  490. 'maketrans', 'atof', 'atoi', 'atol', 'capitalize', 'expandtabs', 'find', 'rfind',
  491. 'index', 'rindex', 'count', 'lower', 'letters', 'split', 'rsplit', 'splitfields',
  492. 'join', 'joinfields', 'lstrip', 'rstrip', 'strip', 'swapcase', 'translate',
  493. 'upper', 'ljust', 'rjust', 'center', 'zfill', 'replace',
  494. 'lowercase', 'letters', 'uppercase', 'atol_error',
  495. 'atof_error', 'atoi_error', 'index_error'
  496. ])
  497. },
  498. 'deprecated-operator-function': {
  499. 'operator': frozenset({'div'}),
  500. },
  501. 'deprecated-urllib-function': {
  502. 'urllib': frozenset({
  503. 'addbase', 'addclosehook', 'addinfo', 'addinfourl', 'always_safe',
  504. 'basejoin', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies',
  505. 'getproxies_environment', 'getproxies_macosx_sysconf', 'main', 'noheaders',
  506. 'pathname2url', 'proxy_bypass', 'proxy_bypass_environment',
  507. 'proxy_bypass_macosx_sysconf', 'quote', 'quote_plus', 'reporthook',
  508. 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport',
  509. 'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'unquote',
  510. 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode',
  511. 'urlopen', 'urlretrieve'
  512. }),
  513. },
  514. 'deprecated-sys-function': {
  515. 'sys': frozenset({'exc_clear'}),
  516. }
  517. }
  518. if (3, 4) <= sys.version_info < (3, 4, 4):
  519. # Python 3.4.0 -> 3.4.3 has a bug which breaks `repr_tree()`:
  520. # https://bugs.python.org/issue23572
  521. _python_2_tests = frozenset()
  522. else:
  523. _python_2_tests = frozenset(
  524. [astroid.extract_node(x).repr_tree() for x in [
  525. 'sys.version_info[0] == 2',
  526. 'sys.version_info[0] < 3',
  527. 'sys.version_info == (2, 7)',
  528. 'sys.version_info <= (2, 7)',
  529. 'sys.version_info < (3, 0)',
  530. ]])
  531. def __init__(self, *args, **kwargs):
  532. self._future_division = False
  533. self._future_absolute_import = False
  534. self._modules_warned_about = set()
  535. self._branch_stack = []
  536. super(Python3Checker, self).__init__(*args, **kwargs)
  537. # pylint: disable=keyword-arg-before-vararg
  538. def add_message(self, msg_id, always_warn=False, # pylint: disable=arguments-differ
  539. *args, **kwargs):
  540. if always_warn or not (self._branch_stack and self._branch_stack[-1].is_py2_only):
  541. super(Python3Checker, self).add_message(msg_id, *args, **kwargs)
  542. def _is_py2_test(self, node):
  543. if isinstance(node.test, astroid.Attribute) and isinstance(node.test.expr, astroid.Name):
  544. if node.test.expr.name == 'six' and node.test.attrname == 'PY2':
  545. return True
  546. elif (isinstance(node.test, astroid.Compare) and
  547. node.test.repr_tree() in self._python_2_tests):
  548. return True
  549. return False
  550. def visit_if(self, node):
  551. self._branch_stack.append(Branch(node, self._is_py2_test(node)))
  552. def leave_if(self, node):
  553. assert self._branch_stack.pop().node == node
  554. def visit_ifexp(self, node):
  555. self._branch_stack.append(Branch(node, self._is_py2_test(node)))
  556. def leave_ifexp(self, node):
  557. assert self._branch_stack.pop().node == node
  558. def visit_module(self, node): # pylint: disable=unused-argument
  559. """Clear checker state after previous module."""
  560. self._future_division = False
  561. self._future_absolute_import = False
  562. def visit_functiondef(self, node):
  563. if node.is_method():
  564. if node.name in self._unused_magic_methods:
  565. method_name = node.name
  566. if node.name.startswith('__'):
  567. method_name = node.name[2:-2]
  568. self.add_message(method_name + '-method', node=node)
  569. elif node.name == 'next':
  570. # If there is a method named `next` declared, if it is invokable
  571. # with zero arguments then it implements the Iterator protocol.
  572. # This means if the method is an instance method or a
  573. # classmethod 1 argument should cause a failure, if it is a
  574. # staticmethod 0 arguments should cause a failure.
  575. failing_arg_count = 1
  576. if utils.decorated_with(node,
  577. [bases.BUILTINS + ".staticmethod"]):
  578. failing_arg_count = 0
  579. if len(node.args.args) == failing_arg_count:
  580. self.add_message('next-method-defined', node=node)
  581. @utils.check_messages('parameter-unpacking')
  582. def visit_arguments(self, node):
  583. for arg in node.args:
  584. if isinstance(arg, astroid.Tuple):
  585. self.add_message('parameter-unpacking', node=arg)
  586. @utils.check_messages('comprehension-escape')
  587. def visit_listcomp(self, node):
  588. names = {
  589. generator.target.name for generator in node.generators
  590. if isinstance(generator.target, astroid.AssignName)
  591. }
  592. scope = node.parent.scope()
  593. scope_names = scope.nodes_of_class(
  594. astroid.Name,
  595. skip_klass=astroid.FunctionDef,
  596. )
  597. has_redefined_assign_name = any(
  598. assign_name
  599. for assign_name in
  600. scope.nodes_of_class(
  601. astroid.AssignName,
  602. skip_klass=astroid.FunctionDef,
  603. )
  604. if assign_name.name in names and assign_name.lineno > node.lineno
  605. )
  606. if has_redefined_assign_name:
  607. return
  608. emitted_for_names = set()
  609. scope_names = list(scope_names)
  610. for scope_name in scope_names:
  611. if (scope_name.name not in names
  612. or scope_name.lineno <= node.lineno
  613. or scope_name.name in emitted_for_names
  614. or scope_name.statement().parent_of(node)):
  615. continue
  616. emitted_for_names.add(scope_name.name)
  617. self.add_message('comprehension-escape', node=scope_name)
  618. def visit_name(self, node):
  619. """Detect when a "bad" built-in is referenced."""
  620. found_node, _ = node.lookup(node.name)
  621. if _is_builtin(found_node):
  622. if node.name in self._bad_builtins:
  623. message = node.name.lower() + '-builtin'
  624. self.add_message(message, node=node)
  625. @utils.check_messages('print-statement')
  626. def visit_print(self, node):
  627. self.add_message('print-statement', node=node, always_warn=True)
  628. def _warn_if_deprecated(self, node, module, attributes, report_on_modules=True):
  629. for message, module_map in self._bad_python3_module_map.items():
  630. if module in module_map and module not in self._modules_warned_about:
  631. if isinstance(module_map, frozenset):
  632. if report_on_modules:
  633. self._modules_warned_about.add(module)
  634. self.add_message(message, node=node)
  635. elif attributes and module_map[module].intersection(attributes):
  636. self.add_message(message, node=node)
  637. def visit_importfrom(self, node):
  638. if node.modname == '__future__':
  639. for name, _ in node.names:
  640. if name == 'division':
  641. self._future_division = True
  642. elif name == 'absolute_import':
  643. self._future_absolute_import = True
  644. else:
  645. if not self._future_absolute_import:
  646. if self.linter.is_message_enabled('no-absolute-import'):
  647. self.add_message('no-absolute-import', node=node)
  648. self._future_absolute_import = True
  649. if not _is_conditional_import(node) and not node.level:
  650. self._warn_if_deprecated(node, node.modname, {x[0] for x in node.names})
  651. if node.names[0][0] == '*':
  652. if self.linter.is_message_enabled('import-star-module-level'):
  653. if not isinstance(node.scope(), astroid.Module):
  654. self.add_message('import-star-module-level', node=node)
  655. def visit_import(self, node):
  656. if not self._future_absolute_import:
  657. if self.linter.is_message_enabled('no-absolute-import'):
  658. self.add_message('no-absolute-import', node=node)
  659. self._future_absolute_import = True
  660. if not _is_conditional_import(node):
  661. for name, _ in node.names:
  662. self._warn_if_deprecated(node, name, None)
  663. @utils.check_messages('metaclass-assignment')
  664. def visit_classdef(self, node):
  665. if '__metaclass__' in node.locals:
  666. self.add_message('metaclass-assignment', node=node)
  667. locals_and_methods = set(node.locals).union(x.name for x in node.mymethods())
  668. if '__eq__' in locals_and_methods and '__hash__' not in locals_and_methods:
  669. self.add_message('eq-without-hash', node=node)
  670. @utils.check_messages('old-division')
  671. def visit_binop(self, node):
  672. if not self._future_division and node.op == '/':
  673. for arg in (node.left, node.right):
  674. if isinstance(arg, astroid.Const) and isinstance(arg.value, float):
  675. break
  676. else:
  677. self.add_message('old-division', node=node)
  678. def _check_cmp_argument(self, node):
  679. # Check that the `cmp` argument is used
  680. kwargs = []
  681. if (isinstance(node.func, astroid.Attribute)
  682. and node.func.attrname == 'sort'):
  683. inferred = utils.safe_infer(node.func.expr)
  684. if not inferred:
  685. return
  686. builtins_list = "{}.list".format(bases.BUILTINS)
  687. if (isinstance(inferred, astroid.List)
  688. or inferred.qname() == builtins_list):
  689. kwargs = node.keywords
  690. elif (isinstance(node.func, astroid.Name)
  691. and node.func.name == 'sorted'):
  692. inferred = utils.safe_infer(node.func)
  693. if not inferred:
  694. return
  695. builtins_sorted = "{}.sorted".format(bases.BUILTINS)
  696. if inferred.qname() == builtins_sorted:
  697. kwargs = node.keywords
  698. for kwarg in kwargs or []:
  699. if kwarg.arg == 'cmp':
  700. self.add_message('using-cmp-argument', node=node)
  701. return
  702. @staticmethod
  703. def _is_constant_string_or_name(node):
  704. if isinstance(node, astroid.Const):
  705. return isinstance(node.value, six.string_types)
  706. return isinstance(node, astroid.Name)
  707. @staticmethod
  708. def _is_none(node):
  709. return isinstance(node, astroid.Const) and node.value is None
  710. @staticmethod
  711. def _has_only_n_positional_args(node, number_of_args):
  712. return len(node.args) == number_of_args and all(node.args) and not node.keywords
  713. @staticmethod
  714. def _could_be_string(inferred_types):
  715. confidence = INFERENCE if inferred_types else INFERENCE_FAILURE
  716. for inferred_type in inferred_types:
  717. if inferred_type is astroid.Uninferable:
  718. confidence = INFERENCE_FAILURE
  719. elif not (isinstance(inferred_type, astroid.Const) and
  720. isinstance(inferred_type.value, six.string_types)):
  721. return None
  722. return confidence
  723. def visit_call(self, node):
  724. self._check_cmp_argument(node)
  725. if isinstance(node.func, astroid.Attribute):
  726. inferred_types = set()
  727. try:
  728. for inferred_receiver in node.func.expr.infer():
  729. if inferred_receiver is astroid.Uninferable:
  730. continue
  731. inferred_types.add(inferred_receiver)
  732. if isinstance(inferred_receiver, astroid.Module):
  733. self._warn_if_deprecated(node, inferred_receiver.name,
  734. {node.func.attrname},
  735. report_on_modules=False)
  736. if (_inferred_value_is_dict(inferred_receiver)
  737. and node.func.attrname in DICT_METHODS):
  738. if not _in_iterating_context(node):
  739. checker = 'dict-{}-not-iterating'.format(node.func.attrname)
  740. self.add_message(checker, node=node)
  741. except astroid.InferenceError:
  742. pass
  743. if node.args:
  744. is_str_confidence = self._could_be_string(inferred_types)
  745. if is_str_confidence:
  746. if (node.func.attrname in ('encode', 'decode') and
  747. len(node.args) >= 1 and node.args[0]):
  748. first_arg = node.args[0]
  749. self._validate_encoding(first_arg, node)
  750. if (node.func.attrname == 'translate' and
  751. self._has_only_n_positional_args(node, 2) and
  752. self._is_none(node.args[0]) and
  753. self._is_constant_string_or_name(node.args[1])):
  754. # The above statement looking for calls of the form:
  755. #
  756. # foo.translate(None, 'abc123')
  757. #
  758. # or
  759. #
  760. # foo.translate(None, some_variable)
  761. #
  762. # This check is somewhat broad and _may_ have some false positives, but
  763. # after checking several large codebases it did not have any false
  764. # positives while finding several real issues. This call pattern seems
  765. # rare enough that the trade off is worth it.
  766. self.add_message('deprecated-str-translate-call',
  767. node=node,
  768. confidence=is_str_confidence)
  769. return
  770. if node.keywords:
  771. return
  772. if node.func.attrname == 'next':
  773. self.add_message('next-method-called', node=node)
  774. else:
  775. if _check_dict_node(node.func.expr):
  776. if node.func.attrname in ('iterkeys', 'itervalues', 'iteritems'):
  777. self.add_message('dict-iter-method', node=node)
  778. elif node.func.attrname in ('viewkeys', 'viewvalues', 'viewitems'):
  779. self.add_message('dict-view-method', node=node)
  780. elif isinstance(node.func, astroid.Name):
  781. found_node = node.func.lookup(node.func.name)[0]
  782. if _is_builtin(found_node):
  783. if node.func.name in ('filter', 'map', 'range', 'zip'):
  784. if not _in_iterating_context(node):
  785. checker = '{}-builtin-not-iterating'.format(node.func.name)
  786. self.add_message(checker, node=node)
  787. if node.func.name == 'open' and node.keywords:
  788. kwargs = node.keywords
  789. for kwarg in kwargs or []:
  790. if kwarg.arg == 'encoding':
  791. self._validate_encoding(kwarg.value, node)
  792. break
  793. def _validate_encoding(self, encoding, node):
  794. if isinstance(encoding, astroid.Const):
  795. value = encoding.value
  796. if value in self._invalid_encodings:
  797. self.add_message('invalid-str-codec',
  798. node=node)
  799. @utils.check_messages('indexing-exception')
  800. def visit_subscript(self, node):
  801. """ Look for indexing exceptions. """
  802. try:
  803. for inferred in node.value.infer():
  804. if not isinstance(inferred, astroid.Instance):
  805. continue
  806. if utils.inherit_from_std_ex(inferred):
  807. self.add_message('indexing-exception', node=node)
  808. except astroid.InferenceError:
  809. return
  810. def visit_assignattr(self, node):
  811. if isinstance(node.assign_type(), astroid.AugAssign):
  812. self.visit_attribute(node)
  813. def visit_delattr(self, node):
  814. self.visit_attribute(node)
  815. @utils.check_messages('exception-message-attribute', 'xreadlines-attribute')
  816. def visit_attribute(self, node):
  817. """Look for removed attributes"""
  818. if node.attrname == 'xreadlines':
  819. self.add_message('xreadlines-attribute', node=node)
  820. return
  821. exception_message = 'message'
  822. try:
  823. for inferred in node.expr.infer():
  824. if (isinstance(inferred, astroid.Instance) and
  825. utils.inherit_from_std_ex(inferred)):
  826. if node.attrname == exception_message:
  827. # Exceptions with .message clearly defined are an exception
  828. if exception_message in inferred.instance_attrs:
  829. continue
  830. self.add_message('exception-message-attribute', node=node)
  831. if isinstance(inferred, astroid.Module):
  832. self._warn_if_deprecated(node, inferred.name, {node.attrname},
  833. report_on_modules=False)
  834. except astroid.InferenceError:
  835. return
  836. @utils.check_messages('unpacking-in-except', 'comprehension-escape')
  837. def visit_excepthandler(self, node):
  838. """Visit an except handler block and check for exception unpacking."""
  839. def _is_used_in_except_block(node):
  840. scope = node.scope()
  841. current = node
  842. while current and current != scope and not isinstance(current, astroid.ExceptHandler):
  843. current = current.parent
  844. return isinstance(current, astroid.ExceptHandler) and current.type != node
  845. if isinstance(node.name, (astroid.Tuple, astroid.List)):
  846. self.add_message('unpacking-in-except', node=node)
  847. return
  848. if not node.name:
  849. return
  850. # Find any names
  851. scope = node.parent.scope()
  852. scope_names = scope.nodes_of_class(
  853. astroid.Name,
  854. skip_klass=astroid.FunctionDef,
  855. )
  856. scope_names = list(scope_names)
  857. potential_leaked_names = [
  858. scope_name
  859. for scope_name in scope_names
  860. if scope_name.name == node.name.name and scope_name.lineno > node.lineno
  861. and not _is_used_in_except_block(scope_name)
  862. ]
  863. reassignments_for_same_name = {
  864. assign_name.lineno
  865. for assign_name in
  866. scope.nodes_of_class(
  867. astroid.AssignName,
  868. skip_klass=astroid.FunctionDef,
  869. )
  870. if assign_name.name == node.name.name
  871. }
  872. for leaked_name in potential_leaked_names:
  873. if any(node.lineno < elem < leaked_name.lineno for elem in reassignments_for_same_name):
  874. continue
  875. self.add_message('exception-escape', node=leaked_name)
  876. @utils.check_messages('backtick')
  877. def visit_repr(self, node):
  878. self.add_message('backtick', node=node)
  879. @utils.check_messages('raising-string', 'old-raise-syntax')
  880. def visit_raise(self, node):
  881. """Visit a raise statement and check for raising
  882. strings or old-raise-syntax.
  883. """
  884. if six.PY2:
  885. if (node.exc is not None and
  886. node.inst is not None):
  887. self.add_message('old-raise-syntax', node=node)
  888. # Ignore empty raise.
  889. if node.exc is None:
  890. return
  891. expr = node.exc
  892. if self._check_raise_value(node, expr):
  893. return
  894. try:
  895. value = next(astroid.unpack_infer(expr))
  896. except astroid.InferenceError:
  897. return
  898. self._check_raise_value(node, value)
  899. def _check_raise_value(self, node, expr):
  900. if isinstance(expr, astroid.Const):
  901. value = expr.value
  902. if isinstance(value, str):
  903. self.add_message('raising-string', node=node)
  904. return True
  905. return None
  906. class Python3TokenChecker(checkers.BaseTokenChecker):
  907. __implements__ = interfaces.ITokenChecker
  908. name = 'python3'
  909. enabled = False
  910. msgs = {
  911. 'E1606': ('Use of long suffix',
  912. 'long-suffix',
  913. 'Used when "l" or "L" is used to mark a long integer. '
  914. 'This will not work in Python 3, since `int` and `long` '
  915. 'types have merged.',
  916. {'maxversion': (3, 0)}),
  917. 'E1607': ('Use of the <> operator',
  918. 'old-ne-operator',
  919. 'Used when the deprecated "<>" operator is used instead '
  920. 'of "!=". This is removed in Python 3.',
  921. {'maxversion': (3, 0),
  922. 'old_names': [('W0331', 'old-ne-operator')]}),
  923. 'E1608': ('Use of old octal literal',
  924. 'old-octal-literal',
  925. 'Used when encountering the old octal syntax, '
  926. 'removed in Python 3. To use the new syntax, '
  927. 'prepend 0o on the number.',
  928. {'maxversion': (3, 0)}),
  929. 'E1610': ('Non-ascii bytes literals not supported in 3.x',
  930. 'non-ascii-bytes-literal',
  931. 'Used when non-ascii bytes literals are found in a program. '
  932. 'They are no longer supported in Python 3.',
  933. {'maxversion': (3, 0)}),
  934. 'E1611': ('unicode raw string literals not supported in 3.x',
  935. 'invalid-unicode-literal',
  936. 'Used when raw unicode literals are found in a program. '
  937. 'They are no longer supported in Python 3.',
  938. {'maxversion': (3, 0)}),
  939. }
  940. def process_tokens(self, tokens):
  941. for idx, (tok_type, token, start, _, _) in enumerate(tokens):
  942. if tok_type == tokenize.NUMBER:
  943. if token.lower().endswith('l'):
  944. # This has a different semantic than lowercase-l-suffix.
  945. self.add_message('long-suffix', line=start[0])
  946. elif _is_old_octal(token):
  947. self.add_message('old-octal-literal', line=start[0])
  948. if tokens[idx][1] == '<>':
  949. self.add_message('old-ne-operator', line=tokens[idx][2][0])
  950. if tok_type == tokenize.STRING and token.startswith('b'):
  951. if any(elem for elem in token if ord(elem) > 127):
  952. self.add_message('non-ascii-bytes-literal', line=start[0])
  953. if tok_type == tokenize.STRING and token.startswith('ur'):
  954. self.add_message('invalid-unicode-literal', line=start[0])
  955. def register(linter):
  956. linter.register_checker(Python3Checker(linter))
  957. linter.register_checker(Python3TokenChecker(linter))