ruff_python_formatter: fix 'dynamic' mode with doctests (#9129)

This fixes a bug where the current indent level was not calculated
correctly for doctests. Namely, it didn't account for the extra indent
level (in terms of ASCII spaces) used by by the PS1 (`>>> `) and PS2
(`... `) prompts. As a result, lines could extend up to 4 spaces beyond
the configured line length limit.

We fix that by passing the `CodeExampleKind` to the `format` routine
instead of just the code itself. In this way, `format` can query whether
there will be any extra indent added _after_ formatting the code and
take that into account for its line length setting.

We add a few regression tests, taken directly from @stinodego's
examples.

Fixes #9126
This commit is contained in:
Andrew Gallant 2023-12-14 09:53:43 -05:00 committed by GitHub
parent c99eae2c08
commit 28b1aa201b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 327 additions and 14 deletions

View file

@ -176,6 +176,55 @@ class Abcdefghijklmopqrstuvwxyz(Abc, Def, Ghi, Jkl, Mno, Pqr, Stu, Vwx, Yz, A1,
Done.
"""
pass
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent1():
"""
Docstring example containing a class.
Examples
--------
>>> @pl.api.register_dataframe_namespace("split")
... class SplitFrame:
... def __init__(self, df: pl.DataFrame):
... self._df = df
...
... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]:
... return [
... self._df.filter(pl.col(col).str.starts_with(c))
... for c in sorted(
... set(df.select(pl.col(col).str.slice(0, 1)).to_series())
... )
... ]
"""
# See: https://github.com/astral-sh/ruff/issues/9126
class DoctestExtraIndent2:
def example2():
"""
Regular docstring of class method.
Examples
--------
>>> df = pl.DataFrame(
... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]}
... )
"""
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent3():
"""
Pragma comment.
Examples
--------
>>> af1, af2, af3 = pl.align_frames(
... df1, df2, df3, on="dt"
... ) # doctest: +IGNORE_RESULT
"""
```
## Outputs
@ -433,6 +482,55 @@ def unindented_barely_exceeds_limit():
Done.
"""
pass
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent1():
"""
Docstring example containing a class.
Examples
--------
>>> @pl.api.register_dataframe_namespace("split")
... class SplitFrame:
... def __init__(self, df: pl.DataFrame):
... self._df = df
...
... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]:
... return [
... self._df.filter(pl.col(col).str.starts_with(c))
... for c in sorted(
... set(df.select(pl.col(col).str.slice(0, 1)).to_series())
... )
... ]
"""
# See: https://github.com/astral-sh/ruff/issues/9126
class DoctestExtraIndent2:
def example2():
"""
Regular docstring of class method.
Examples
--------
>>> df = pl.DataFrame(
... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]}
... )
"""
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent3():
"""
Pragma comment.
Examples
--------
>>> af1, af2, af3 = pl.align_frames(
... df1, df2, df3, on="dt"
... ) # doctest: +IGNORE_RESULT
"""
```
@ -686,6 +784,49 @@ def unindented_barely_exceeds_limit():
Done.
"""
pass
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent1():
"""
Docstring example containing a class.
Examples
--------
>>> @pl.api.register_dataframe_namespace("split")
... class SplitFrame:
... def __init__(self, df: pl.DataFrame):
... self._df = df
...
... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]:
... return [
... self._df.filter(pl.col(col).str.starts_with(c))
... for c in sorted(set(df.select(pl.col(col).str.slice(0, 1)).to_series()))
... ]
"""
# See: https://github.com/astral-sh/ruff/issues/9126
class DoctestExtraIndent2:
def example2():
"""
Regular docstring of class method.
Examples
--------
>>> df = pl.DataFrame({"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]})
"""
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent3():
"""
Pragma comment.
Examples
--------
>>> af1, af2, af3 = pl.align_frames(df1, df2, df3, on="dt") # doctest: +IGNORE_RESULT
"""
```
@ -943,6 +1084,55 @@ def unindented_barely_exceeds_limit():
Done.
"""
pass
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent1():
"""
Docstring example containing a class.
Examples
--------
>>> @pl.api.register_dataframe_namespace("split")
... class SplitFrame:
... def __init__(self, df: pl.DataFrame):
... self._df = df
...
... def by_first_letter_of_column_values(self, col: str) -> list[pl.DataFrame]:
... return [
... self._df.filter(pl.col(col).str.starts_with(c))
... for c in sorted(
... set(df.select(pl.col(col).str.slice(0, 1)).to_series())
... )
... ]
"""
# See: https://github.com/astral-sh/ruff/issues/9126
class DoctestExtraIndent2:
def example2():
"""
Regular docstring of class method.
Examples
--------
>>> df = pl.DataFrame(
... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]}
... )
"""
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent3():
"""
Pragma comment.
Examples
--------
>>> af1, af2, af3 = pl.align_frames(
... df1, df2, df3, on="dt"
... ) # doctest: +IGNORE_RESULT
"""
```
@ -1624,6 +1814,61 @@ def unindented_barely_exceeds_limit():
Done.
"""
pass
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent1():
"""
Docstring example containing a class.
Examples
--------
>>> @pl.api.register_dataframe_namespace("split")
... class SplitFrame:
... def __init__(self, df: pl.DataFrame):
... self._df = df
...
... def by_first_letter_of_column_values(
... self, col: str
... ) -> list[pl.DataFrame]:
... return [
... self._df.filter(pl.col(col).str.starts_with(c))
... for c in sorted(
... set(
... df.select(
... pl.col(col).str.slice(0, 1)
... ).to_series()
... )
... )
... ]
"""
# See: https://github.com/astral-sh/ruff/issues/9126
class DoctestExtraIndent2:
def example2():
"""
Regular docstring of class method.
Examples
--------
>>> df = pl.DataFrame(
... {"foo": [1, 2, 3], "bar": [6, 7, 8], "ham": ["a", "b", "c"]}
... )
"""
# See: https://github.com/astral-sh/ruff/issues/9126
def doctest_extra_indent3():
"""
Pragma comment.
Examples
--------
>>> af1, af2, af3 = pl.align_frames(
... df1, df2, df3, on="dt"
... ) # doctest: +IGNORE_RESULT
"""
```