Skip to content

No rule for sequential write calls (for-loop-writes (FURB122)] matches loops only) despite claiming writelines is more idiomatic #24259

@Avasam

Description

@Avasam

Summary

for-loop-writes (FURB122) says

When writing a batch of elements, it's more idiomatic to use a single method call to IOBase.writelines, rather than write elements one by one.

That rule checks for write in loop, but sequential write calls, which match the exact same reasoning, are not flagged.

Given the following example, should either cases be caught?

import pathlib

# from
def foo(fname: str) -> None:
    with pathlib.Path(fname).open("w", encoding="utf-8") as output:
        output.write("a\n")
        output.write("b\n")
        output.write("c\n")
        for subtitle, suffix in (
            ("Overviews", "_overview"),
            ("Modules", "_modules"),
            ("Objects", "_objects"),
        ):
            output.write(f"{suffix} {subtitle}\n")
        output.write("d\n")

# to
def foo(fname: str) -> None:
    with pathlib.Path(fname).open("w", encoding="utf-8") as output:
        output.writelines(("a\n", "b\n", "c\n"))
        output.writelines(
            f"{suffix} {subtitle}\n"
            for subtitle, suffix in (
                ("Overviews", "_overview"),
                ("Modules", "_modules"),
                ("Objects", "_objects"),
            )
        )
        output.write("d\n")

# or even, if we take collection-literal-concatenation (RUF005) into account
def foo(fname: str) -> None:
    with pathlib.Path(fname).open("w", encoding="utf-8") as output:
        output.writelines(
            [
                "a\n",
                "b\n",
                "c\n",
                *[
                    f"{suffix} {subtitle}\n"
                    for subtitle, suffix in (
                        ("Overviews", "_overview"),
                        ("Modules", "_modules"),
                        ("Objects", "_objects"),
                    )
                ],
                "d\n",
            ]
        )

Playground: https://play.ruff.rs/18194c34-af39-462b-9633-0c0af9281da8


Or is maybe the description is not quite correct and

When writing a batch of elements [...]

is missing the specifier "already in iterable format (list, tuple, etc)".

For instance, I doubt that, in my case with a generator/list expression, that passing that to writelines is really that much better, especially if the implementation of writelines is just to loop over lines. I end up double looping.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-decisionAwaiting a decision from a maintainerruleImplementing or modifying a lint rule

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions