def replace_decorators(node, capture, filename):
    """
    Replaces usage of ``@tornado.<etc>`` with ``@salt.ext.tornado.<etc>``
    """
    indent = find_indentation(node)

    decorator = _get_decorator(node)
    decorator.remove()

    decorated = Node(
        SYMBOL.decorated,
        [
            Node(
                SYMBOL.decorator,
                [
                    Leaf(TOKEN.AT, "@"),
                    Name("salt.ext.{}".format(get_decorator_name(decorator))),
                    Leaf(TOKEN.NEWLINE, "\n"),
                ],
            )
        ],
        prefix=decorator.prefix,
    )
    node.replace(decorated)
    decorated.append_child(node)

    if indent is not None:
        node.prefix = indent
    else:
        node.prefix = ""
Esempio n. 2
0
def split_suffix(leaf: Leaf) -> Tuple[str, str]:
    """Split a suffix node (a DEDENT with prefix) into two.

    The indentation of the leaf is discovered so that comments that
    are inline with the previous block remain part of the prefix.
    """
    indent = find_indentation(leaf)
    parts = leaf.prefix.split("\n")
    pre = []
    for part in parts:
        if not part.startswith(indent):
            break
        pre.append(part)
    # Insert \n at the beginning of everything
    parts = [parts[0]] + ["\n" + x for x in parts[1:]]
    pre, post = "".join(parts[:len(pre)]), "".join(parts[len(pre):])

    # If we have a pre but no newline, add/move one from post
    if pre and not pre.rstrip(" ").endswith("\n"):
        pre = pre + "\n"
        if post.startswith("\n"):
            post = post[1:]
    return pre, post
Esempio n. 3
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")
Esempio n. 4
0
def process_class(node: LN, capture: Capture,
                  filename: Filename) -> Optional[LN]:
    """Do the processing/modification of the class node"""
    print(f"Class for show(): {filename}:{node.get_lineno()}")

    suite = get_child(node, python_symbols.suite)
    # Get the suite indent
    indent = find_indentation(suite)

    # Find the show() function
    funcs = {
        x.children[1].value: x
        for x in get_children(suite, python_symbols.funcdef)
    }
    show_func = funcs["show"]
    # Get the name of the filename object keyword that this show uses
    show_keyword = analyse_show(show_func, filename)

    if show_keyword is None:
        # show() writes to stdout. Use Graeme's method for now.
        kludge_text = (
            f"def __str__(self):\n{indent}  return kludge_show_to_str(self)\n\n"
        )
    else:
        # We can more intelligently call show
        kludge_text = (f"def __str__(self):\n{indent}  out = StringIO()\n"
                       f"{indent}  self.show({show_keyword}=out)\n"
                       f"{indent}  return out.getvalue.rstrip()\n\n")

    # To avoid having to work out indent correction, just generate with correct
    kludge_node = get_child(driver.parse_string(kludge_text),
                            python_symbols.funcdef)

    # Work out if we have any trailing text/comments that need to be moved
    trail_node = get_trailing_text_node(suite)
    pre, post = split_suffix(trail_node)

    # The trailing contents of this node will be moved
    trail_node.prefix = pre

    # Get the dedent node at the end of the previous - suite always ends with dedent
    # This is the dedent before the end of the suite, so the one to alter for the new
    # function
    # If we aren't after a suite then we don't have a DEDENT so don't need to
    # correct the indentation.
    # children[-2] is the last statement at the end of the suite
    # children[-1] is the suite on a function definition
    # children[-1] is the dedent at the end of the function's suite
    if suite.children[-2].type == python_symbols.funcdef:
        last_func_dedent_node = suite.children[-2].children[-1].children[-1]
        last_func_dedent_node.prefix += "\n" + indent

    suite.children.insert(-1, kludge_node)

    # Get the kludge dedent - now the last dedent
    kludge_dedent = kludge_node.children[-1].children[-1]
    kludge_dedent.prefix = post

    # Make sure the functions used are available
    if show_keyword is None:
        touch_import("libtbx.utils", "kludge_show_to_str", node)
    else:
        touch_import("six.moves", "StringIO", node)