コード例 #1
0
def _infer_context_manager(self, mgr, context):
    inferred = next(mgr.infer(context=context))
    if isinstance(inferred, bases.Generator):
        # Check if it is decorated with contextlib.contextmanager.
        func = inferred.parent
        if not func.decorators:
            raise exceptions.InferenceError(
                "No decorators found on inferred generator %s", node=func
            )

        for decorator_node in func.decorators.nodes:
            decorator = next(decorator_node.infer(context=context))
            if isinstance(decorator, nodes.FunctionDef):
                if decorator.qname() == _CONTEXTLIB_MGR:
                    break
        else:
            # It doesn't interest us.
            raise exceptions.InferenceError(node=func)

        # Get the first yield point. If it has multiple yields,
        # then a RuntimeError will be raised.

        possible_yield_points = func.nodes_of_class(nodes.Yield)
        # Ignore yields in nested functions
        yield_point = next(
            (node for node in possible_yield_points if node.scope() == func), None
        )
        if yield_point:
            if not yield_point.value:
                const = nodes.Const(None)
                const.parent = yield_point
                const.lineno = yield_point.lineno
                yield const
            else:
                yield from yield_point.value.infer(context=context)
    elif isinstance(inferred, bases.Instance):
        try:
            enter = next(inferred.igetattr("__enter__", context=context))
        except (exceptions.InferenceError, exceptions.AttributeInferenceError):
            raise exceptions.InferenceError(node=inferred)
        if not isinstance(enter, bases.BoundMethod):
            raise exceptions.InferenceError(node=enter)
        yield from enter.infer_call_result(self, context)
    else:
        raise exceptions.InferenceError(node=mgr)
コード例 #2
0
def _infer_context_manager(self, mgr, context):
    try:
        inferred = next(mgr.infer(context=context))
    except exceptions.InferenceError:
        return
    if isinstance(inferred, bases.Generator):
        # Check if it is decorated with contextlib.contextmanager.
        func = inferred.parent
        if not func.decorators:
            return
        for decorator_node in func.decorators.nodes:
            decorator = next(decorator_node.infer(context))
            if isinstance(decorator, nodes.FunctionDef):
                if decorator.qname() == _CONTEXTLIB_MGR:
                    break
        else:
            # It doesn't interest us.
            return

        # Get the first yield point. If it has multiple yields,
        # then a RuntimeError will be raised.
        # TODO(cpopa): Handle flows.
        yield_point = next(func.nodes_of_class(nodes.Yield), None)
        if yield_point:
            if not yield_point.value:
                # TODO(cpopa): an empty yield. Should be wrapped to Const.
                const = nodes.Const(None)
                const.parent = yield_point
                const.lineno = yield_point.lineno
                yield const
            else:
                for inferred in yield_point.value.infer(context=context):
                    yield inferred
    elif isinstance(inferred, bases.Instance):
        try:
            enter = next(inferred.igetattr('__enter__', context=context))
        except (exceptions.InferenceError, exceptions.AttributeInferenceError):
            return
        if not isinstance(enter, bases.BoundMethod):
            return
        if not context.callcontext:
            context.callcontext = contextmod.CallContext(args=[inferred])
        for result in enter.infer_call_result(self, context):
            yield result
コード例 #3
0
def infer_issubclass(callnode, context=None):
    """Infer issubclass() calls

    :param nodes.Call callnode: an `issubclass` call
    :param InferenceContext: the context for the inference
    :rtype nodes.Const: Boolean Const value of the `issubclass` call
    :raises UseInferenceDefault: If the node cannot be inferred
    """
    call = arguments.CallSite.from_call(callnode, context=context)
    if call.keyword_arguments:
        # issubclass doesn't support keyword arguments
        raise UseInferenceDefault("TypeError: issubclass() takes no keyword arguments")
    if len(call.positional_arguments) != 2:
        raise UseInferenceDefault(
            "Expected two arguments, got {count}".format(
                count=len(call.positional_arguments)
            )
        )
    # The left hand argument is the obj to be checked
    obj_node, class_or_tuple_node = call.positional_arguments

    try:
        obj_type = next(obj_node.infer(context=context))
    except InferenceError as exc:
        raise UseInferenceDefault from exc
    if not isinstance(obj_type, nodes.ClassDef):
        raise UseInferenceDefault("TypeError: arg 1 must be class")

    # The right hand argument is the class(es) that the given
    # object is to be checked against.
    try:
        class_container = _class_or_tuple_to_container(
            class_or_tuple_node, context=context
        )
    except InferenceError as exc:
        raise UseInferenceDefault from exc
    try:
        issubclass_bool = helpers.object_issubclass(obj_type, class_container, context)
    except AstroidTypeError as exc:
        raise UseInferenceDefault("TypeError: " + str(exc)) from exc
    except MroError as exc:
        raise UseInferenceDefault from exc
    return nodes.Const(issubclass_bool)
コード例 #4
0
def const_infer_binary_op(self, opnode, operator, other, context, _):
    not_implemented = nodes.Const(NotImplemented)
    if isinstance(other, nodes.Const):
        try:
            impl = BIN_OP_IMPL[operator]
            try:
                yield nodes.const_factory(impl(self.value, other.value))
            except TypeError:
                # ArithmeticError is not enough: float >> float is a TypeError
                yield not_implemented
            except Exception:  # pylint: disable=broad-except
                yield util.Uninferable
        except TypeError:
            yield not_implemented
    elif isinstance(self.value, six.string_types) and operator == '%':
        # TODO(cpopa): implement string interpolation later on.
        yield util.Uninferable
    else:
        yield not_implemented
コード例 #5
0
ファイル: inference.py プロジェクト: Andrewou2010/webview
def instance_getitem(self, index, context=None):
    # Rewrap index to Const for this case
    index = nodes.Const(index)
    if context:
        new_context = context.clone()
    else:
        context = new_context = contextmod.InferenceContext()

    # Create a new callcontext for providing index as an argument.
    new_context.callcontext = contextmod.CallContext(args=[index])
    new_context.boundnode = self

    method = next(self.igetattr('__getitem__', context=context))
    if not isinstance(method, bases.BoundMethod):
        raise exceptions.InferenceError

    try:
        return next(method.infer_call_result(self, new_context))
    except StopIteration:
        raise exceptions.InferenceError
コード例 #6
0
def infer_len(node, context=None):
    """Infer length calls

    :param nodes.Call node: len call to infer
    :param context.InferenceContext: node context
    :rtype nodes.Const: a Const node with the inferred length, if possible
    """
    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault("TypeError: len() must take no keyword arguments")
    if len(call.positional_arguments) != 1:
        raise UseInferenceDefault(
            "TypeError: len() must take exactly one argument "
            "({len}) given".format(len=len(call.positional_arguments))
        )
    [argument_node] = call.positional_arguments
    try:
        return nodes.Const(helpers.object_len(argument_node, context=context))
    except (AstroidTypeError, InferenceError) as exc:
        raise UseInferenceDefault(str(exc)) from exc
コード例 #7
0
def infer_callable(node, context=None):
    """Understand callable calls

    This follows Python's semantics, where an object
    is callable if it provides an attribute __call__,
    even though that attribute is something which can't be
    called.
    """
    if len(node.args) != 1:
        # Invalid callable call.
        raise UseInferenceDefault

    argument = node.args[0]
    try:
        inferred = next(argument.infer(context=context))
    except InferenceError:
        return util.Uninferable
    if inferred is util.Uninferable:
        return util.Uninferable
    return nodes.Const(inferred.callable())
コード例 #8
0
ファイル: rebuilder.py プロジェクト: Andrewou2010/webview
 def visit_name(self, node, parent, assign_ctx=None):
     """visit a Name node by returning a fresh instance of it"""
     # True and False can be assigned to something in py2x, so we have to
     # check first the asscontext
     # pylint: disable=redefined-variable-type
     if assign_ctx == "Del":
         newnode = new.DelName()
     elif assign_ctx is not None: # Ass
         newnode = new.AssName()
     elif node.id in CONST_NAME_TRANSFORMS:
         newnode = new.Const(CONST_NAME_TRANSFORMS[node.id])
         _set_infos(node, newnode, parent)
         return newnode
     else:
         newnode = new.Name()
     _lineno_parent(node, newnode, parent)
     newnode.name = node.id
     # XXX REMOVE me :
     if assign_ctx in ('Del', 'Assign'): # 'Aug' ??
         self._save_assignment(newnode)
     return newnode
コード例 #9
0
 def visit_name(self, node, parent):
     """visit a Name node by returning a fresh instance of it"""
     # True and False can be assigned to something in py2x, so we have to
     # check first the asscontext
     if self.asscontext == "Del":
         newnode = new.DelName()
     elif self.asscontext is not None: # Ass
         assert self.asscontext == "Ass"
         newnode = new.AssName()
     elif node.id in CONST_NAME_TRANSFORMS:
         newnode = new.Const(CONST_NAME_TRANSFORMS[node.id])
         _set_infos(node, newnode, parent)
         return newnode
     else:
         newnode = new.Name()
     _lineno_parent(node, newnode, parent)
     newnode.name = node.id
     # XXX REMOVE me :
     if self.asscontext in ('Del', 'Ass'): # 'Aug' ??
         self._save_assignment(newnode)
     return newnode
コード例 #10
0
def tl_infer_binary_op(
    self,
    opnode: nodes.BinOp,
    operator: str,
    other: nodes.NodeNG,
    context: InferenceContext,
    method: nodes.FunctionDef,
) -> Generator[nodes.NodeNG | type[util.Uninferable], None, None]:
    """Infer a binary operation on a tuple or list.

    The instance on which the binary operation is performed is a tuple
    or list. This refers to the left-hand side of the operation, so:
    'tuple() + 1' or '[] + A()'
    """
    # For tuples and list the boundnode is no longer the tuple or list instance
    context.boundnode = None
    not_implemented = nodes.Const(NotImplemented)
    if isinstance(other, self.__class__) and operator == "+":
        node = self.__class__(parent=opnode)
        node.elts = list(
            itertools.chain(
                _filter_uninferable_nodes(self.elts, context),
                _filter_uninferable_nodes(other.elts, context),
            ))
        yield node
    elif isinstance(other, nodes.Const) and operator == "*":
        if not isinstance(other.value, int):
            yield not_implemented
            return
        yield _multiply_seq_by_int(self, opnode, other, context)
    elif isinstance(other, bases.Instance) and operator == "*":
        # Verify if the instance supports __index__.
        as_index = helpers.class_instance_as_index(other)
        if not as_index:
            yield util.Uninferable
        else:
            yield _multiply_seq_by_int(self, opnode, as_index, context)
    else:
        yield not_implemented
コード例 #11
0
def infer_isinstance(callnode, context=None):
    """Infer isinstance calls

    :param nodes.Call callnode: an isinstance call
    :param InferenceContext: context for call
        (currently unused but is a common interface for inference)
    :rtype nodes.Const: Boolean Const value of isinstance call

    :raises UseInferenceDefault: If the node cannot be inferred
    """
    call = arguments.CallSite.from_call(callnode, context=context)
    if call.keyword_arguments:
        # isinstance doesn't support keyword arguments
        raise UseInferenceDefault("TypeError: isinstance() takes no keyword arguments")
    if len(call.positional_arguments) != 2:
        raise UseInferenceDefault(
            "Expected two arguments, got {count}".format(
                count=len(call.positional_arguments)
            )
        )
    # The left hand argument is the obj to be checked
    obj_node, class_or_tuple_node = call.positional_arguments
    # The right hand argument is the class(es) that the given
    # obj is to be check is an instance of
    try:
        class_container = _class_or_tuple_to_container(
            class_or_tuple_node, context=context
        )
    except InferenceError as exc:
        raise UseInferenceDefault from exc
    try:
        isinstance_bool = helpers.object_isinstance(obj_node, class_container, context)
    except AstroidTypeError as exc:
        raise UseInferenceDefault("TypeError: " + str(exc)) from exc
    except MroError as exc:
        raise UseInferenceDefault from exc
    if isinstance_bool is util.Uninferable:
        raise UseInferenceDefault
    return nodes.Const(isinstance_bool)
コード例 #12
0
ファイル: protocols.py プロジェクト: tcwz/astroid
def _resolve_asspart(parts, asspath, context):
    """recursive function to resolve multiple assignments"""
    asspath = asspath[:]
    index = asspath.pop(0)
    for part in parts:
        assigned = None
        if isinstance(part, nodes.Dict):
            # A dictionary in an iterating context
            try:
                assigned, _ = part.items[index]
            except IndexError:
                return

        elif hasattr(part, 'getitem'):
            index_node = nodes.Const(index)
            try:
                assigned = part.getitem(index_node, context)
            # XXX raise a specific exception to avoid potential hiding of
            # unexpected exception ?
            except (exceptions.AstroidTypeError, exceptions.AstroidIndexError):
                return

        if not assigned:
            return

        if not asspath:
            # we achieved to resolved the assignment path, don't infer the
            # last part
            yield assigned
        elif assigned is util.Uninferable:
            return
        else:
            # we are not yet on the last part of the path search on each
            # possibly inferred value
            try:
                yield from _resolve_asspart(assigned.infer(context), asspath,
                                            context)
            except exceptions.InferenceError:
                return
コード例 #13
0
def tl_infer_binary_op(self, opnode, operator, other, context, method):
    not_implemented = nodes.Const(NotImplemented)
    if isinstance(other, self.__class__) and operator == '+':
        node = self.__class__(parent=opnode)
        elts = list(_filter_uninferable_nodes(self.elts, context))
        elts += list(_filter_uninferable_nodes(other.elts, context))
        node.elts = elts
        yield node
    elif isinstance(other, nodes.Const) and operator == '*':
        if not isinstance(other.value, int):
            yield not_implemented
            return
        yield _multiply_seq_by_int(self, opnode, other, context)
    elif isinstance(other, bases.Instance) and operator == '*':
        # Verify if the instance supports __index__.
        as_index = helpers.class_instance_as_index(other)
        if not as_index:
            yield util.Uninferable
        else:
            yield _multiply_seq_by_int(self, opnode, as_index, context)
    else:
        yield not_implemented
コード例 #14
0
 def visit_name(self, node, parent):
     """visit a Name node by returning a fresh instance of it"""
     context = self._get_context(node)
     # True and False can be assigned to something in py2x, so we have to
     # check first the context.
     if context == astroid.Del:
         newnode = nodes.DelName(node.id, node.lineno, node.col_offset,
                                 parent)
     elif context == astroid.Store:
         newnode = nodes.AssignName(node.id, node.lineno, node.col_offset,
                                    parent)
     elif node.id in CONST_NAME_TRANSFORMS:
         newnode = nodes.Const(CONST_NAME_TRANSFORMS[node.id],
                               getattr(node, 'lineno', None),
                               getattr(node, 'col_offset', None), parent)
         return newnode
     else:
         newnode = nodes.Name(node.id, node.lineno, node.col_offset, parent)
     # XXX REMOVE me :
     if context in (astroid.Del, astroid.Store):  # 'Aug' ??
         self._save_assignment(newnode)
     return newnode
コード例 #15
0
def _resolve_looppart(parts, assign_path, context):
    """recursive function to resolve multiple assignments on loops"""
    assign_path = assign_path[:]
    index = assign_path.pop(0)
    for part in parts:
        if part is util.Uninferable:
            continue
        if not hasattr(part, "itered"):
            continue
        try:
            itered = part.itered()
        except TypeError:
            continue
        for stmt in itered:
            index_node = nodes.Const(index)
            try:
                assigned = stmt.getitem(index_node, context)
            except (
                AttributeError,
                exceptions.AstroidTypeError,
                exceptions.AstroidIndexError,
            ):
                continue
            if not assign_path:
                # we achieved to resolved the assignment path,
                # don't infer the last part
                yield assigned
            elif assigned is util.Uninferable:
                break
            else:
                # we are not yet on the last part of the path
                # search on each possibly inferred value
                try:
                    yield from _resolve_looppart(
                        assigned.infer(context), assign_path, context
                    )
                except exceptions.InferenceError:
                    break
コード例 #16
0
 def test_cls_special_attributes_1(self):
     cls = MODULE['YO']
     self.assertEqual(len(cls.getattr('__bases__')), 1)
     self.assertEqual(len(cls.getattr('__name__')), 1)
     self.assertIsInstance(cls.getattr('__name__')[0], nodes.Const)
     self.assertEqual(cls.getattr('__name__')[0].value, 'YO')
     self.assertEqual(len(cls.getattr('__doc__')), 1)
     self.assertIsInstance(cls.getattr('__doc__')[0], nodes.Const)
     self.assertEqual(cls.getattr('__doc__')[0].value, 'hehe')
     self.assertEqual(len(cls.getattr('__module__')), 1)
     self.assertIsInstance(cls.getattr('__module__')[0], nodes.Const)
     self.assertEqual(cls.getattr('__module__')[0].value, 'data.module')
     self.assertEqual(len(cls.getattr('__dict__')), 1)
     if not cls.newstyle:
         self.assertRaises(NotFoundError, cls.getattr, '__mro__')
     for cls in (nodes.List._proxied, nodes.Const(1)._proxied):
         self.assertEqual(len(cls.getattr('__bases__')), 1)
         self.assertEqual(len(cls.getattr('__name__')), 1)
         self.assertEqual(len(cls.getattr('__doc__')), 1, (cls, cls.getattr('__doc__')))
         self.assertEqual(cls.getattr('__doc__')[0].value, cls.doc)
         self.assertEqual(len(cls.getattr('__module__')), 1)
         self.assertEqual(len(cls.getattr('__dict__')), 1)
         self.assertEqual(len(cls.getattr('__mro__')), 1)
コード例 #17
0
def _infer_compare(self: nodes.Compare,
                   context: Optional[InferenceContext] = None) -> Any:
    """Chained comparison inference logic."""
    retval = True

    ops = self.ops
    left_node = self.left
    lhs = list(left_node.infer(context=context))
    # should we break early if first element is uninferable?
    for op, right_node in ops:
        # eagerly evaluate rhs so that values can be re-used as lhs
        rhs = list(right_node.infer(context=context))
        try:
            retval = _do_compare(lhs, op, rhs)
        except AstroidTypeError:
            retval = util.Uninferable
            break
        if retval is not True:
            break  # short-circuit
        lhs = rhs  # continue
    if retval is util.Uninferable:
        yield retval
    else:
        yield nodes.Const(retval)
コード例 #18
0
 def test_copy(self):
     """
     Make sure copying a Const object doesn't result in infinite recursion
     """
     const = copy.copy(nodes.Const(1))
     assert const.value == 1
コード例 #19
0
 def visit_nameconstant(self, node, parent):
     # in Python 3.4 we have NameConstant for True / False / None
     return nodes.Const(node.value, getattr(node, 'lineno', None),
                        getattr(node, 'col_offset', None), parent)
コード例 #20
0
 def visit_num(self, node, parent):
     """visit a Num node by returning a fresh instance of Const"""
     return nodes.Const(node.n, getattr(node, 'lineno', None),
                        getattr(node, 'col_offset', None), parent)
コード例 #21
0
 def visit_str(self, node, parent):
     """visit a String/Bytes node by returning a fresh instance of Const"""
     return nodes.Const(node.s, getattr(node, 'lineno', None),
                        getattr(node, 'col_offset', None), parent)
コード例 #22
0
 def visit_constant(self, node, parent):
     """visit a Constant node by returning a fresh instance of Const"""
     return nodes.Const(node.value, getattr(node, 'lineno', None),
                        getattr(node, 'col_offset', None), parent)
コード例 #23
0
def infer_dict_fromkeys(node, context=None):
    """Infer dict.fromkeys

    :param nodes.Call node: dict.fromkeys() call to infer
    :param context.InferenceContext: node context
    :rtype nodes.Dict:
        a Dictionary containing the values that astroid was able to infer.
        In case the inference failed for any reason, an empty dictionary
        will be inferred instead.
    """
    def _build_dict_with_elements(elements):
        new_node = nodes.Dict(col_offset=node.col_offset,
                              lineno=node.lineno,
                              parent=node.parent)
        new_node.postinit(elements)
        return new_node

    call = arguments.CallSite.from_call(node, context=context)
    if call.keyword_arguments:
        raise UseInferenceDefault(
            "TypeError: int() must take no keyword arguments")
    if len(call.positional_arguments) not in {1, 2}:
        raise UseInferenceDefault(
            "TypeError: Needs between 1 and 2 positional arguments")

    default = nodes.Const(None)
    values = call.positional_arguments[0]
    try:
        inferred_values = next(values.infer(context=context))
    except InferenceError:
        return _build_dict_with_elements([])
    if inferred_values is util.Uninferable:
        return _build_dict_with_elements([])

    # Limit to a couple of potential values, as this can become pretty complicated
    accepted_iterable_elements = (nodes.Const, )
    if isinstance(inferred_values, (nodes.List, nodes.Set, nodes.Tuple)):
        elements = inferred_values.elts
        for element in elements:
            if not isinstance(element, accepted_iterable_elements):
                # Fallback to an empty dict
                return _build_dict_with_elements([])

        elements_with_value = [(element, default) for element in elements]
        return _build_dict_with_elements(elements_with_value)

    elif isinstance(inferred_values, nodes.Const) and isinstance(
            inferred_values.value, (str, bytes)):
        elements = [(nodes.Const(element), default)
                    for element in inferred_values.value]
        return _build_dict_with_elements(elements)
    elif isinstance(inferred_values, nodes.Dict):
        keys = inferred_values.itered()
        for key in keys:
            if not isinstance(key, accepted_iterable_elements):
                # Fallback to an empty dict
                return _build_dict_with_elements([])

        elements_with_value = [(element, default) for element in keys]
        return _build_dict_with_elements(elements_with_value)

    # Fallback to an empty dictionary
    return _build_dict_with_elements([])
コード例 #24
0
ファイル: unittest_python3.py プロジェクト: wogsland/astroid
 def test_unpacking_in_dict_getitem(self):
     node = extract_node('{1:2, **{2:3, 3:4}, **{5: 6}}')
     for key, expected in ((1, 2), (2, 3), (3, 4), (5, 6)):
         value = node.getitem(nodes.Const(key))
         self.assertIsInstance(value, nodes.Const)
         self.assertEqual(value.value, expected)
コード例 #25
0
 def test_genexpr(node):
     if node.elt.value == 1:
         node.elt = nodes.Const(2, node.lineno, node.col_offset,
                                node.parent)
         return node
     return None
コード例 #26
0
 def visit_num(self, node, parent):
     """visit a Num node by returning a fresh instance of Const"""
     newnode = new.Const(node.n)
     _set_infos(node, newnode, parent)
     return newnode
コード例 #27
0
 def visit_nameconstant(self, node, parent):
     # in Python 3.4 we have NameConstant for True / False / None
     newnode = new.Const(node.value)
     _set_infos(node, newnode, parent)
     return newnode
コード例 #28
0
def _patch_uuid_class(node):
    # The .int member is patched using __dict__
    node.locals["int"] = [nodes.Const(0, parent=node)]
コード例 #29
0
 def visit_str(self, node, parent):
     """visit a Str node by returning a fresh instance of Const"""
     newnode = new.Const(node.s)
     _set_infos(node, newnode, parent)
     return newnode
コード例 #30
0
    def _check_new_format_specifiers(self, node, fields, named):
        """
        Check attribute and index access in the format
        string ("{0.a}" and "{0[a]}").
        """
        for key, specifiers in fields:
            # Obtain the argument. If it can't be obtained
            # or inferred, skip this check.
            if key == "":
                # {[0]} will have an unnamed argument, defaulting
                # to 0. It will not be present in `named`, so use the value
                # 0 for it.
                key = 0
            if isinstance(key, numbers.Number):
                try:
                    argname = utils.get_argument_from_call(node, key)
                except utils.NoSuchArgumentError:
                    continue
            else:
                if key not in named:
                    continue
                argname = named[key]
            if argname in (astroid.Uninferable, None):
                continue
            try:
                argument = utils.safe_infer(argname)
            except astroid.InferenceError:
                continue
            if not specifiers or not argument:
                # No need to check this key if it doesn't
                # use attribute / item access
                continue
            if argument.parent and isinstance(argument.parent,
                                              nodes.Arguments):
                # Ignore any object coming from an argument,
                # because we can't infer its value properly.
                continue
            previous = argument
            parsed = []
            for is_attribute, specifier in specifiers:
                if previous is astroid.Uninferable:
                    break
                parsed.append((is_attribute, specifier))
                if is_attribute:
                    try:
                        previous = previous.getattr(specifier)[0]
                    except astroid.NotFoundError:
                        if (hasattr(previous, "has_dynamic_getattr")
                                and previous.has_dynamic_getattr()):
                            # Don't warn if the object has a custom __getattr__
                            break
                        path = get_access_path(key, parsed)
                        self.add_message(
                            "missing-format-attribute",
                            args=(specifier, path),
                            node=node,
                        )
                        break
                else:
                    warn_error = False
                    if hasattr(previous, "getitem"):
                        try:
                            previous = previous.getitem(nodes.Const(specifier))
                        except (
                                astroid.AstroidIndexError,
                                astroid.AstroidTypeError,
                                astroid.AttributeInferenceError,
                        ):
                            warn_error = True
                        except astroid.InferenceError:
                            break
                        if previous is astroid.Uninferable:
                            break
                    else:
                        try:
                            # Lookup __getitem__ in the current node,
                            # but skip further checks, because we can't
                            # retrieve the looked object
                            previous.getattr("__getitem__")
                            break
                        except astroid.NotFoundError:
                            warn_error = True
                    if warn_error:
                        path = get_access_path(key, parsed)
                        self.add_message("invalid-format-index",
                                         args=(specifier, path),
                                         node=node)
                        break

                try:
                    previous = next(previous.infer())
                except astroid.InferenceError:
                    # can't check further if we can't infer it
                    break