def rename()

in bowler/query.py [0:0]


    def rename(self, new_name: str) -> "Query":
        transform = self.current
        old_name = transform.kwargs["name"]

        def rename_transform(node: LN, capture: Capture, filename: Filename) -> None:
            log.debug(f"{filename} [{list(capture)}]: {node}")

            # If two keys reference the same underlying object, do not modify it twice
            visited: List[LN] = []
            for _key, value in capture.items():
                log.debug(f"{_key}: {value}")
                if value in visited:
                    continue
                visited.append(value)

                if isinstance(value, Leaf) and value.type == TOKEN.NAME:
                    if value.value == old_name and value.parent is not None:
                        value.replace(Name(new_name, prefix=value.prefix))
                        break
                elif isinstance(value, Node):
                    if type_repr(value.type) == "dotted_name":
                        dp_old = dotted_parts(old_name)
                        dp_new = dotted_parts(new_name)
                        parts = zip(dp_old, dp_new, value.children)
                        for old, new, leaf in parts:
                            if old != leaf.value:
                                break
                            if old != new:
                                leaf.replace(Name(new, prefix=leaf.prefix))

                        if len(dp_new) < len(dp_old):
                            # if new path is shorter, remove excess children
                            del value.children[len(dp_new) : len(dp_old)]
                        elif len(dp_new) > len(dp_old):
                            # if new path is longer, add new children
                            children = [
                                Name(new) for new in dp_new[len(dp_old) : len(dp_new)]
                            ]
                            value.children[len(dp_old) : len(dp_old)] = children

                    elif type_repr(value.type) == "power":
                        # We don't actually need the '.' so just skip it
                        dp_old = old_name.split(".")
                        dp_new = new_name.split(".")

                        for old, new, leaf in zip(dp_old, dp_new, value.children):
                            if isinstance(leaf, Node):
                                name_leaf = leaf.children[1]
                            else:
                                name_leaf = leaf
                            if old != name_leaf.value:
                                break
                            name_leaf.replace(Name(new, prefix=name_leaf.prefix))

                        if len(dp_new) < len(dp_old):
                            # if new path is shorter, remove excess children
                            del value.children[len(dp_new) : len(dp_old)]
                        elif len(dp_new) > len(dp_old):
                            # if new path is longer, add new trailers in the middle
                            for i in range(len(dp_old), len(dp_new)):
                                value.insert_child(
                                    i, Node(SYMBOL.trailer, [Dot(), Name(dp_new[i])])
                                )

        transform.callbacks.append(rename_transform)
        return self