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.

utils.py 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2006-2007, 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
  3. # Copyright (c) 2009 Mads Kiilerich <mads@kiilerich.com>
  4. # Copyright (c) 2010 Daniel Harding <dharding@gmail.com>
  5. # Copyright (c) 2012-2014 Google, Inc.
  6. # Copyright (c) 2012 FELD Boris <lothiraldan@gmail.com>
  7. # Copyright (c) 2013-2017 Claudiu Popa <pcmanticore@gmail.com>
  8. # Copyright (c) 2014 Brett Cannon <brett@python.org>
  9. # Copyright (c) 2014 Ricardo Gemignani <ricardo.gemignani@gmail.com>
  10. # Copyright (c) 2014 Arun Persaud <arun@nubati.net>
  11. # Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
  12. # Copyright (c) 2015 Florian Bruhin <me@the-compiler.org>
  13. # Copyright (c) 2015 Radu Ciorba <radu@devrandom.ro>
  14. # Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
  15. # Copyright (c) 2016, 2018 Ashley Whetter <ashley@awhetter.co.uk>
  16. # Copyright (c) 2016-2017 Łukasz Rogalski <rogalski.91@gmail.com>
  17. # Copyright (c) 2016-2017 Moises Lopez <moylop260@vauxoo.com>
  18. # Copyright (c) 2016 Brian C. Lane <bcl@redhat.com>
  19. # Copyright (c) 2017-2018 hippo91 <guillaume.peillex@gmail.com>
  20. # Copyright (c) 2017 ttenhoeve-aa <ttenhoeve@appannie.com>
  21. # Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
  22. # Copyright (c) 2018 Brian Shaginaw <brian.shaginaw@warbyparker.com>
  23. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  24. # For details: https://github.com/PyCQA/pylint/blob/master/COPYING
  25. # pylint: disable=W0611
  26. """some functions that may be useful for various checkers
  27. """
  28. import collections
  29. import functools
  30. try:
  31. from functools import singledispatch as singledispatch
  32. except ImportError:
  33. # pylint: disable=import-error
  34. from singledispatch import singledispatch as singledispatch
  35. try:
  36. from functools import lru_cache
  37. except ImportError:
  38. from backports.functools_lru_cache import lru_cache
  39. import itertools
  40. import re
  41. import sys
  42. import string
  43. import warnings
  44. import six
  45. from six.moves import map, builtins # pylint: disable=redefined-builtin
  46. import astroid
  47. from astroid import bases as _bases
  48. from astroid import scoped_nodes
  49. BUILTINS_NAME = builtins.__name__
  50. COMP_NODE_TYPES = (astroid.ListComp, astroid.SetComp,
  51. astroid.DictComp, astroid.GeneratorExp)
  52. PY3K = sys.version_info[0] == 3
  53. if not PY3K:
  54. EXCEPTIONS_MODULE = "exceptions"
  55. else:
  56. EXCEPTIONS_MODULE = "builtins"
  57. ABC_METHODS = set(('abc.abstractproperty', 'abc.abstractmethod',
  58. 'abc.abstractclassmethod', 'abc.abstractstaticmethod'))
  59. ITER_METHOD = '__iter__'
  60. NEXT_METHOD = 'next' if six.PY2 else '__next__'
  61. GETITEM_METHOD = '__getitem__'
  62. SETITEM_METHOD = '__setitem__'
  63. DELITEM_METHOD = '__delitem__'
  64. CONTAINS_METHOD = '__contains__'
  65. KEYS_METHOD = 'keys'
  66. # Dictionary which maps the number of expected parameters a
  67. # special method can have to a set of special methods.
  68. # The following keys are used to denote the parameters restrictions:
  69. #
  70. # * None: variable number of parameters
  71. # * number: exactly that number of parameters
  72. # * tuple: this are the odd ones. Basically it means that the function
  73. # can work with any number of arguments from that tuple,
  74. # although it's best to implement it in order to accept
  75. # all of them.
  76. _SPECIAL_METHODS_PARAMS = {
  77. None: ('__new__', '__init__', '__call__'),
  78. 0: ('__del__', '__repr__', '__str__', '__bytes__', '__hash__', '__bool__',
  79. '__dir__', '__len__', '__length_hint__', '__iter__', '__reversed__',
  80. '__neg__', '__pos__', '__abs__', '__invert__', '__complex__', '__int__',
  81. '__float__', '__neg__', '__pos__', '__abs__', '__complex__', '__int__',
  82. '__float__', '__index__', '__enter__', '__aenter__', '__getnewargs_ex__',
  83. '__getnewargs__', '__getstate__', '__reduce__', '__copy__',
  84. '__unicode__', '__nonzero__', '__await__', '__aiter__', '__anext__',
  85. '__fspath__'),
  86. 1: ('__format__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__',
  87. '__ge__', '__getattr__', '__getattribute__', '__delattr__',
  88. '__delete__', '__instancecheck__', '__subclasscheck__',
  89. '__getitem__', '__missing__', '__delitem__', '__contains__',
  90. '__add__', '__sub__', '__mul__', '__truediv__', '__floordiv__',
  91. '__mod__', '__divmod__', '__lshift__', '__rshift__', '__and__',
  92. '__xor__', '__or__', '__radd__', '__rsub__', '__rmul__', '__rtruediv__',
  93. '__rmod__', '__rdivmod__', '__rpow__', '__rlshift__', '__rrshift__',
  94. '__rand__', '__rxor__', '__ror__', '__iadd__', '__isub__', '__imul__',
  95. '__itruediv__', '__ifloordiv__', '__imod__', '__ilshift__',
  96. '__irshift__', '__iand__', '__ixor__', '__ior__', '__ipow__',
  97. '__setstate__', '__reduce_ex__', '__deepcopy__', '__cmp__',
  98. '__matmul__', '__rmatmul__', '__div__'),
  99. 2: ('__setattr__', '__get__', '__set__', '__setitem__', '__set_name__'),
  100. 3: ('__exit__', '__aexit__'),
  101. (0, 1): ('__round__', ),
  102. }
  103. SPECIAL_METHODS_PARAMS = {
  104. name: params
  105. for params, methods in _SPECIAL_METHODS_PARAMS.items()
  106. for name in methods
  107. }
  108. PYMETHODS = set(SPECIAL_METHODS_PARAMS)
  109. class NoSuchArgumentError(Exception):
  110. pass
  111. def is_inside_except(node):
  112. """Returns true if node is inside the name of an except handler."""
  113. current = node
  114. while current and not isinstance(current.parent, astroid.ExceptHandler):
  115. current = current.parent
  116. return current and current is current.parent.name
  117. def get_all_elements(node):
  118. """Recursively returns all atoms in nested lists and tuples."""
  119. if isinstance(node, (astroid.Tuple, astroid.List)):
  120. for child in node.elts:
  121. for e in get_all_elements(child):
  122. yield e
  123. else:
  124. yield node
  125. def clobber_in_except(node):
  126. """Checks if an assignment node in an except handler clobbers an existing
  127. variable.
  128. Returns (True, args for W0623) if assignment clobbers an existing variable,
  129. (False, None) otherwise.
  130. """
  131. if isinstance(node, astroid.AssignAttr):
  132. return (True, (node.attrname, 'object %r' % (node.expr.as_string(),)))
  133. elif isinstance(node, astroid.AssignName):
  134. name = node.name
  135. if is_builtin(name):
  136. return (True, (name, 'builtins'))
  137. else:
  138. stmts = node.lookup(name)[1]
  139. if (stmts and not isinstance(stmts[0].assign_type(),
  140. (astroid.Assign, astroid.AugAssign,
  141. astroid.ExceptHandler))):
  142. return (True, (name, 'outer scope (line %s)' % stmts[0].fromlineno))
  143. return (False, None)
  144. def is_super(node):
  145. """return True if the node is referencing the "super" builtin function
  146. """
  147. if getattr(node, 'name', None) == 'super' and \
  148. node.root().name == BUILTINS_NAME:
  149. return True
  150. return False
  151. def is_error(node):
  152. """return true if the function does nothing but raising an exception"""
  153. for child_node in node.get_children():
  154. if isinstance(child_node, astroid.Raise):
  155. return True
  156. return False
  157. def is_raising(body):
  158. """return true if the given statement node raise an exception"""
  159. for node in body:
  160. if isinstance(node, astroid.Raise):
  161. return True
  162. return False
  163. builtins = builtins.__dict__.copy()
  164. SPECIAL_BUILTINS = ('__builtins__',) # '__path__', '__file__')
  165. def is_builtin_object(node):
  166. """Returns True if the given node is an object from the __builtin__ module."""
  167. return node and node.root().name == BUILTINS_NAME
  168. def is_builtin(name):
  169. """return true if <name> could be considered as a builtin defined by python
  170. """
  171. return name in builtins or name in SPECIAL_BUILTINS
  172. def is_defined_before(var_node):
  173. """return True if the variable node is defined by a parent node (list,
  174. set, dict, or generator comprehension, lambda) or in a previous sibling
  175. node on the same line (statement_defining ; statement_using)
  176. """
  177. varname = var_node.name
  178. _node = var_node.parent
  179. while _node:
  180. if isinstance(_node, COMP_NODE_TYPES):
  181. for ass_node in _node.nodes_of_class(astroid.AssignName):
  182. if ass_node.name == varname:
  183. return True
  184. elif isinstance(_node, astroid.For):
  185. for ass_node in _node.target.nodes_of_class(astroid.AssignName):
  186. if ass_node.name == varname:
  187. return True
  188. elif isinstance(_node, astroid.With):
  189. for expr, ids in _node.items:
  190. if expr.parent_of(var_node):
  191. break
  192. if (ids and
  193. isinstance(ids, astroid.AssignName) and
  194. ids.name == varname):
  195. return True
  196. elif isinstance(_node, (astroid.Lambda, astroid.FunctionDef)):
  197. if _node.args.is_argument(varname):
  198. # If the name is found inside a default value
  199. # of a function, then let the search continue
  200. # in the parent's tree.
  201. if _node.args.parent_of(var_node):
  202. try:
  203. _node.args.default_value(varname)
  204. _node = _node.parent
  205. continue
  206. except astroid.NoDefault:
  207. pass
  208. return True
  209. if getattr(_node, 'name', None) == varname:
  210. return True
  211. break
  212. elif isinstance(_node, astroid.ExceptHandler):
  213. if isinstance(_node.name, astroid.AssignName):
  214. ass_node = _node.name
  215. if ass_node.name == varname:
  216. return True
  217. _node = _node.parent
  218. # possibly multiple statements on the same line using semi colon separator
  219. stmt = var_node.statement()
  220. _node = stmt.previous_sibling()
  221. lineno = stmt.fromlineno
  222. while _node and _node.fromlineno == lineno:
  223. for ass_node in _node.nodes_of_class(astroid.AssignName):
  224. if ass_node.name == varname:
  225. return True
  226. for imp_node in _node.nodes_of_class((astroid.ImportFrom, astroid.Import)):
  227. if varname in [name[1] or name[0] for name in imp_node.names]:
  228. return True
  229. _node = _node.previous_sibling()
  230. return False
  231. def is_func_default(node):
  232. """return true if the given Name node is used in function default argument's
  233. value
  234. """
  235. parent = node.scope()
  236. if isinstance(parent, astroid.FunctionDef):
  237. for default_node in parent.args.defaults:
  238. for default_name_node in default_node.nodes_of_class(astroid.Name):
  239. if default_name_node is node:
  240. return True
  241. return False
  242. def is_func_decorator(node):
  243. """return true if the name is used in function decorator"""
  244. parent = node.parent
  245. while parent is not None:
  246. if isinstance(parent, astroid.Decorators):
  247. return True
  248. if (parent.is_statement or
  249. isinstance(parent, (astroid.Lambda,
  250. scoped_nodes.ComprehensionScope,
  251. scoped_nodes.ListComp))):
  252. break
  253. parent = parent.parent
  254. return False
  255. def is_ancestor_name(frame, node):
  256. """return True if `frame` is a astroid.Class node with `node` in the
  257. subtree of its bases attribute
  258. """
  259. try:
  260. bases = frame.bases
  261. except AttributeError:
  262. return False
  263. for base in bases:
  264. if node in base.nodes_of_class(astroid.Name):
  265. return True
  266. return False
  267. def assign_parent(node):
  268. """return the higher parent which is not an AssignName, Tuple or List node
  269. """
  270. while node and isinstance(node, (astroid.AssignName,
  271. astroid.Tuple,
  272. astroid.List)):
  273. node = node.parent
  274. return node
  275. def overrides_a_method(class_node, name):
  276. """return True if <name> is a method overridden from an ancestor"""
  277. for ancestor in class_node.ancestors():
  278. if name in ancestor and isinstance(ancestor[name], astroid.FunctionDef):
  279. return True
  280. return False
  281. def check_messages(*messages):
  282. """decorator to store messages that are handled by a checker method"""
  283. def store_messages(func):
  284. func.checks_msgs = messages
  285. return func
  286. return store_messages
  287. class IncompleteFormatString(Exception):
  288. """A format string ended in the middle of a format specifier."""
  289. pass
  290. class UnsupportedFormatCharacter(Exception):
  291. """A format character in a format string is not one of the supported
  292. format characters."""
  293. def __init__(self, index):
  294. Exception.__init__(self, index)
  295. self.index = index
  296. def parse_format_string(format_string):
  297. """Parses a format string, returning a tuple of (keys, num_args), where keys
  298. is the set of mapping keys in the format string, and num_args is the number
  299. of arguments required by the format string. Raises
  300. IncompleteFormatString or UnsupportedFormatCharacter if a
  301. parse error occurs."""
  302. keys = set()
  303. num_args = 0
  304. def next_char(i):
  305. i += 1
  306. if i == len(format_string):
  307. raise IncompleteFormatString
  308. return (i, format_string[i])
  309. i = 0
  310. while i < len(format_string):
  311. char = format_string[i]
  312. if char == '%':
  313. i, char = next_char(i)
  314. # Parse the mapping key (optional).
  315. key = None
  316. if char == '(':
  317. depth = 1
  318. i, char = next_char(i)
  319. key_start = i
  320. while depth != 0:
  321. if char == '(':
  322. depth += 1
  323. elif char == ')':
  324. depth -= 1
  325. i, char = next_char(i)
  326. key_end = i - 1
  327. key = format_string[key_start:key_end]
  328. # Parse the conversion flags (optional).
  329. while char in '#0- +':
  330. i, char = next_char(i)
  331. # Parse the minimum field width (optional).
  332. if char == '*':
  333. num_args += 1
  334. i, char = next_char(i)
  335. else:
  336. while char in string.digits:
  337. i, char = next_char(i)
  338. # Parse the precision (optional).
  339. if char == '.':
  340. i, char = next_char(i)
  341. if char == '*':
  342. num_args += 1
  343. i, char = next_char(i)
  344. else:
  345. while char in string.digits:
  346. i, char = next_char(i)
  347. # Parse the length modifier (optional).
  348. if char in 'hlL':
  349. i, char = next_char(i)
  350. # Parse the conversion type (mandatory).
  351. if PY3K:
  352. flags = 'diouxXeEfFgGcrs%a'
  353. else:
  354. flags = 'diouxXeEfFgGcrs%'
  355. if char not in flags:
  356. raise UnsupportedFormatCharacter(i)
  357. if key:
  358. keys.add(key)
  359. elif char != '%':
  360. num_args += 1
  361. i += 1
  362. return keys, num_args
  363. def is_attr_protected(attrname):
  364. """return True if attribute name is protected (start with _ and some other
  365. details), False otherwise.
  366. """
  367. return attrname[0] == '_' and attrname != '_' and not (
  368. attrname.startswith('__') and attrname.endswith('__'))
  369. def node_frame_class(node):
  370. """return klass node for a method node (or a staticmethod or a
  371. classmethod), return null otherwise
  372. """
  373. klass = node.frame()
  374. while klass is not None and not isinstance(klass, astroid.ClassDef):
  375. if klass.parent is None:
  376. klass = None
  377. else:
  378. klass = klass.parent.frame()
  379. return klass
  380. def is_attr_private(attrname):
  381. """Check that attribute name is private (at least two leading underscores,
  382. at most one trailing underscore)
  383. """
  384. regex = re.compile('^_{2,}.*[^_]+_?$')
  385. return regex.match(attrname)
  386. def get_argument_from_call(call_node, position=None, keyword=None):
  387. """Returns the specified argument from a function call.
  388. :param astroid.Call call_node: Node representing a function call to check.
  389. :param int position: position of the argument.
  390. :param str keyword: the keyword of the argument.
  391. :returns: The node representing the argument, None if the argument is not found.
  392. :rtype: astroid.Name
  393. :raises ValueError: if both position and keyword are None.
  394. :raises NoSuchArgumentError: if no argument at the provided position or with
  395. the provided keyword.
  396. """
  397. if position is None and keyword is None:
  398. raise ValueError('Must specify at least one of: position or keyword.')
  399. if position is not None:
  400. try:
  401. return call_node.args[position]
  402. except IndexError:
  403. pass
  404. if keyword and call_node.keywords:
  405. for arg in call_node.keywords:
  406. if arg.arg == keyword:
  407. return arg.value
  408. raise NoSuchArgumentError
  409. def inherit_from_std_ex(node):
  410. """
  411. Return true if the given class node is subclass of
  412. exceptions.Exception.
  413. """
  414. if node.name in ('Exception', 'BaseException') \
  415. and node.root().name == EXCEPTIONS_MODULE:
  416. return True
  417. if not hasattr(node, 'ancestors'):
  418. return False
  419. return any(inherit_from_std_ex(parent)
  420. for parent in node.ancestors(recurs=True))
  421. def error_of_type(handler, error_type):
  422. """
  423. Check if the given exception handler catches
  424. the given error_type.
  425. The *handler* parameter is a node, representing an ExceptHandler node.
  426. The *error_type* can be an exception, such as AttributeError,
  427. the name of an exception, or it can be a tuple of errors.
  428. The function will return True if the handler catches any of the
  429. given errors.
  430. """
  431. def stringify_error(error):
  432. if not isinstance(error, six.string_types):
  433. return error.__name__
  434. return error
  435. if not isinstance(error_type, tuple):
  436. error_type = (error_type, )
  437. expected_errors = {stringify_error(error) for error in error_type}
  438. if not handler.type:
  439. # bare except. While this indeed catches anything, if the desired errors
  440. # aren't specified directly, then we just ignore it.
  441. return False
  442. return handler.catch(expected_errors)
  443. def decorated_with_property(node):
  444. """ Detect if the given function node is decorated with a property. """
  445. if not node.decorators:
  446. return False
  447. for decorator in node.decorators.nodes:
  448. if not isinstance(decorator, astroid.Name):
  449. continue
  450. try:
  451. if _is_property_decorator(decorator):
  452. return True
  453. except astroid.InferenceError:
  454. pass
  455. return False
  456. def _is_property_decorator(decorator):
  457. for infered in decorator.infer():
  458. if isinstance(infered, astroid.ClassDef):
  459. if infered.root().name == BUILTINS_NAME and infered.name == 'property':
  460. return True
  461. for ancestor in infered.ancestors():
  462. if ancestor.name == 'property' and ancestor.root().name == BUILTINS_NAME:
  463. return True
  464. return None
  465. def decorated_with(func, qnames):
  466. """Determine if the `func` node has a decorator with the qualified name `qname`."""
  467. decorators = func.decorators.nodes if func.decorators else []
  468. for decorator_node in decorators:
  469. try:
  470. if any(i is not None and i.qname() in qnames for i in decorator_node.infer()):
  471. return True
  472. except astroid.InferenceError:
  473. continue
  474. return False
  475. @lru_cache(maxsize=1024)
  476. def unimplemented_abstract_methods(node, is_abstract_cb=None):
  477. """
  478. Get the unimplemented abstract methods for the given *node*.
  479. A method can be considered abstract if the callback *is_abstract_cb*
  480. returns a ``True`` value. The check defaults to verifying that
  481. a method is decorated with abstract methods.
  482. The function will work only for new-style classes. For old-style
  483. classes, it will simply return an empty dictionary.
  484. For the rest of them, it will return a dictionary of abstract method
  485. names and their inferred objects.
  486. """
  487. if is_abstract_cb is None:
  488. is_abstract_cb = functools.partial(
  489. decorated_with, qnames=ABC_METHODS)
  490. visited = {}
  491. try:
  492. mro = reversed(node.mro())
  493. except NotImplementedError:
  494. # Old style class, it will not have a mro.
  495. return {}
  496. except astroid.ResolveError:
  497. # Probably inconsistent hierarchy, don'try
  498. # to figure this out here.
  499. return {}
  500. for ancestor in mro:
  501. for obj in ancestor.values():
  502. infered = obj
  503. if isinstance(obj, astroid.AssignName):
  504. infered = safe_infer(obj)
  505. if not infered:
  506. # Might be an abstract function,
  507. # but since we don't have enough information
  508. # in order to take this decision, we're taking
  509. # the *safe* decision instead.
  510. if obj.name in visited:
  511. del visited[obj.name]
  512. continue
  513. if not isinstance(infered, astroid.FunctionDef):
  514. if obj.name in visited:
  515. del visited[obj.name]
  516. if isinstance(infered, astroid.FunctionDef):
  517. # It's critical to use the original name,
  518. # since after inferring, an object can be something
  519. # else than expected, as in the case of the
  520. # following assignment.
  521. #
  522. # class A:
  523. # def keys(self): pass
  524. # __iter__ = keys
  525. abstract = is_abstract_cb(infered)
  526. if abstract:
  527. visited[obj.name] = infered
  528. elif not abstract and obj.name in visited:
  529. del visited[obj.name]
  530. return visited
  531. def _import_node_context(node):
  532. """Return the ExceptHandler or the TryExcept node in which the node is."""
  533. current = node
  534. ignores = (astroid.ExceptHandler, astroid.TryExcept)
  535. while current and not isinstance(current.parent, ignores):
  536. current = current.parent
  537. if current and isinstance(current.parent, ignores):
  538. return current.parent
  539. return None
  540. def is_from_fallback_block(node):
  541. """Check if the given node is from a fallback import block."""
  542. context = _import_node_context(node)
  543. if not context:
  544. return False
  545. if isinstance(context, astroid.ExceptHandler):
  546. other_body = context.parent.body
  547. handlers = context.parent.handlers
  548. else:
  549. other_body = itertools.chain.from_iterable(
  550. handler.body for handler in context.handlers)
  551. handlers = context.handlers
  552. has_fallback_imports = any(isinstance(import_node, (astroid.ImportFrom, astroid.Import))
  553. for import_node in other_body)
  554. ignores_import_error = _except_handlers_ignores_exception(handlers, ImportError)
  555. return ignores_import_error or has_fallback_imports
  556. def _except_handlers_ignores_exception(handlers, exception):
  557. func = functools.partial(error_of_type, error_type=(exception, ))
  558. return any(map(func, handlers))
  559. def get_exception_handlers(node, exception):
  560. """Return the collections of handlers handling the exception in arguments.
  561. Args:
  562. node (astroid.Raise): the node raising the exception.
  563. exception (builtin.Exception or str): exception or name of the exception.
  564. Returns:
  565. generator: the collection of handlers that are handling the exception or None.
  566. """
  567. context = _import_node_context(node)
  568. if isinstance(context, astroid.TryExcept):
  569. return (_handler for _handler in context.handlers
  570. if error_of_type(_handler, exception))
  571. return None
  572. def is_node_inside_try_except(node):
  573. """Check if the node is directly under a Try/Except statement.
  574. (but not under an ExceptHandler!)
  575. Args:
  576. node (astroid.Raise): the node raising the exception.
  577. Returns:
  578. bool: True if the node is inside a try/except statement, False otherwise.
  579. """
  580. context = _import_node_context(node)
  581. return isinstance(context, astroid.TryExcept)
  582. def node_ignores_exception(node, exception):
  583. """Check if the node is in a TryExcept which handles the given exception."""
  584. managing_handlers = get_exception_handlers(node, exception)
  585. if not managing_handlers:
  586. return False
  587. return any(managing_handlers)
  588. def class_is_abstract(node):
  589. """return true if the given class node should be considered as an abstract
  590. class
  591. """
  592. for method in node.methods():
  593. if method.parent.frame() is node:
  594. if method.is_abstract(pass_is_abstract=False):
  595. return True
  596. return False
  597. def _supports_protocol_method(value, attr):
  598. try:
  599. attributes = value.getattr(attr)
  600. except astroid.NotFoundError:
  601. return False
  602. first = attributes[0]
  603. if isinstance(first, astroid.AssignName):
  604. if isinstance(first.parent.value, astroid.Const):
  605. return False
  606. return True
  607. def is_comprehension(node):
  608. comprehensions = (astroid.ListComp,
  609. astroid.SetComp,
  610. astroid.DictComp,
  611. astroid.GeneratorExp)
  612. return isinstance(node, comprehensions)
  613. def _supports_mapping_protocol(value):
  614. return (
  615. _supports_protocol_method(value, GETITEM_METHOD)
  616. and _supports_protocol_method(value, KEYS_METHOD)
  617. )
  618. def _supports_membership_test_protocol(value):
  619. return _supports_protocol_method(value, CONTAINS_METHOD)
  620. def _supports_iteration_protocol(value):
  621. return (
  622. _supports_protocol_method(value, ITER_METHOD)
  623. or _supports_protocol_method(value, GETITEM_METHOD)
  624. )
  625. def _supports_getitem_protocol(value):
  626. return _supports_protocol_method(value, GETITEM_METHOD)
  627. def _supports_setitem_protocol(value):
  628. return _supports_protocol_method(value, SETITEM_METHOD)
  629. def _supports_delitem_protocol(value):
  630. return _supports_protocol_method(value, DELITEM_METHOD)
  631. def _is_abstract_class_name(name):
  632. lname = name.lower()
  633. is_mixin = lname.endswith('mixin')
  634. is_abstract = lname.startswith('abstract')
  635. is_base = lname.startswith('base') or lname.endswith('base')
  636. return is_mixin or is_abstract or is_base
  637. def is_inside_abstract_class(node):
  638. while node is not None:
  639. if isinstance(node, astroid.ClassDef):
  640. if class_is_abstract(node):
  641. return True
  642. name = getattr(node, 'name', None)
  643. if name is not None and _is_abstract_class_name(name):
  644. return True
  645. node = node.parent
  646. return False
  647. def _supports_protocol(value, protocol_callback):
  648. if isinstance(value, astroid.ClassDef):
  649. if not has_known_bases(value):
  650. return True
  651. # classobj can only be iterable if it has an iterable metaclass
  652. meta = value.metaclass()
  653. if meta is not None:
  654. if protocol_callback(meta):
  655. return True
  656. if isinstance(value, astroid.BaseInstance):
  657. if not has_known_bases(value):
  658. return True
  659. if value.has_dynamic_getattr():
  660. return True
  661. if protocol_callback(value):
  662. return True
  663. # TODO: this is not needed in astroid 2.0, where we can
  664. # check the type using a virtual base class instead.
  665. if (isinstance(value, _bases.Proxy)
  666. and isinstance(value._proxied, astroid.BaseInstance)
  667. and has_known_bases(value._proxied)):
  668. value = value._proxied
  669. return protocol_callback(value)
  670. return False
  671. def is_iterable(value):
  672. return _supports_protocol(value, _supports_iteration_protocol)
  673. def is_mapping(value):
  674. return _supports_protocol(value, _supports_mapping_protocol)
  675. def supports_membership_test(value):
  676. supported = _supports_protocol(value, _supports_membership_test_protocol)
  677. return supported or is_iterable(value)
  678. def supports_getitem(value):
  679. return _supports_protocol(value, _supports_getitem_protocol)
  680. def supports_setitem(value):
  681. return _supports_protocol(value, _supports_setitem_protocol)
  682. def supports_delitem(value):
  683. return _supports_protocol(value, _supports_delitem_protocol)
  684. # TODO(cpopa): deprecate these or leave them as aliases?
  685. @lru_cache(maxsize=1024)
  686. def safe_infer(node, context=None):
  687. """Return the inferred value for the given node.
  688. Return None if inference failed or if there is some ambiguity (more than
  689. one node has been inferred).
  690. """
  691. try:
  692. inferit = node.infer(context=context)
  693. value = next(inferit)
  694. except astroid.InferenceError:
  695. return None
  696. try:
  697. next(inferit)
  698. return None # None if there is ambiguity on the inferred node
  699. except astroid.InferenceError:
  700. return None # there is some kind of ambiguity
  701. except StopIteration:
  702. return value
  703. def has_known_bases(klass, context=None):
  704. """Return true if all base classes of a class could be inferred."""
  705. try:
  706. return klass._all_bases_known
  707. except AttributeError:
  708. pass
  709. for base in klass.bases:
  710. result = safe_infer(base, context=context)
  711. # TODO: check for A->B->A->B pattern in class structure too?
  712. if (not isinstance(result, astroid.ClassDef) or
  713. result is klass or
  714. not has_known_bases(result, context=context)):
  715. klass._all_bases_known = False
  716. return False
  717. klass._all_bases_known = True
  718. return True
  719. def is_none(node):
  720. return (node is None or
  721. (isinstance(node, astroid.Const) and node.value is None) or
  722. (isinstance(node, astroid.Name) and node.name == 'None')
  723. )
  724. def node_type(node):
  725. """Return the inferred type for `node`
  726. If there is more than one possible type, or if inferred type is YES or None,
  727. return None
  728. """
  729. # check there is only one possible type for the assign node. Else we
  730. # don't handle it for now
  731. types = set()
  732. try:
  733. for var_type in node.infer():
  734. if var_type == astroid.Uninferable or is_none(var_type):
  735. continue
  736. types.add(var_type)
  737. if len(types) > 1:
  738. return None
  739. except astroid.InferenceError:
  740. return None
  741. return types.pop() if types else None
  742. def is_registered_in_singledispatch_function(node):
  743. """Check if the given function node is a singledispatch function."""
  744. singledispatch_qnames = (
  745. 'functools.singledispatch',
  746. 'singledispatch.singledispatch'
  747. )
  748. if not isinstance(node, astroid.FunctionDef):
  749. return False
  750. decorators = node.decorators.nodes if node.decorators else []
  751. for decorator in decorators:
  752. # func.register are function calls
  753. if not isinstance(decorator, astroid.Call):
  754. continue
  755. func = decorator.func
  756. if not isinstance(func, astroid.Attribute) or func.attrname != 'register':
  757. continue
  758. try:
  759. func_def = next(func.expr.infer())
  760. except astroid.InferenceError:
  761. continue
  762. if isinstance(func_def, astroid.FunctionDef):
  763. return decorated_with(func_def, singledispatch_qnames)
  764. return False
  765. def get_node_last_lineno(node):
  766. """
  767. Get the last lineno of the given node. For a simple statement this will just be node.lineno,
  768. but for a node that has child statements (e.g. a method) this will be the lineno of the last
  769. child statement recursively.
  770. """
  771. # 'finalbody' is always the last clause in a try statement, if present
  772. if getattr(node, 'finalbody', False):
  773. return get_node_last_lineno(node.finalbody[-1])
  774. # For if, while, and for statements 'orelse' is always the last clause.
  775. # For try statements 'orelse' is the last in the absence of a 'finalbody'
  776. if getattr(node, 'orelse', False):
  777. return get_node_last_lineno(node.orelse[-1])
  778. # try statements have the 'handlers' last if there is no 'orelse' or 'finalbody'
  779. if getattr(node, 'handlers', False):
  780. return get_node_last_lineno(node.handlers[-1])
  781. # All compound statements have a 'body'
  782. if getattr(node, 'body', False):
  783. return get_node_last_lineno(node.body[-1])
  784. # Not a compound statement
  785. return node.lineno
  786. def in_comprehension(node):
  787. """Return True if the given node is in a comprehension"""
  788. curnode = node
  789. while curnode.parent:
  790. curnode = curnode.parent
  791. if is_comprehension(curnode):
  792. return True
  793. return False
  794. def is_enum_class(node):
  795. """Check if a class definition defines an Enum class.
  796. :param node: The class node to check.
  797. :type node: astroid.ClassDef
  798. :returns: True if the given node represents an Enum class. False otherwise.
  799. :rtype: bool
  800. """
  801. for base in node.bases:
  802. try:
  803. inferred_bases = base.inferred()
  804. except astroid.InferenceError:
  805. continue
  806. for ancestor in inferred_bases:
  807. if not isinstance(ancestor, astroid.ClassDef):
  808. continue
  809. if ancestor.name == 'Enum' and ancestor.root().name == 'enum':
  810. return True
  811. return False