Ejemplo n.º 1
0
def _make_bare_import_node(name: str, trailing_nl: bool = False) -> Node:
    assert name  # non-empty
    children = [
        Leaf(token.NAME, "import"),
        Leaf(token.NAME, name, prefix=" "),
        Newline(),
    ]
    if trailing_nl:
        children.append(Newline())
    return Node(
        syms.import_name,
        children,
    )
Ejemplo n.º 2
0
def _make_from_import_node(left: str,
                           right: Sequence[str],
                           trailing_nl: bool = False) -> Node:
    assert right  # non-empty
    name_leaves = [Leaf(token.NAME, right[0], prefix=" ")]
    name_leaves.extend(
        Leaf(token.NAME, name, prefix=", ") for name in right[1:])
    children = [
        Leaf(token.NAME, "from"),
        Leaf(token.NAME, left, prefix=" "),
        Leaf(token.NAME, "import", prefix=" "),
        Node(syms.import_as_names, name_leaves),
        Newline(),
    ]
    if trailing_nl:
        children.append(Newline())
    return Node(syms.import_from, children)
Ejemplo n.º 3
0
def newline_node(node):
    """
    Find a NEWLINE node from AST tree, and clone it to create a new NEWLINE node.
    So we don't need to care about os platform.
    if no NEWLINE node found in AST tree, create a new NEWLINE node according to os platform.
    """
    global _newline_node
    if _newline_node is None:
        p = node
        while p is not None and p.parent is not None:
            p = p.parent
        if p is not None:
            for leaf in p.leaves():
                if leaf.type == token.NEWLINE:
                    _newline_node = leaf
                    break
        if _newline_node is None:
            if is_windows:
                _newline_node = Newline(value="\r\n")
            else:
                _newline_node = Newline()
    return _newline_node.clone()
Ejemplo n.º 4
0
def remove_success_expectations(node, capture, filename):
    """
    We're about to remove the 'success' return value of all the helpers,
    and just let them pytest.fail() themselves.

    So we need to remove where tests are expecting them to return 'success'.

    if x() != 'success':
        return 'fail'

    --> x()
    """

    if capture['returntype'].type not in (TOKEN.STRING, TOKEN.NAME):
        return

    if capture['x'].type == TOKEN.NAME:
        # `if ret == 'success'`.
        # We can just remove this.

        if (capture['returntype'] == TOKEN.NAME
                and capture['returntype'].value != capture['x'].value):
            # not sure what this is doing? leave it alone.
            return

        # Trailing whitespace and any comments after the if statement are captured
        # in the prefix for the dedent node. Copy it to the following node.
        dedent = capture["dedent"]
        next_node = node.next_sibling
        node.remove()
        next_node.prefix = dedent.prefix
    elif capture['x'].type == syms.power:
        # is a function call. call it, just discard the result.
        if capture['returntype'].type == TOKEN.NAME:
            # not sure what this is doing? leave it alone
            return
        func = capture['x'].clone()
        func.prefix = node.prefix

        # Trailing whitespace and any comments after the if statement are captured
        # in the prefix for the dedent node. Copy it to the following node.
        dedent = capture["dedent"]
        next_node = node.next_sibling
        node.replace([func, Newline()])
        next_node.prefix = dedent.prefix
    else:
        print(capture['x'])
        raise ValueError("unknown type")
Ejemplo n.º 5
0
def replace_unicode_methods(node, capture, arguments):

    # remove any existing __str__ method
    b = find_binding("__str__", capture['suite'])
    if b and b.type == syms.funcdef:
        b.remove()

    # rename __unicode__ to __str__
    funcname = capture['funcname'].clone()
    funcname.value = '__str__'
    capture['funcname'].replace(funcname)

    # Add a six import
    touch_import(None, "six", node)

    # Decorate the class with `@six.python_2_unicode_compatible`
    classdef = node.clone()
    classdef.prefix = ''
    decorated = Node(
        syms.decorated,
        [
            Node(
                syms.decorator,
                [
                    Leaf(TOKEN.AT, '@', prefix=node.prefix),
                    Node(
                        syms.dotted_name,
                        [
                            Name('six'),
                            Dot(),
                            Name('python_2_unicode_compatible')
                        ],
                    ),
                    Newline(),
                ],
                prefix=node.prefix,
            ),
            classdef,
        ],
        prefix=node.prefix,
    )
    node.replace(decorated)
Ejemplo n.º 6
0
def replace_if_with_assert(if_node, dedent_node, assert_node):
    # Trailing whitespace and any comments after the if statement are captured
    # in the prefix for the dedent node. Copy it to the following node.
    next_node = if_node.next_sibling
    if_node.replace([assert_node, Newline()])
    next_node.prefix = dedent_node.prefix

    message_nodes = assert_node.children[3:]

    if message_nodes:
        # If one line, and it's longer than LONG_LINE, make a basic attempt to split before the message
        lines = str(assert_node).splitlines()
        original_num_long_lines = sum(1 for line in lines
                                      if len(line) > LONG_LINE)

        if original_num_long_lines:
            # First, clone the original.
            assert_node, split_assert = assert_node.clone(), assert_node

            # now insert a newline after the comma
            reason_node = message_nodes[0]
            reason_node.prefix = f" \\\n{find_indentation(split_assert)}    {reason_node.prefix.lstrip(' ')}"
Ejemplo n.º 7
0
    def transform(self, node, results):
        # First, find the sys import. We'll just hope it's global scope.
        if "sys_import" in results:
            if self.sys_import is None:
                self.sys_import = results["sys_import"]
            return

        func = results["func"].clone()
        func.prefix = ""
        register = pytree.Node(syms.power, Attr(Name("atexit"), Name("register")))
        call = Call(register, [func], node.prefix)
        node.replace(call)

        if self.sys_import is None:
            # That's interesting.
            self.warning(
                node,
                "Can't find sys import; Please add an atexit "
                "import at the top of your file.",
            )
            return

        # Now add an atexit import after the sys import.
        names = self.sys_import.children[1]
        if names.type == syms.dotted_as_names:
            names.append_child(Comma())
            names.append_child(Name("atexit", " "))
        else:
            containing_stmt = self.sys_import.parent
            position = containing_stmt.children.index(self.sys_import)
            stmt_container = containing_stmt.parent
            new_import = pytree.Node(
                syms.import_name, [Name("import"), Name("atexit", " ")]
            )
            new = pytree.Node(syms.simple_stmt, [new_import])
            containing_stmt.insert_child(position + 1, Newline())
            containing_stmt.insert_child(position + 2, new)
Ejemplo n.º 8
0
    def transform_member(self, node, results):
        """Transform for imports of specific module elements. Replaces
        the module to be imported from with the appropriate new
        module.
        """
        mod_member = results.get("mod_member")
        pref = mod_member.prefix
        member = results.get("member")

        # Simple case with only a single member being imported
        if member:
            # this may be a list of length one, or just a node
            if isinstance(member, list):
                member = member[0]
            new_name = None
            for change in MAPPING[mod_member.value]:
                if member.value in change[1]:
                    new_name = change[0]
                    break
            if new_name:
                mod_member.replace(Name(new_name, prefix=pref))
            else:
                self.cannot_convert(node, "This is an invalid module element")

        # Multiple members being imported
        else:
            # a dictionary for replacements, order matters
            modules = []
            mod_dict = {}
            members = results["members"]
            for member in members:
                # we only care about the actual members
                if member.type == syms.import_as_name:
                    as_name = member.children[2].value
                    member_name = member.children[0].value
                else:
                    member_name = member.value
                    as_name = None
                if member_name != ",":
                    for change in MAPPING[mod_member.value]:
                        if member_name in change[1]:
                            if change[0] not in mod_dict:
                                modules.append(change[0])
                            mod_dict.setdefault(change[0], []).append(member)

            new_nodes = []
            indentation = find_indentation(node)
            first = True

            def handle_name(name, prefix):
                if name.type == syms.import_as_name:
                    kids = [
                        Name(name.children[0].value, prefix=prefix),
                        name.children[1].clone(),
                        name.children[2].clone(),
                    ]
                    return [Node(syms.import_as_name, kids)]
                return [Name(name.value, prefix=prefix)]

            for module in modules:
                elts = mod_dict[module]
                names = []
                for elt in elts[:-1]:
                    names.extend(handle_name(elt, pref))
                    names.append(Comma())
                names.extend(handle_name(elts[-1], pref))
                new = FromImport(module, names)
                if not first or node.parent.prefix.endswith(indentation):
                    new.prefix = indentation
                new_nodes.append(new)
                first = False
            if new_nodes:
                nodes = []
                for new_node in new_nodes[:-1]:
                    nodes.extend([new_node, Newline()])
                nodes.append(new_nodes[-1])
                node.replace(nodes)
            else:
                self.cannot_convert(node, "All module elements are invalid")
Ejemplo n.º 9
0
        def encapsulate_transform(
            node: LN, capture: Capture, filename: Filename
        ) -> None:
            if "attr_assignment" in capture:
                leaf = capture["attr_name"]
                leaf.replace(Name(new_name, prefix=leaf.prefix))

                if make_property:
                    # TODO: capture and use type annotation from original assignment

                    class_node = get_class(node)
                    suite = find_first(class_node, SYMBOL.suite)
                    assert isinstance(suite, Node)
                    indent_node = find_first(suite, TOKEN.INDENT)
                    assert isinstance(indent_node, Leaf)
                    indent = indent_node.value

                    getter = Node(
                        SYMBOL.decorated,
                        [
                            Node(
                                SYMBOL.decorator,
                                [
                                    Leaf(TOKEN.AT, "@"),
                                    Name("property"),
                                    Leaf(TOKEN.NEWLINE, "\n"),
                                ],
                            ),
                            Node(
                                SYMBOL.funcdef,
                                [
                                    Name("def", indent),
                                    Name(old_name, prefix=" "),
                                    Node(
                                        SYMBOL.parameters,
                                        [LParen(), Name("self"), RParen()],
                                    ),
                                    Leaf(TOKEN.COLON, ":"),
                                    Node(
                                        SYMBOL.suite,
                                        [
                                            Newline(),
                                            Leaf(TOKEN.INDENT, indent.value + "    "),
                                            Node(
                                                SYMBOL.simple_stmt,
                                                [
                                                    Node(
                                                        SYMBOL.return_stmt,
                                                        [
                                                            Name("return"),
                                                            Node(
                                                                SYMBOL.power,
                                                                Attr(
                                                                    Name("self"),
                                                                    Name(new_name),
                                                                ),
                                                                prefix=" ",
                                                            ),
                                                        ],
                                                    ),
                                                    Newline(),
                                                ],
                                            ),
                                            Leaf(TOKEN.DEDENT, "\n" + indent),
                                        ],
                                    ),
                                ],
                                prefix=indent,
                            ),
                        ],
                    )

                    setter = Node(
                        SYMBOL.decorated,
                        [
                            Node(
                                SYMBOL.decorator,
                                [
                                    Leaf(TOKEN.AT, "@"),
                                    Node(
                                        SYMBOL.dotted_name,
                                        [Name(old_name), Dot(), Name("setter")],
                                    ),
                                    Leaf(TOKEN.NEWLINE, "\n"),
                                ],
                            ),
                            Node(
                                SYMBOL.funcdef,
                                [
                                    Name("def", indent),
                                    Name(old_name, prefix=" "),
                                    Node(
                                        SYMBOL.parameters,
                                        [
                                            LParen(),
                                            Node(
                                                SYMBOL.typedargslist,
                                                [
                                                    Name("self"),
                                                    Comma(),
                                                    Name("value", prefix=" "),
                                                ],
                                            ),
                                            RParen(),
                                        ],
                                    ),
                                    Leaf(TOKEN.COLON, ":"),
                                    Node(
                                        SYMBOL.suite,
                                        [
                                            Newline(),
                                            Leaf(TOKEN.INDENT, indent + "    "),
                                            Node(
                                                SYMBOL.simple_stmt,
                                                [
                                                    Node(
                                                        SYMBOL.expr_stmt,
                                                        [
                                                            Node(
                                                                SYMBOL.power,
                                                                Attr(
                                                                    Name("self"),
                                                                    Name(new_name),
                                                                ),
                                                            ),
                                                            Leaf(
                                                                TOKEN.EQUAL,
                                                                "=",
                                                                prefix=" ",
                                                            ),
                                                            Name("value", prefix=" "),
                                                        ],
                                                    ),
                                                    Newline(),
                                                ],
                                            ),
                                            Leaf(TOKEN.DEDENT, "\n" + indent),
                                        ],
                                    ),
                                ],
                                prefix=indent,
                            ),
                        ],
                    )

                    suite.insert_child(-1, getter)
                    suite.insert_child(-1, setter)

                    prev = find_previous(getter, TOKEN.DEDENT, recursive=True)
                    curr = find_last(setter, TOKEN.DEDENT, recursive=True)
                    assert isinstance(prev, Leaf) and isinstance(curr, Leaf)
                    prev.prefix, curr.prefix = curr.prefix, prev.prefix
                    prev.value, curr.value = curr.value, prev.value
Ejemplo n.º 10
0
def make_pytest_raises_blocks(node, capture, filename):
    """
    Turns this:

        try:
            ...
            pytest.fail(...)
        except:
            pass

    Into:
        with pytest.raises(Exception):
            ...

    Not only is this prettier, but the former is a bug since
    pytest.fail() raises an exception.
    """

    exc_class = capture.get('exc_class', None)

    if exc_class:
        exc_class = exc_class.clone()
        exc_class.prefix = ''
        raises_args = [exc_class]
    else:
        raises_args = [kw('Exception', prefix='')]

    reason = capture.get('reason')
    if reason:
        assert len(reason) == 1
        reason = KeywordArg(kw('message'), reason[0].clone())
        raises_args = [Node(syms.arglist, raises_args + [Comma(), reason])]

    raises_args = [LParen()] + raises_args + [RParen()]

    capture['fail_stmt'].remove()

    try_suite = capture['try_suite'].clone()

    with_stmt = Node(
        syms.with_stmt,
        [
            kw('with', prefix=''),
            Node(
                syms.power,
                [
                    kw('pytest'),
                    Node(syms.trailer, [Dot(), kw('raises', prefix='')]),
                    Node(syms.trailer, raises_args),
                ],
            ),
            Leaf(TOKEN.COLON, ':'),
            try_suite,
        ],
        prefix=node.prefix,
    )

    # Trailing whitespace and any comments after the if statement are captured
    # in the prefix for the dedent node. Copy it to the following node.
    dedent = capture["dedent"]
    next_node = node.next_sibling

    # This extra newline avoids syntax errors in some cases (where the try
    # statement is at the end of another suite)
    # I don't really know why those occur.
    # Should clean this stuff up with `black` later.
    node.replace([with_stmt, Newline()])
    next_node.prefix = dedent.prefix