Ejemplo n.º 1
0
def _transform_assert_false_into_raise(assertion):
    if isinstance(assertion.test, Const) and assertion.test.value is False:
        out = Raise(lineno=assertion.lineno,
                    col_offset=assertion.col_offset,
                    parent=assertion.parent)
        exc = Call(parent=out)
        if assertion.fail:
            args = [assertion.fail]
            args[0].parent = exc
        else:
            args = []
        exc.postinit(Name("AssertionError", parent=exc), args)
        out.postinit(exc, None)
        return out
    def visit_call(self, node: astroid.Call) -> None:
        f = self.type_constraints.resolve(node.func.inf_type)
        func_inf_type = self.get_call_signature(f, node.func)
        arg_inf_types = [arg.inf_type for arg in node.args]

        node.inf_type = self.type_constraints.unify_call(func_inf_type,
                                                         *arg_inf_types,
                                                         node=node)
Ejemplo n.º 3
0
    def _check_class_decorator(self, node: astroid.Call) -> None:
        """
        Verify the class decorator.

        :param node: the decorator node
        :return:
        """
        # Infer the decorator so that we resolve import aliases.
        try:
            decorator = next(node.infer())
        except astroid.exceptions.NameInferenceError:
            # Ignore uninferrable decorators
            return

        # Ignore decorators which could not be inferred.
        if decorator is astroid.Uninferable:
            return

        pytype = decorator.pytype()

        if pytype != 'icontract._decorators.invariant':
            return

        condition_node = self._find_condition_node(node=node)

        if condition_node is None:
            self.errors.append(
                Error(
                    identifier=ErrorID.NO_CONDITION,
                    description="The contract decorator lacks the condition.",
                    filename=self._filename,
                    lineno=node.lineno))
            return

        # Infer the condition so as to resolve functions by name etc.
        try:
            condition = next(condition_node.infer())
        except astroid.exceptions.NameInferenceError:
            # Ignore uninferrable conditions
            return

        assert isinstance(condition, (astroid.nodes.Lambda, astroid.nodes.FunctionDef)), \
            "Expected the inferred condition to be either a lambda or a function definition, but got: {}".format(
                condition)

        condition_args = condition.argnames()
        if condition_args != ['self']:
            self.errors.append(
                Error(
                    identifier=ErrorID.INV_INVALID_ARG,
                    description=
                    "An invariant expects one and only argument 'self', but the arguments are: {}"
                    .format(condition_args),
                    filename=self._filename,
                    lineno=node.lineno))
Ejemplo n.º 4
0
    def visit_call(self, node: astroid.Call) -> None:
        callable_t = node.func.inf_type.getValue()
        # Check if Union
        if hasattr(callable_t,
                   '__origin__') and callable_t.__origin__ is Union:
            is_union = True
        else:
            is_union = False

        if not isinstance(callable_t, (CallableMeta, list)) and not is_union:
            if isinstance(callable_t, _ForwardRef):
                func_name = callable_t.__forward_arg__
            else:
                func_name = callable_t.__args__[0].__name__
            if '__init__' in self.type_store.classes[func_name]:
                init_type = self.type_store.classes[func_name]['__init__'][0]
            else:
                init_type = Callable[[callable_t], None]
            # TODO: handle method overloading (through optional parameters)
            arg_types = [callable_t
                         ] + [arg.inf_type.getValue() for arg in node.args]
            # TODO: Check for number of arguments if function is an initializer
            type_result = self.type_constraints.unify_call(init_type,
                                                           *arg_types,
                                                           node=node)
            if isinstance(type_result, TypeFail):
                node.inf_type = type_result
            else:
                node.inf_type = TypeInfo(callable_t)
        else:
            # TODO: resolve this case (from method lookup) more gracefully
            if isinstance(callable_t, list):
                callable_t = callable_t[0]
                arg_types = [node.func.expr.inf_type.getValue()]
            else:
                arg_types = []
            arg_types += [arg.inf_type.getValue() for arg in node.args]
            node.inf_type = self.type_constraints.unify_call(callable_t,
                                                             *arg_types,
                                                             node=node)
Ejemplo n.º 5
0
    def visit_call(self, node: astroid.Call) -> None:
        func_inf_type = self.get_call_signature(node.func.inf_type, node.func)
        arg_inf_types = [arg.inf_type for arg in node.args]

        func_params = func_inf_type >> (lambda f: getattr(f, '__args__', [])) \
            if not isinstance(func_inf_type, TypeFail) else []
        for param, i in zip(func_params, range(len(arg_inf_types))):
            if isinstance(param, GenericMeta) and _gorg(param) is Iterable:
                arg_inf_types[i] = self._handle_call(node, '__iter__',
                                                     arg_inf_types[i])

        node.inf_type = self.type_constraints.unify_call(func_inf_type,
                                                         *arg_inf_types,
                                                         node=node)
Ejemplo n.º 6
0
 def visit_call(self, node: astroid.Call):
     if not _should_ignore(
             node.root().file) and _is_unittest_assert_raises(node):
         self.add_message(self.name, node=node)
Ejemplo n.º 7
0
    def visit_call(self, node: astroid.Call) -> None:
        f = self.type_constraints.resolve(node.func.inf_type)
        func_inf_type = self.get_call_signature(f, node.func)
        arg_inf_types = [arg.inf_type for arg in node.args]

        node.inf_type = self.type_constraints.unify_call(func_inf_type, *arg_inf_types, node=node)
Ejemplo n.º 8
0
def _should_ignore(node: astroid.Call):
    path = node.root().file
    return any(path.startswith(d) for d in IGNORE_DIRS)
    def _check_use_maxsplit_arg(self, node: astroid.Call) -> None:
        """Add message when accessing first or last elements of a str.split() or str.rsplit()."""

        # Check if call is split() or rsplit()
        if not (isinstance(node.func, astroid.Attribute)
                and node.func.attrname in ("split", "rsplit") and isinstance(
                    utils.safe_infer(node.func), astroid.BoundMethod)):
            return

        try:
            utils.get_argument_from_call(node, 0, "sep")
        except utils.NoSuchArgumentError:
            return

        try:
            # Ignore if maxsplit arg has been set
            utils.get_argument_from_call(node, 1, "maxsplit")
            return
        except utils.NoSuchArgumentError:
            pass

        if isinstance(node.parent, astroid.Subscript):
            try:
                subscript_value = utils.get_subscript_const_value(
                    node.parent).value
            except utils.InferredTypeError:
                return

            # Check for cases where variable (Name) subscripts may be mutated within a loop
            if isinstance(node.parent.slice, astroid.Name):
                # Check if loop present within the scope of the node
                scope = node.scope()
                for loop_node in scope.nodes_of_class(
                    (astroid.For, astroid.While)):
                    loop_node = cast(astroid.node_classes.NodeNG, loop_node)
                    if not loop_node.parent_of(node):
                        continue

                    # Check if var is mutated within loop (Assign/AugAssign)
                    for assignment_node in loop_node.nodes_of_class(
                            astroid.AugAssign):
                        assignment_node = cast(astroid.AugAssign,
                                               assignment_node)
                        if node.parent.slice.name == assignment_node.target.name:
                            return
                    for assignment_node in loop_node.nodes_of_class(
                            astroid.Assign):
                        assignment_node = cast(astroid.Assign, assignment_node)
                        if node.parent.slice.name in [
                                n.name for n in assignment_node.targets
                        ]:
                            return

            if subscript_value in (-1, 0):
                fn_name = node.func.attrname
                new_fn = "rsplit" if subscript_value == -1 else "split"
                new_name = (
                    node.func.as_string().rsplit(fn_name, maxsplit=1)[0] +
                    new_fn +
                    f"({node.args[0].as_string()}, maxsplit=1)[{subscript_value}]"
                )
                self.add_message("use-maxsplit-arg",
                                 node=node,
                                 args=(new_name, ))