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.

helpers.py 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
  2. # Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
  3. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  4. # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
  5. """
  6. Various helper utilities.
  7. """
  8. import six
  9. from astroid import bases
  10. from astroid import context as contextmod
  11. from astroid import exceptions
  12. from astroid import manager
  13. from astroid import nodes
  14. from astroid import raw_building
  15. from astroid import scoped_nodes
  16. from astroid import util
  17. BUILTINS = six.moves.builtins.__name__
  18. def _build_proxy_class(cls_name, builtins):
  19. proxy = raw_building.build_class(cls_name)
  20. proxy.parent = builtins
  21. return proxy
  22. def _function_type(function, builtins):
  23. if isinstance(function, scoped_nodes.Lambda):
  24. if function.root().name == BUILTINS:
  25. cls_name = 'builtin_function_or_method'
  26. else:
  27. cls_name = 'function'
  28. elif isinstance(function, bases.BoundMethod):
  29. if six.PY2:
  30. cls_name = 'instancemethod'
  31. else:
  32. cls_name = 'method'
  33. elif isinstance(function, bases.UnboundMethod):
  34. if six.PY2:
  35. cls_name = 'instancemethod'
  36. else:
  37. cls_name = 'function'
  38. return _build_proxy_class(cls_name, builtins)
  39. def _object_type(node, context=None):
  40. astroid_manager = manager.AstroidManager()
  41. builtins = astroid_manager.astroid_cache[BUILTINS]
  42. context = context or contextmod.InferenceContext()
  43. for inferred in node.infer(context=context):
  44. if isinstance(inferred, scoped_nodes.ClassDef):
  45. if inferred.newstyle:
  46. metaclass = inferred.metaclass()
  47. if metaclass:
  48. yield metaclass
  49. continue
  50. yield builtins.getattr('type')[0]
  51. elif isinstance(inferred, (scoped_nodes.Lambda, bases.UnboundMethod)):
  52. yield _function_type(inferred, builtins)
  53. elif isinstance(inferred, scoped_nodes.Module):
  54. yield _build_proxy_class('module', builtins)
  55. else:
  56. yield inferred._proxied
  57. def object_type(node, context=None):
  58. """Obtain the type of the given node
  59. This is used to implement the ``type`` builtin, which means that it's
  60. used for inferring type calls, as well as used in a couple of other places
  61. in the inference.
  62. The node will be inferred first, so this function can support all
  63. sorts of objects, as long as they support inference.
  64. """
  65. try:
  66. types = set(_object_type(node, context))
  67. except exceptions.InferenceError:
  68. return util.Uninferable
  69. if len(types) > 1 or not types:
  70. return util.Uninferable
  71. return list(types)[0]
  72. def safe_infer(node, context=None):
  73. """Return the inferred value for the given node.
  74. Return None if inference failed or if there is some ambiguity (more than
  75. one node has been inferred).
  76. """
  77. try:
  78. inferit = node.infer(context=context)
  79. value = next(inferit)
  80. except exceptions.InferenceError:
  81. return None
  82. try:
  83. next(inferit)
  84. return None # None if there is ambiguity on the inferred node
  85. except exceptions.InferenceError:
  86. return None# there is some kind of ambiguity
  87. except StopIteration:
  88. return value
  89. def has_known_bases(klass, context=None):
  90. """Return true if all base classes of a class could be inferred."""
  91. try:
  92. return klass._all_bases_known
  93. except AttributeError:
  94. pass
  95. for base in klass.bases:
  96. result = safe_infer(base, context=context)
  97. # TODO: check for A->B->A->B pattern in class structure too?
  98. if (not isinstance(result, scoped_nodes.ClassDef) or
  99. result is klass or
  100. not has_known_bases(result, context=context)):
  101. klass._all_bases_known = False
  102. return False
  103. klass._all_bases_known = True
  104. return True
  105. def _type_check(type1, type2):
  106. if not all(map(has_known_bases, (type1, type2))):
  107. raise exceptions._NonDeducibleTypeHierarchy
  108. if not all([type1.newstyle, type2.newstyle]):
  109. return False
  110. try:
  111. return type1 in type2.mro()[:-1]
  112. except exceptions.MroError:
  113. # The MRO is invalid.
  114. raise exceptions._NonDeducibleTypeHierarchy
  115. def is_subtype(type1, type2):
  116. """Check if *type1* is a subtype of *typ2*."""
  117. return _type_check(type2, type1)
  118. def is_supertype(type1, type2):
  119. """Check if *type2* is a supertype of *type1*."""
  120. return _type_check(type1, type2)
  121. def class_instance_as_index(node):
  122. """Get the value as an index for the given instance.
  123. If an instance provides an __index__ method, then it can
  124. be used in some scenarios where an integer is expected,
  125. for instance when multiplying or subscripting a list.
  126. """
  127. context = contextmod.InferenceContext()
  128. context.callcontext = contextmod.CallContext(args=[node])
  129. try:
  130. for inferred in node.igetattr('__index__', context=context):
  131. if not isinstance(inferred, bases.BoundMethod):
  132. continue
  133. for result in inferred.infer_call_result(node, context=context):
  134. if (isinstance(result, nodes.Const)
  135. and isinstance(result.value, int)):
  136. return result
  137. except exceptions.InferenceError:
  138. pass
  139. return None