Exemple #1
0
    def visit_Call(self, node):
        positional_final_wildcard = False
        for i, n in enumerate(node.args):
            if astcheck.is_ast_like(n, ast.Name(id=MULTIWILDCARD_NAME)):
                if i + 1 == len(node.args):
                    # Last positional argument - wildcard may extend to kwargs
                    positional_final_wildcard = True

                node.args = (self._visit_list(node.args[:i]) +
                             astcheck.listmiddle() +
                             self._visit_list(node.args[i + 1:]))

                # Don't try to handle multiple multiwildcards
                break

        kwargs_are_subset = False
        if positional_final_wildcard and node.starargs is None:
            del node.starargs  # Accept any (or none) *args
            # f(a, ??) -> wildcarded kwargs as well
            kwargs_are_subset = True

        if kwargs_are_subset or any(k.arg == MULTIWILDCARD_NAME
                                    for k in node.keywords):
            template_keywords = [
                self.visit(k) for k in node.keywords
                if k.arg != MULTIWILDCARD_NAME
            ]

            def kwargs_checker(sample_keywords, path):
                sample_kwargs = {k.arg: k.value for k in sample_keywords}

                for k in template_keywords:
                    if k.arg == MULTIWILDCARD_NAME:
                        continue
                    if k.arg in sample_kwargs:
                        astcheck.assert_ast_like(sample_kwargs[k.arg], k.value,
                                                 path + [k.arg])
                    else:
                        raise astcheck.ASTMismatch(path, "(missing)",
                                                   "keyword arg %s" % k.arg)

            if template_keywords:
                node.keywords = kwargs_checker
            else:
                # Shortcut if there are no keywords to check
                del node.keywords

            # Accepting arbitrary keywords, so don't check absence of **kwargs
            if node.kwargs is None:
                del node.kwargs

        # In block contexts, we want to avoid checking empty lists (for optional
        # nodes), but here, an empty list should mean that there are no
        # arguments in that group. So we need to override the behaviour in
        # generic_visit
        if node.args == []:
            node.args = must_not_exist_checker
        if getattr(node, "keywords", None) == []:
            node.keywords = must_not_exist_checker
        return self.generic_visit(node)
Exemple #2
0
    def scan_ast(self, tree):
        """Walk an AST and yield nodes matching pattern.

        :param ast.AST tree: The AST in which to search
        """
        nodetype = type(self.pattern)
        for node in ast.walk(tree):
            if isinstance(node, nodetype) and astcheck.is_ast_like(node, self.pattern):
                yield node
Exemple #3
0
 def _is_multiwildcard(n):
     return astcheck.is_ast_like(
         n, ast.Expr(value=ast.Name(id=MULTIWILDCARD_NAME)))