Exemplo n.º 1
0
    def tree_matches(self, template):
        if is_ast_like(self.tree, ast.parse(template)):
            return True

        if is_ast_like(ast.parse(self.input.lower()),
                       ast.parse(template.lower())):
            return dict(
                message=
                "Python is case sensitive! That means that small and capital letters "
                "matter and changing them changes the meaning of the program. The strings "
                "`'hello'` and `'Hello'` are different, as are the variable names "
                "`word` and `Word`.")
Exemplo n.º 2
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)
Exemplo n.º 3
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
Exemplo n.º 4
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
Exemplo n.º 5
0
def search_ast(node, template, predicate=lambda n: True):
    """
    Returns the number of descendants of `node` that match `template`
    (either a type or tuple that is passed to `isinstance`,
    or a partial AST that is passed to `is_ast_like`)
    and satisfy the optional predicate.
    """
    return sum(
        (isinstance(child, template) if isinstance(template, (
            type, tuple)) else is_ast_like(child, template))
        and predicate(child) and child != node for child in ast.walk(node))
Exemplo n.º 6
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)
Exemplo n.º 7
0
def immunise_setuptools():
    ei_file = easy_install.__file__
    if not os.access(ei_file, os.R_OK|os.W_OK):
        print("Don't have access to {}, not changing".format(ei_file))
        return

    # Don't try this at home
    lines, first_line_no = inspect.getsourcelines(
                easy_install.PthDistributions.save)

    mod = ast.parse("".join(lines).lstrip())
    pattern = ast.Assign(targets=[ast.Name(id='data')],
                  value=ast.BinOp(left=ast.Str(), op=ast.Mod(),
                              right=ast.Name(id='data')))
    for astpath, node in _walk_with_path(mod):
        if astcheck.is_ast_like(node, pattern):
            break
    else:
        print("Leaving easy_install module untouched")
        return

    starting_line = first_line_no + node.lineno - 1

    parent = _resolve_ast_path(astpath[:-2], mod)  # -2 for ('body', ix)
    if astpath[-1] == len(parent.body) - 1:
        print("PthDistributions.save not as expected, leaving untouched")
        return

    print("Immunising", ei_file)
    next_node = parent.body[astpath[-1]+1]
    finishing_line = first_line_no + next_node.lineno - 1
    print("Cut lines:", starting_line, finishing_line)

    with open(ei_file) as f:
        contents = f.readlines()

    #print(contents[starting_line-1:finishing_line-1])
    contents[starting_line-1:finishing_line-1] = []

    with open(ei_file, 'w') as f:
        f.writelines(contents)
Exemplo n.º 8
0
def search_ast(node, template):
    return any(is_ast_like(child, template) for child in ast.walk(node))
Exemplo n.º 9
0
 def truncated_trees_match(self, input_tree, program_tree):
     input_tree = ast.Module(
         body=input_tree.body[:len(program_tree.body)],
         type_ignores=[],
     )
     return is_ast_like(input_tree, program_tree)
Exemplo n.º 10
0
 def test_matching(self):
     assert_ast_like(sample1, template1)
     assert is_ast_like(sample1, template1)
     assert_ast_like(sample2, template2)
     assert is_ast_like(sample2, template2)
Exemplo n.º 11
0
 def test_name_or_attr_correct(self):
     assert_ast_like(sample4, template4)
     assert is_ast_like(sample4, template4)
Exemplo n.º 12
0
 def test_matching(self):
     assert_ast_like(sample3, template3)
     assert is_ast_like(sample3, template3)
     assert isinstance(template3.body.front[0], ast.Delete)
     assert isinstance(template3.body.back[0], ast.Delete)
Exemplo n.º 13
0
 def test_wrong_plain_list(self):
     with self.assertRaisesRegexp(astcheck.ASTPlainListMismatch, re.escape("Expected: ['x', 'y']")):
         assert_ast_like(sample2, template2_wronglist)
     assert not is_ast_like(sample2, template2_wronglist)
Exemplo n.º 14
0
 def test_wrong_plain_value(self):
     with self.assertRaisesRegexp(astcheck.ASTPlainObjMismatch, "'d' instead of 'e'"):
         assert_ast_like(sample1, template1_wrongvalue)
     assert not is_ast_like(sample1, template1_wrongvalue)
Exemplo n.º 15
0
 def truncated_trees_match(self, input_tree, program_tree):
     del input_tree.body[len(program_tree.body):]
     return is_ast_like(input_tree, program_tree)
Exemplo n.º 16
0
 def _is_multiwildcard(n):
     return astcheck.is_ast_like(
         n, ast.Expr(value=ast.Name(id=MULTIWILDCARD_NAME)))
Exemplo n.º 17
0
 def test_wrongnode(self):
     with self.assertRaises(astcheck.ASTNodeTypeMismatch):
         assert_ast_like(sample1, template1_wrongnode)
     assert not is_ast_like(sample1, template1_wrongnode)
Exemplo n.º 18
0
 def test_wrong_nodelist(self):
     with self.assertRaisesRegexp(astcheck.ASTNodeListMismatch, re.escape("5 node(s) instead of 4")):
         assert_ast_like(sample1, template1_wrongnodelist)
     assert not is_ast_like(sample1, template1_wrongnodelist)
Exemplo n.º 19
0
 def check(self):
     return (is_ast_like(
         self.tree,
         ast.Module(
             body=[ast.Assign(targets=[ast.Name(id='your_name')])]))
             and isinstance(self.console.locals.get('your_name'), str))
Exemplo n.º 20
0
 def _is_multiwildcard(n):
     return astcheck.is_ast_like(n,
                     ast.Expr(value=ast.Name(id=MULTIWILDCARD_NAME)))