Skip to content

format-on-write launches ruff without the stdin marker, so a .py write can reformat the whole directory #1069

Description

@Vasanthdev2004

What happens

With ZERO_FORMAT_ON_WRITE=1, writing any .py file launches ruff without the argument that tells it to read standard input, and with its working directory set to the written file's own directory. Ruff's stdin marker is a trailing -; --stdin-filename only names the input. With no path argument and no -, ruff format formats the current directory, which is documented ("ruff format (format current directory)").

So a single-file write can rewrite every .py file in that directory and below, while the tool reports one file written.

Where

internal/tools/format_on_write.go, the .py entry of formatterCommands:

".py": {argv: []string{"ruff", "format", "--quiet"}, stdin: true, filenameFlag: "--stdin-filename"},

and formatWithStdin, which sets formatter.Dir to the destination's directory.

Measured

Recorded from the real launch on main at 99721c7, with a recording shim standing in for ruff, writing pkg/new_file.py into a workspace where pkg/already_here.py already exists:

ARGV  format --quiet --stdin-filename=...\pkg\new_file.py
CWD   ...\pkg

No - anywhere in the argv, and the working directory is the one holding the neighbouring file.

There is a second effect. Under --quiet ruff prints nothing to stdout in that mode, so the written file is published unformatted and the call reports success, which is why this does not show up as a formatting failure.

Suggested fix

Add - to the .py argv, after the flags, so ruff reads the bytes it is given:

".py": {argv: []string{"ruff", "format", "--quiet", "-"}, stdin: true, filenameFlag: "--stdin-filename"},

.tf and .lua already pass - for the same reason, and .zig, .gleam and .kt pass --stdin.

While there: dart format has no - either. That one errors out rather than reaching for the directory, so it fails the format and publishes the written bytes, but it means .dart files are never actually formatted.

A regression test wants to assert the argv each stdin adapter is launched with, rather than only that formatting happened, since a formatter acting on its working directory still looks like success from the outside.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions