Skip to content

Commit b6fb972

Browse files
authored
config: add new docstring-code-format knob (#8854)
This PR does the plumbing to make a new formatting option, `docstring-code-format`, available in the configuration for end users. It is disabled by default (opt-in). It is opt-in at least initially to reflect a conservative posture. The intent is to make it opt-out at some point in the future. This was split out from #8811 in order to make #8811 easier to merge. Namely, once this is merged, docstring code snippet formatting will become available to end users. (See comments below for how we arrived at the name.) Closes #7146 ## Test Plan Other than the standard test suite, I ran the formatter over the CPython and polars projects to ensure both that the result looked sensible and that tests still passed. At time of writing, one issue that currently appears is that reformatting code snippets trips the long line lint: https://github.com/BurntSushi/polars/actions/runs/7006619426/job/19058868021
1 parent 18452cf commit b6fb972

21 files changed

+505
-55
lines changed

crates/ruff_cli/tests/format.rs

+93
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,99 @@ if condition:
139139
Ok(())
140140
}
141141

142+
#[test]
143+
fn docstring_options() -> Result<()> {
144+
let tempdir = TempDir::new()?;
145+
let ruff_toml = tempdir.path().join("ruff.toml");
146+
fs::write(
147+
&ruff_toml,
148+
r#"
149+
[format]
150+
docstring-code-format = true
151+
docstring-code-line-length = 20
152+
"#,
153+
)?;
154+
155+
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
156+
.args(["format", "--config"])
157+
.arg(&ruff_toml)
158+
.arg("-")
159+
.pass_stdin(r#"
160+
def f(x):
161+
'''
162+
Something about `f`. And an example:
163+
164+
.. code-block:: python
165+
166+
foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
167+
168+
Another example:
169+
170+
```py
171+
foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
172+
```
173+
174+
And another:
175+
176+
>>> foo, bar, quux = this_is_a_long_line(lion, hippo, lemur, bear)
177+
'''
178+
pass
179+
"#), @r###"
180+
success: true
181+
exit_code: 0
182+
----- stdout -----
183+
def f(x):
184+
"""
185+
Something about `f`. And an example:
186+
187+
.. code-block:: python
188+
189+
(
190+
foo,
191+
bar,
192+
quux,
193+
) = this_is_a_long_line(
194+
lion,
195+
hippo,
196+
lemur,
197+
bear,
198+
)
199+
200+
Another example:
201+
202+
```py
203+
(
204+
foo,
205+
bar,
206+
quux,
207+
) = this_is_a_long_line(
208+
lion,
209+
hippo,
210+
lemur,
211+
bear,
212+
)
213+
```
214+
215+
And another:
216+
217+
>>> (
218+
... foo,
219+
... bar,
220+
... quux,
221+
... ) = this_is_a_long_line(
222+
... lion,
223+
... hippo,
224+
... lemur,
225+
... bear,
226+
... )
227+
"""
228+
pass
229+
230+
----- stderr -----
231+
"###);
232+
Ok(())
233+
}
234+
142235
#[test]
143236
fn mixed_line_endings() -> Result<()> {
144237
let tempdir = TempDir::new()?;

crates/ruff_python_formatter/src/options.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ impl PyFormatOptions {
175175
self
176176
}
177177

178+
#[must_use]
179+
pub fn with_docstring_code_line_width(mut self, line_width: DocstringCodeLineWidth) -> Self {
180+
self.docstring_code_line_width = line_width;
181+
self
182+
}
183+
178184
#[must_use]
179185
pub fn with_preview(mut self, preview: PreviewMode) -> Self {
180186
self.preview = preview;
@@ -302,26 +308,21 @@ impl DocstringCode {
302308
}
303309
}
304310

305-
#[derive(Copy, Clone, Eq, PartialEq, CacheKey)]
311+
#[derive(Copy, Clone, Default, Eq, PartialEq, CacheKey)]
306312
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
307313
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
308314
#[cfg_attr(feature = "serde", serde(untagged))]
309315
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
310316
pub enum DocstringCodeLineWidth {
311317
Fixed(LineWidth),
318+
#[default]
312319
#[cfg_attr(
313320
feature = "serde",
314321
serde(deserialize_with = "deserialize_docstring_code_line_width_dynamic")
315322
)]
316323
Dynamic,
317324
}
318325

319-
impl Default for DocstringCodeLineWidth {
320-
fn default() -> DocstringCodeLineWidth {
321-
DocstringCodeLineWidth::Fixed(default_line_width())
322-
}
323-
}
324-
325326
impl std::fmt::Debug for DocstringCodeLineWidth {
326327
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
327328
match *self {

crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap

+5-5
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ quote-style = Double
173173
line-ending = LineFeed
174174
magic-trailing-comma = Respect
175175
docstring-code = Disabled
176-
docstring-code-line-width = 88
176+
docstring-code-line-width = "dynamic"
177177
preview = Disabled
178178
```
179179

@@ -347,7 +347,7 @@ quote-style = Double
347347
line-ending = LineFeed
348348
magic-trailing-comma = Respect
349349
docstring-code = Disabled
350-
docstring-code-line-width = 88
350+
docstring-code-line-width = "dynamic"
351351
preview = Disabled
352352
```
353353

@@ -521,7 +521,7 @@ quote-style = Double
521521
line-ending = LineFeed
522522
magic-trailing-comma = Respect
523523
docstring-code = Disabled
524-
docstring-code-line-width = 88
524+
docstring-code-line-width = "dynamic"
525525
preview = Disabled
526526
```
527527

@@ -695,7 +695,7 @@ quote-style = Double
695695
line-ending = LineFeed
696696
magic-trailing-comma = Respect
697697
docstring-code = Disabled
698-
docstring-code-line-width = 88
698+
docstring-code-line-width = "dynamic"
699699
preview = Disabled
700700
```
701701

@@ -869,7 +869,7 @@ quote-style = Single
869869
line-ending = LineFeed
870870
magic-trailing-comma = Respect
871871
docstring-code = Disabled
872-
docstring-code-line-width = 88
872+
docstring-code-line-width = "dynamic"
873873
preview = Disabled
874874
```
875875

crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap

+30-13
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,7 @@ quote-style = Double
13661366
line-ending = LineFeed
13671367
magic-trailing-comma = Respect
13681368
docstring-code = Disabled
1369-
docstring-code-line-width = 88
1369+
docstring-code-line-width = "dynamic"
13701370
preview = Disabled
13711371
```
13721372
@@ -2736,7 +2736,7 @@ quote-style = Double
27362736
line-ending = LineFeed
27372737
magic-trailing-comma = Respect
27382738
docstring-code = Disabled
2739-
docstring-code-line-width = 88
2739+
docstring-code-line-width = "dynamic"
27402740
preview = Disabled
27412741
```
27422742
@@ -4106,7 +4106,7 @@ quote-style = Double
41064106
line-ending = LineFeed
41074107
magic-trailing-comma = Respect
41084108
docstring-code = Disabled
4109-
docstring-code-line-width = 88
4109+
docstring-code-line-width = "dynamic"
41104110
preview = Disabled
41114111
```
41124112
@@ -5476,7 +5476,7 @@ quote-style = Double
54765476
line-ending = LineFeed
54775477
magic-trailing-comma = Respect
54785478
docstring-code = Disabled
5479-
docstring-code-line-width = 88
5479+
docstring-code-line-width = "dynamic"
54805480
preview = Disabled
54815481
```
54825482
@@ -6846,7 +6846,7 @@ quote-style = Double
68466846
line-ending = LineFeed
68476847
magic-trailing-comma = Respect
68486848
docstring-code = Enabled
6849-
docstring-code-line-width = 88
6849+
docstring-code-line-width = "dynamic"
68506850
preview = Disabled
68516851
```
68526852
@@ -7090,7 +7090,9 @@ def doctest_long_lines():
70907090
This won't get wrapped even though it exceeds our configured
70917091
line width because it doesn't exceed the line width within this
70927092
docstring. e.g, the `f` in `foo` is treated as the first column.
7093-
>>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey)
7093+
>>> foo, bar, quux = this_is_a_long_line(
7094+
... lion, giraffe, hippo, zeba, lemur, penguin, monkey
7095+
... )
70947096

70957097
But this one is long enough to get wrapped.
70967098
>>> foo, bar, quux = this_is_a_long_line(
@@ -8211,7 +8213,7 @@ quote-style = Double
82118213
line-ending = LineFeed
82128214
magic-trailing-comma = Respect
82138215
docstring-code = Enabled
8214-
docstring-code-line-width = 88
8216+
docstring-code-line-width = "dynamic"
82158217
preview = Disabled
82168218
```
82178219
@@ -8455,7 +8457,9 @@ def doctest_long_lines():
84558457
This won't get wrapped even though it exceeds our configured
84568458
line width because it doesn't exceed the line width within this
84578459
docstring. e.g, the `f` in `foo` is treated as the first column.
8458-
>>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey)
8460+
>>> foo, bar, quux = this_is_a_long_line(
8461+
... lion, giraffe, hippo, zeba, lemur, penguin, monkey
8462+
... )
84598463

84608464
But this one is long enough to get wrapped.
84618465
>>> foo, bar, quux = this_is_a_long_line(
@@ -9576,7 +9580,7 @@ quote-style = Double
95769580
line-ending = LineFeed
95779581
magic-trailing-comma = Respect
95789582
docstring-code = Enabled
9579-
docstring-code-line-width = 88
9583+
docstring-code-line-width = "dynamic"
95809584
preview = Disabled
95819585
```
95829586
@@ -9820,11 +9824,22 @@ def doctest_long_lines():
98209824
This won't get wrapped even though it exceeds our configured
98219825
line width because it doesn't exceed the line width within this
98229826
docstring. e.g, the `f` in `foo` is treated as the first column.
9823-
>>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey)
9827+
>>> foo, bar, quux = this_is_a_long_line(
9828+
... lion, giraffe, hippo, zeba, lemur, penguin, monkey
9829+
... )
98249830

98259831
But this one is long enough to get wrapped.
98269832
>>> foo, bar, quux = this_is_a_long_line(
9827-
... lion, giraffe, hippo, zeba, lemur, penguin, monkey, spider, bear, leopard
9833+
... lion,
9834+
... giraffe,
9835+
... hippo,
9836+
... zeba,
9837+
... lemur,
9838+
... penguin,
9839+
... monkey,
9840+
... spider,
9841+
... bear,
9842+
... leopard,
98289843
... )
98299844
"""
98309845
# This demostrates a normal line that will get wrapped but won't
@@ -10941,7 +10956,7 @@ quote-style = Double
1094110956
line-ending = LineFeed
1094210957
magic-trailing-comma = Respect
1094310958
docstring-code = Enabled
10944-
docstring-code-line-width = 88
10959+
docstring-code-line-width = "dynamic"
1094510960
preview = Disabled
1094610961
```
1094710962
@@ -11185,7 +11200,9 @@ def doctest_long_lines():
1118511200
This won't get wrapped even though it exceeds our configured
1118611201
line width because it doesn't exceed the line width within this
1118711202
docstring. e.g, the `f` in `foo` is treated as the first column.
11188-
>>> foo, bar, quux = this_is_a_long_line(lion, giraffe, hippo, zeba, lemur, penguin, monkey)
11203+
>>> foo, bar, quux = this_is_a_long_line(
11204+
... lion, giraffe, hippo, zeba, lemur, penguin, monkey
11205+
... )
1118911206

1119011207
But this one is long enough to get wrapped.
1119111208
>>> foo, bar, quux = this_is_a_long_line(

crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ quote-style = Double
2525
line-ending = CarriageReturnLineFeed
2626
magic-trailing-comma = Respect
2727
docstring-code = Enabled
28-
docstring-code-line-width = 88
28+
docstring-code-line-width = "dynamic"
2929
preview = Disabled
3030
```
3131

crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ quote-style = Double
136136
line-ending = LineFeed
137137
magic-trailing-comma = Respect
138138
docstring-code = Disabled
139-
docstring-code-line-width = 88
139+
docstring-code-line-width = "dynamic"
140140
preview = Disabled
141141
```
142142

@@ -288,7 +288,7 @@ quote-style = Single
288288
line-ending = LineFeed
289289
magic-trailing-comma = Respect
290290
docstring-code = Disabled
291-
docstring-code-line-width = 88
291+
docstring-code-line-width = "dynamic"
292292
preview = Disabled
293293
```
294294

crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ quote-style = Double
151151
line-ending = LineFeed
152152
magic-trailing-comma = Respect
153153
docstring-code = Disabled
154-
docstring-code-line-width = 88
154+
docstring-code-line-width = "dynamic"
155155
preview = Disabled
156156
```
157157

@@ -327,7 +327,7 @@ quote-style = Single
327327
line-ending = LineFeed
328328
magic-trailing-comma = Respect
329329
docstring-code = Disabled
330-
docstring-code-line-width = 88
330+
docstring-code-line-width = "dynamic"
331331
preview = Disabled
332332
```
333333

crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ quote-style = Double
3535
line-ending = LineFeed
3636
magic-trailing-comma = Respect
3737
docstring-code = Disabled
38-
docstring-code-line-width = 88
38+
docstring-code-line-width = "dynamic"
3939
preview = Disabled
4040
```
4141

@@ -71,7 +71,7 @@ quote-style = Double
7171
line-ending = LineFeed
7272
magic-trailing-comma = Respect
7373
docstring-code = Disabled
74-
docstring-code-line-width = 88
74+
docstring-code-line-width = "dynamic"
7575
preview = Disabled
7676
```
7777

0 commit comments

Comments
 (0)