--line-ranges puts the next statement inside the comment after a comment only fmt: off block · Issue #5524 · psf/black · GitHub
Skip to content

--line-ranges puts the next statement inside the comment after a comment only fmt: off block #5524

Closed

Description

@jiteshgulati

Describe the bug

When a # fmt: off / # fmt: on block has only comments in it and the statement right after it is outside the lines given to --line-ranges black glues that statement onto the # fmt: on line so it ends up inside the comment

With --fast the code is just gone while black still reports the file as reformatted and exits 0. Without --fast the safety check catches it and you get an internal error instead

To Reproduce

For example take this code in settings.py

# fmt: off
#---------+---------#
#  name   |  value  #
#---------+---------#
# fmt: on
TIMEOUT = 30
retries  =  3

And run it with these arguments

$ black --fast --line-ranges 7-7 settings.py
reformatted settings.py

The file now looks like this

# fmt: off
#---------+---------#
#  name   |  value  #
#---------+---------#
# fmt: onTIMEOUT = 30
retries = 3

so TIMEOUT doesn't exist anymore and import settings; settings.TIMEOUT raises AttributeError

Without --fast the same command gives

error: cannot format settings.py: INTERNAL ERROR: Black ... produced code that is not equivalent to the source

If the block is inside a function or class body (statement after it is return 1 or debug = True) it fails even with --fast with produced invalid code since the body ends up empty

Expected behavior

Only line 7 should change (retries = 3) and everything outside the range should be left as it is

Environment

  • Black's version: main (11cff13)
  • OS and Python version: Linux (WSL2) / Python 3.14.7

Additional context

From what I can tell _handle_comment_only_fmt_block in comments.py takes the newline after the # fmt: on line out of the next leaf's prefix and the line ranges code then writes the unselected statement back with str(node) which puts both on one line. #5477 added a newline in _str_with_standalone_comments for this kind of thing but only when the comment ends with # fmt: skip so comment only fmt off blocks still hit it

This is also why some lines of the existing fmtonoff.py and fmtskip11.py test cases fail when formatted with --line-ranges

I have a fix with tests ready and can open a PR for it

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions