|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- # Copyright (c) 2015-2016 Cara Vinson <ceridwenv@gmail.com>
- # Copyright (c) 2015-2016 Claudiu Popa <pcmanticore@gmail.com>
-
- # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
- # For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER
-
-
- """
- Various helper utilities.
- """
-
- import six
-
- from astroid import bases
- from astroid import context as contextmod
- from astroid import exceptions
- from astroid import manager
- from astroid import nodes
- from astroid import raw_building
- from astroid import scoped_nodes
- from astroid import util
-
-
- BUILTINS = six.moves.builtins.__name__
-
-
- def _build_proxy_class(cls_name, builtins):
- proxy = raw_building.build_class(cls_name)
- proxy.parent = builtins
- return proxy
-
-
- def _function_type(function, builtins):
- if isinstance(function, scoped_nodes.Lambda):
- if function.root().name == BUILTINS:
- cls_name = 'builtin_function_or_method'
- else:
- cls_name = 'function'
- elif isinstance(function, bases.BoundMethod):
- if six.PY2:
- cls_name = 'instancemethod'
- else:
- cls_name = 'method'
- elif isinstance(function, bases.UnboundMethod):
- if six.PY2:
- cls_name = 'instancemethod'
- else:
- cls_name = 'function'
- return _build_proxy_class(cls_name, builtins)
-
-
- def _object_type(node, context=None):
- astroid_manager = manager.AstroidManager()
- builtins = astroid_manager.astroid_cache[BUILTINS]
- context = context or contextmod.InferenceContext()
-
- for inferred in node.infer(context=context):
- if isinstance(inferred, scoped_nodes.ClassDef):
- if inferred.newstyle:
- metaclass = inferred.metaclass()
- if metaclass:
- yield metaclass
- continue
- yield builtins.getattr('type')[0]
- elif isinstance(inferred, (scoped_nodes.Lambda, bases.UnboundMethod)):
- yield _function_type(inferred, builtins)
- elif isinstance(inferred, scoped_nodes.Module):
- yield _build_proxy_class('module', builtins)
- else:
- yield inferred._proxied
-
-
- def object_type(node, context=None):
- """Obtain the type of the given node
-
- This is used to implement the ``type`` builtin, which means that it's
- used for inferring type calls, as well as used in a couple of other places
- in the inference.
- The node will be inferred first, so this function can support all
- sorts of objects, as long as they support inference.
- """
-
- try:
- types = set(_object_type(node, context))
- except exceptions.InferenceError:
- return util.Uninferable
- if len(types) > 1 or not types:
- return util.Uninferable
- return list(types)[0]
-
-
- def safe_infer(node, context=None):
- """Return the inferred value for the given node.
-
- Return None if inference failed or if there is some ambiguity (more than
- one node has been inferred).
- """
- try:
- inferit = node.infer(context=context)
- value = next(inferit)
- except exceptions.InferenceError:
- return None
- try:
- next(inferit)
- return None # None if there is ambiguity on the inferred node
- except exceptions.InferenceError:
- return None# there is some kind of ambiguity
- except StopIteration:
- return value
-
-
- def has_known_bases(klass, context=None):
- """Return true if all base classes of a class could be inferred."""
- try:
- return klass._all_bases_known
- except AttributeError:
- pass
- for base in klass.bases:
- result = safe_infer(base, context=context)
- # TODO: check for A->B->A->B pattern in class structure too?
- if (not isinstance(result, scoped_nodes.ClassDef) or
- result is klass or
- not has_known_bases(result, context=context)):
- klass._all_bases_known = False
- return False
- klass._all_bases_known = True
- return True
-
-
- def _type_check(type1, type2):
- if not all(map(has_known_bases, (type1, type2))):
- raise exceptions._NonDeducibleTypeHierarchy
-
- if not all([type1.newstyle, type2.newstyle]):
- return False
- try:
- return type1 in type2.mro()[:-1]
- except exceptions.MroError:
- # The MRO is invalid.
- raise exceptions._NonDeducibleTypeHierarchy
-
-
- def is_subtype(type1, type2):
- """Check if *type1* is a subtype of *typ2*."""
- return _type_check(type2, type1)
-
-
- def is_supertype(type1, type2):
- """Check if *type2* is a supertype of *type1*."""
- return _type_check(type1, type2)
-
-
- def class_instance_as_index(node):
- """Get the value as an index for the given instance.
-
- If an instance provides an __index__ method, then it can
- be used in some scenarios where an integer is expected,
- for instance when multiplying or subscripting a list.
- """
- context = contextmod.InferenceContext()
- context.callcontext = contextmod.CallContext(args=[node])
-
- try:
- for inferred in node.igetattr('__index__', context=context):
- if not isinstance(inferred, bases.BoundMethod):
- continue
-
- for result in inferred.infer_call_result(node, context=context):
- if (isinstance(result, nodes.Const)
- and isinstance(result.value, int)):
- return result
- except exceptions.InferenceError:
- pass
- return None
|