google / yapf

A formatter for Python files
Apache License 2.0
13.7k stars 888 forks source link

continuation_align_style=FIXED causes wrong indentation for dictionary layer 2 indentation #968

Open spaceone opened 2 years ago

spaceone commented 2 years ago
[style]
based_on_style=pep8
continuation_align_style=FIXED

reformats:

class CLI(object):
    def __init__(self):
        self.modes = { 
            'request': self.request,
            'response': self.response,
            'parse': {
                'request': self.parse_request,
                'response': self.parse_response,
            }   
        } 

into:

class CLI(object):
    def __init__(self):
        self.modes = {
            'request': self.request,
            'response': self.response,
            'parse': {
            'request': self.parse_request,
            'response': self.parse_response,
            }
        }

(nothing should be changed at all)

spaceone commented 2 years ago

in FormatDecisionState._AddTokenOnNewline() a wrong indent level is used (self.line.depth)

Traceback (most recent call last):
  File "/home//.local/bin/yapf", line 8, in <module>
    sys.exit(run_main())
  File "/home//.local/lib/python3.9/site-packages/yapf/__init__.py", line 362, in run_main
    sys.exit(main(sys.argv))
  File "/home//.local/lib/python3.9/site-packages/yapf/__init__.py", line 126, in main
    changed = FormatFiles(
  File "/home//.local/lib/python3.9/site-packages/yapf/__init__.py", line 204, in FormatFiles
    changed |= _FormatFile(filename, lines, style_config, no_local_style,
  File "/home//.local/lib/python3.9/site-packages/yapf/__init__.py", line 227, in _FormatFile
    reformatted_code, encoding, has_change = yapf_api.FormatFile(
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/yapf_api.py", line 94, in FormatFile
    reformatted_source, changed = FormatCode(
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/yapf_api.py", line 166, in FormatCode
    reformatted_source = reformatter.Reformat(
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/reformatter.py", line 94, in Reformat
    if not _AnalyzeSolutionSpace(state):
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/reformatter.py", line 508, in _AnalyzeSolutionSpace
    _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node)
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/reformatter.py", line 560, in _ReconstructPath
    initial_state.AddTokenToState(newline=node.newline, dry_run=False)
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/format_decision_state.py", line 583, in AddTokenToState
    penalty = self._AddTokenOnNewline(dry_run, must_split)
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/format_decision_state.py", line 657, in _AddTokenOnNewline
    current.AddWhitespacePrefix(
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/format_token.py", line 169, in AddWhitespacePrefix
    indent_before = '\t' * indent_level + _TabbedContinuationAlignPadding(
  File "/home//.local/lib/python3.9/site-packages/yapf/yapflib/format_token.py", line 78, in _TabbedContinuationAlignPadding
    return '\t' * int((spaces + tab_width - 1) / tab_width)
spaceone commented 2 years ago

I think

 928   def _IndentWithContinuationAlignStyle(self, column):
…
 932     if align_style == 'FIXED':
 933       return ((self.line.depth * style.Get('INDENT_WIDTH')) +
 934               style.Get('CONTINUATION_INDENT_WIDTH'))

should return what 'VALIGN-RIGHT' does.

AlexanderWirthSAP commented 2 months ago

Any updates on this? I have the same issue. Fixed indentation to me does not mean "Do not indent past the first level", but it seems that this is how yapf handles it at the moment.

In a nested dict and similar nested expressions I want a fixed indentation per logical level. Possibly this could be done with a new setting for continuation_align_style if the behavior of "fixed" is deemed correct and should remain backwards-compatible.

My issue with the default continuation_align_style is mostly that it sometimes indents very far if the intial line break is near the end of the line.

Example: existing_data = spark.createDataFrame([(1, 12, date(2024, 1, 28)),(1, 13, date(2024, 2, 10)),(1, 10, date(2023, 5, 11)),],StructType([StructField("note", IntegerType(), True),StructField("count", IntegerType(), True),StructField("calculated_on", DateType(), True)]))

With default align style:

[style]
based_on_style = yapf
column_limit = 120
indent_width = 4
    existing_data = spark.createDataFrame([
        (1, 12, date(2024, 1, 28)),
        (1, 13, date(2024, 2, 10)),
        (1, 10, date(2023, 5, 11)),
    ],
                                          StructType([
                                              StructField("note", IntegerType(), True),
                                              StructField("count", IntegerType(), True),
                                              StructField("calculated_on", DateType(), True)
                                          ]))

With fixed alignment:

[style]
based_on_style = yapf
column_limit = 120
indent_width = 4
continuation_align_style = fixed
continuation_indent_width = 4
    existing_data = spark.createDataFrame([
        (1, 12, date(2024, 1, 28)),
        (1, 13, date(2024, 2, 10)),
        (1, 10, date(2023, 5, 11)),
    ],
        StructType([
        StructField("note", IntegerType(), True),
        StructField("count", IntegerType(), True),
        StructField("calculated_on", DateType(), True)
        ]))

Desired output:

    existing_data = spark.createDataFrame([
        (1, 12, date(2024, 1, 28)),
        (1, 13, date(2024, 2, 10)),
        (1, 10, date(2023, 5, 11)),
    ],
        StructType([
            StructField("note", IntegerType(), True),
            StructField("count", IntegerType(), True),
            StructField("calculated_on", DateType(), True)
        ]))