ruff/crates/ruff_python_formatter/resources/test/fixtures/ruff
Dylan 4e1cf5747a
Fluent formatting of method chains (#21369)
This PR implements a modification (in preview) to fluent formatting for
method chains: We break _at_ the first call instead of _after_.

For example, we have the following diff between `main` and this PR (with
`line-length=8` so I don't have to stretch out the text):

```diff
 x = (
-    df.merge()
+    df
+    .merge()
     .groupby()
     .agg()
     .filter()
 )
```

## Explanation of current implementation

Recall that we traverse the AST to apply formatting. A method chain,
while read left-to-right, is stored in the AST "in reverse". So if we
start with something like

```python
a.b.c.d().e.f()
```

then the first syntax node we meet is essentially `.f()`. So we have to
peek ahead. And we actually _already_ do this in our current fluent
formatting logic: we peek ahead to count how many calls we have in the
chain to see whether we should be using fluent formatting or now.

In this implementation, we actually _record_ this number inside the enum
for `CallChainLayout`. That is, we make the variant `Fluent` hold an
`AttributeState`. This state can either be:

- The number of call-like attributes preceding the current attribute
- The state `FirstCallOrSubscript` which means we are at the first
call-like attribute in the chain (reading from left to right)
- The state `BeforeFirstCallOrSubscript` which means we are in the
"first group" of attributes, preceding that first call.

In our example, here's what it looks like at each attribute:

```
a.b.c.d().e.f @ Fluent(CallsOrSubscriptsPreceding(1))
a.b.c.d().e @ Fluent(CallsOrSubscriptsPreceding(1))
a.b.c.d @ Fluent(FirstCallOrSubscript)
a.b.c @ Fluent(BeforeFirstCallOrSubscript)
a.b @ Fluent(BeforeFirstCallOrSubscript)
```

Now, as we descend down from the parent expression, we pass along this
little piece of state and modify it as we go to track where we are. This
state doesn't do anything except when we are in `FirstCallOrSubscript`,
in which case we add a soft line break.

Closes #8598

---------

Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
2025-12-15 09:29:50 -06:00
..
carriage_return Normalize '\r' in string literals to '\n' 2023-06-30 10:13:23 +02:00
expression Keep lambda parameters on one line and parenthesize the body if it expands (#21385) 2025-12-12 12:02:25 -05:00
fmt_on_off Restore `indent.py` (#21094) 2025-10-27 10:34:29 +00:00
fmt_skip Respect `fmt: skip` for compound statements on single line (#20633) 2025-11-18 12:02:09 -06:00
parentheses Fluent formatting of method chains (#21369) 2025-12-15 09:29:50 -06:00
pattern Preserve tuple parentheses in case patterns (#18147) 2025-05-22 07:52:21 +02:00
range_formatting Allow newlines after function headers without docstrings (#21110) 2025-10-31 14:53:40 -04:00
statement Adjust own-line comment placement between branches (#21185) 2025-11-17 07:30:34 -06:00
stub_files [formatter] Fix missing blank lines before decorated classes in .pyi files (#18888) 2025-06-24 16:25:44 +02:00
.editorconfig Fix `\r` and `\r\n` handling in t- and f-string debug texts (#18673) 2025-06-15 06:53:06 +01:00
blank_line_before_class_docstring.options.json Implement `no_blank_line_before_class_docstring` preview style (#9154) 2023-12-19 00:43:20 -06:00
blank_line_before_class_docstring.py Implement `no_blank_line_before_class_docstring` preview style (#9154) 2023-12-19 00:43:20 -06:00
docstring.options.json Use double quotes for all docstrings, including single-quoted docstrings (#9020) 2023-12-07 04:41:00 +00:00
docstring.py Spellcheck & grammar (#10375) 2024-03-13 02:34:23 +00:00
docstring_chaperones.py Don't add chaperone space after escaped quote in triple quote (#17216) 2025-04-11 10:21:47 +02:00
docstring_code_examples.options.json ruff_python_formatter: implement "dynamic" line width mode for docstring code formatting (#9098) 2023-12-12 09:58:07 -05:00
docstring_code_examples.py Fix typos found by codespell (#9346) 2024-01-02 02:08:15 +00:00
docstring_code_examples_crlf.options.json format doctests in docstrings (#8811) 2023-11-27 11:14:55 -05:00
docstring_code_examples_crlf.py format doctests in docstrings (#8811) 2023-11-27 11:14:55 -05:00
docstring_code_examples_dynamic_line_width.options.json ruff_python_formatter: implement "dynamic" line width mode for docstring code formatting (#9098) 2023-12-12 09:58:07 -05:00
docstring_code_examples_dynamic_line_width.py Fix codeblock dynamic line length calculation for indented examples (#13523) 2024-09-27 09:09:07 +02:00
docstring_newlines.py Don't trim last empty line in docstrings (#9813) 2024-02-05 13:29:24 +00:00
docstring_non_visible_characters.py Fix typos found by codespell (#14863) 2024-12-09 09:32:12 +00:00
docstring_tab_indentation.options.json Docstring formatting: Preserve tab indentation when using `indent-style=tabs` (#9915) 2024-02-12 16:09:13 +01:00
docstring_tab_indentation.py Docstring formatting: Preserve tab indentation when using `indent-style=tabs` (#9915) 2024-02-12 16:09:13 +01:00
empty_multiple_trailing_newlines.py Fix handling of newlines in empty files (#7473) 2023-09-18 06:08:10 +00:00
empty_now_newline.py Fix handling of newlines in empty files (#7473) 2023-09-18 06:08:10 +00:00
empty_trailing_newline.py Fix handling of newlines in empty files (#7473) 2023-09-18 06:08:10 +00:00
empty_whitespace.py Fix handling of newlines in empty files (#7473) 2023-09-18 06:08:10 +00:00
f-string-carriage-return-newline.py Fix `\r` and `\r\n` handling in t- and f-string debug texts (#18673) 2025-06-15 06:53:06 +01:00
fluent.options.json Fluent formatting of method chains (#21369) 2025-12-15 09:29:50 -06:00
fluent.py Fluent formatting of method chains (#21369) 2025-12-15 09:29:50 -06:00
form_feed.py Treat form feed as whitespace in `SimpleTokenizer` (#7626) 2023-09-25 14:34:59 +00:00
module_dangling_comment1.py Format empty lines in stub files like black's preview style (#7206) 2023-09-11 08:03:59 +00:00
module_dangling_comment2.py Format empty lines in stub files like black's preview style (#7206) 2023-09-11 08:03:59 +00:00
multiline_string_deviations.py Hug multiline-strings preview style (#9243) 2024-01-10 12:47:34 +01:00
newlines.py Allow newlines after function headers without docstrings (#21110) 2025-10-31 14:53:40 -04:00
newlines.pyi Insert empty line between suite and alternative branch after def/class (#12294) 2024-07-15 12:59:33 +02:00
notebook_docstring.options.json Disable top-level docstring formatting for notebooks (#9957) 2024-02-12 18:14:02 +00:00
notebook_docstring.py Disable top-level docstring formatting for notebooks (#9957) 2024-02-12 18:14:02 +00:00
pattern_match_regression_brackets.py Preserve tuple parentheses in case patterns (#18147) 2025-05-22 07:52:21 +02:00
preview.options.json Add test and basic implementation for formatter preview mode (#8044) 2023-10-26 15:33:26 +00:00
preview.py Add test and basic implementation for formatter preview mode (#8044) 2023-10-26 15:33:26 +00:00
quote_style.options.json Add "preserve" quote-style to mimic Black's skip-string-normalization (#8822) 2023-12-07 23:59:22 +00:00
quote_style.py Preview Style: Format module level docstring (#9725) 2024-02-05 15:03:34 +00:00
skip_magic_trailing_comma.options.json Add tests for skip magic trailing comma 2023-06-26 14:15:55 +02:00
skip_magic_trailing_comma.py Improve `with` statement comment handling and expression breaking (#6621) 2023-08-18 03:30:38 +00:00
tab_width.options.json Introduce `IndentWidth` (#7301) 2023-09-13 14:52:24 +02:00
tab_width.py Introduce `IndentWidth` (#7301) 2023-09-13 14:52:24 +02:00
trailing_comments.py Treat `ty: ` comments as pragma comments (#18532) 2025-06-07 16:02:43 +02:00
trivia.py Use `pass` over ellipsis in non-function/class contexts (#8049) 2023-10-19 11:11:17 +02:00