psf / black

The uncompromising Python code formatter
https://black.readthedocs.io/en/stable/
MIT License
38.58k stars 2.43k forks source link

`--line-ranges` formats lines outside of range #4430

Open rhencke opened 1 month ago

rhencke commented 1 month ago

Describe the bug

Black's --line-ranges option does not completely prevent reformatting of code outside of the specified line ranges.

To Reproduce

For example, take this code:

print("format me"  )
 # format whitespace
  # format whitespace
   # format whitespace
print( "format me" )
   # format whitespace
  # format whitespace
 # format whitespace
print(  "format me")

print("don't format me"  )
 # don't format whitespace
  # don't format whitespace
   # don't format whitespace
print( "don't format me" )
   # don't format whitespace
  # don't format whitespace
 # don't format whitespace
print(  "don't format me")

And run it with these arguments:

$ black --line-ranges 1-9 file.py

The result is:

print("format me")
# whitespace
# whitespace
# whitespace
print("format me")
# whitespace
# whitespace
# whitespace
print("format me")

print("don't format me"  )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print( "don't format me" )
# don't format whitespace
# don't format whitespace
# don't format whitespace
print(  "don't format me")

Expected behavior

The expected result would be the formatting constrains itself to lines 1 through 9, and does not modify whitespace outside of this line range:

print("format me")
# format whitespace
# format whitespace
# format whitespace
print("format me")
# format whitespace
# format whitespace
# format whitespace
print("format me")

print("don't format me"  )
 # don't format whitespace
  # don't format whitespace
   # don't format whitespace
print( "don't format me" )
   # don't format whitespace
  # don't format whitespace
 # don't format whitespace
print(  "don't format me")

Note both the three-line separation as well as the indentation would be preserved as they are outside of the line range 1-9.

Environment

Additional context

It would be useful for --line-ranges to only format what is contained within the specified line ranges, as much as possible, to allow for incremental adoption of formatting in larger code bases.

Typocalypse commented 1 month ago

This is clearly mentioned in the comments, `The prefix contains comments and indentation whitespaces. They are

reformatted accordingly to the correct indentation level.

# This also means the indentation will be changed on the unchanged lines, and
# this is actually required to not break incremental reformatting.`. Please refere to https://github.com/psf/black/blob/c20423249e9d8dfb8581eebbfc67a13984ee45e9/src/black/ranges.py#L306.
afontenot commented 1 month ago

I'm not sure I understand what the effect is. If I try to use line-ranges, should I expect comments to get modified

  1. everywhere in the file?
  2. anywhere at the same indentation level in the same block as modified code?
  3. only if the comment is "attached" to the code (for some definition of "attached")?
  4. something else?

If the answer is (2), I can provide a direct counterexample that would presumably demonstrate a bug. If (3) or (4), can more clarification be given? I don't know what a "prefix" is.

Typocalypse commented 3 weeks ago

@afontenot Black will first parse all the file contents, respecting the given line length. The prefix indicates the start of the first node/line. If the first node starts with # or whitespace, it will be reformatted according to the correct indentation level, based on the syntax in the preceding line. If you provide the whole file to Black or specify a line length, it will ensure the correct indentation is used throughout the entire file. Since Black first parses the entire file, maintaining correct indentation is particularly important. Please correct me if I'm wrong.