Skip to content

Commit

Permalink
Merge branch 'main' into redo-pr-2484
Browse files Browse the repository at this point in the history
  • Loading branch information
aaossa committed Oct 26, 2022
2 parents 1a409b2 + 09d4acd commit a2150e9
Show file tree
Hide file tree
Showing 14 changed files with 406 additions and 50 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/diff_shades_comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ jobs:
- name: Try to find pre-existing PR comment
if: steps.metadata.outputs.needs-comment == 'true'
id: find-comment
uses: peter-evans/find-comment@1769778a0c5bd330272d749d12c036d65e70d39d
uses: peter-evans/find-comment@b657a70ff16d17651703a84bee1cb9ad9d2be2ea
with:
issue-number: ${{ steps.metadata.outputs.pr-number }}
comment-author: "github-actions[bot]"
body-includes: "diff-shades"

- name: Create or update PR comment
if: steps.metadata.outputs.needs-comment == 'true'
uses: peter-evans/create-or-update-comment@c9fcb64660bc90ec1cc535646af190c992007c32
uses: peter-evans/create-or-update-comment@2b2c85d0bf1b8a7b4e7e344bd5c71dc4b9196e9f
with:
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ steps.metadata.outputs.pr-number }}
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

<!-- Changes that affect Black's preview style -->

- Enforce empty lines before classes and functions with sticky leading comments (#3302)

### Configuration

<!-- Changes to how Black can be configured -->
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Further information can be found in our docs:
_Black_ is already [successfully used](https://github.com/psf/black#used-by) by many
projects, small and big. _Black_ has a comprehensive test suite, with efficient parallel
tests, and our own auto formatting and parallel Continuous Integration runner. Now that
we have become stable, you should not expect large formatting to changes in the future.
we have become stable, you should not expect large formatting changes in the future.
Stylistic changes will mostly be responses to bug reports and support for new Python
syntax. For more information please refer to the
[The Black Code Style](https://black.readthedocs.io/en/stable/the_black_code_style/index.html).
Expand Down
22 changes: 14 additions & 8 deletions docs/contributing/reference/reference_classes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,29 @@
.. autoclass:: black.brackets.BracketTracker
:members:

:class:`EmptyLineTracker`
:class:`Line`
-------------

.. autoclass:: black.lines.Line
:members:
:special-members: __str__, __bool__

:class:`LinesBlock`
-------------------------

.. autoclass:: black.EmptyLineTracker
.. autoclass:: black.lines.LinesBlock
:members:

:class:`Line`
-------------
:class:`EmptyLineTracker`
-------------------------

.. autoclass:: black.Line
.. autoclass:: black.lines.EmptyLineTracker
:members:
:special-members: __str__, __bool__

:class:`LineGenerator`
----------------------

.. autoclass:: black.LineGenerator
.. autoclass:: black.linegen.LineGenerator
:show-inheritance:
:members:

Expand All @@ -40,7 +46,7 @@
:class:`Report`
---------------

.. autoclass:: black.Report
.. autoclass:: black.report.Report
:members:
:special-members: __str__

Expand Down
2 changes: 1 addition & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Used by ReadTheDocs; pinned requirements for stability.

myst-parser==0.18.1
Sphinx==5.2.3
Sphinx==5.3.0
# Older versions break Sphinx even though they're declared to be supported.
docutils==0.19
sphinxcontrib-programoutput==0.17
Expand Down
49 changes: 35 additions & 14 deletions docs/the_black_code_style/future_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,26 +63,47 @@ limit. Line continuation backslashes are converted into parenthesized strings.
Unnecessary parentheses are stripped. The stability and status of this feature is
tracked in [this issue](https://github.com/psf/black/issues/2188).

### Removing newlines in the beginning of code blocks
### Improved empty line management

_Black_ will remove newlines in the beginning of new code blocks, i.e. when the
indentation level is increased. For example:
1. _Black_ will remove newlines in the beginning of new code blocks, i.e. when the
indentation level is increased. For example:

```python
def my_func():
```python
def my_func():

print("The line above me will be deleted!")
```
print("The line above me will be deleted!")
```

will be changed to:
will be changed to:

```python
def my_func():
print("The line above me will be deleted!")
```

This new feature will be applied to **all code blocks**: `def`, `class`, `if`,
`for`, `while`, `with`, `case` and `match`.

2. _Black_ will enforce empty lines before classes and functions with leading comments.
For example:

```python
some_var = 1
# Leading sticky comment
def my_func():
...
```

will be changed to:

```python
some_var = 1

```python
def my_func():
print("The line above me will be deleted!")
```

This new feature will be applied to **all code blocks**: `def`, `class`, `if`, `for`,
`while`, `with`, `case` and `match`.
# Leading sticky comment
def my_func():
...
```

### Improved parentheses management

Expand Down
21 changes: 12 additions & 9 deletions src/black/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
unmask_cell,
)
from black.linegen import LN, LineGenerator, transform_line
from black.lines import EmptyLineTracker, Line
from black.lines import EmptyLineTracker, LinesBlock
from black.mode import (
FUTURE_FLAG_TO_FEATURE,
VERSION_TO_FEATURES,
Expand Down Expand Up @@ -1075,7 +1075,7 @@ def f(

def _format_str_once(src_contents: str, *, mode: Mode) -> str:
src_node = lib2to3_parse(src_contents.lstrip(), mode.target_versions)
dst_contents = []
dst_blocks: List[LinesBlock] = []
if mode.target_versions:
versions = mode.target_versions
else:
Expand All @@ -1084,22 +1084,25 @@ def _format_str_once(src_contents: str, *, mode: Mode) -> str:

normalize_fmt_off(src_node, preview=mode.preview)
lines = LineGenerator(mode=mode)
elt = EmptyLineTracker(is_pyi=mode.is_pyi)
empty_line = Line(mode=mode)
after = 0
elt = EmptyLineTracker(mode=mode)
split_line_features = {
feature
for feature in {Feature.TRAILING_COMMA_IN_CALL, Feature.TRAILING_COMMA_IN_DEF}
if supports_feature(versions, feature)
}
block: Optional[LinesBlock] = None
for current_line in lines.visit(src_node):
dst_contents.append(str(empty_line) * after)
before, after = elt.maybe_empty_lines(current_line)
dst_contents.append(str(empty_line) * before)
block = elt.maybe_empty_lines(current_line)
dst_blocks.append(block)
for line in transform_line(
current_line, mode=mode, features=split_line_features
):
dst_contents.append(str(line))
block.content_lines.append(str(line))
if dst_blocks:
dst_blocks[-1].after = 0
dst_contents = []
for block in dst_blocks:
dst_contents.extend(block.all_lines())
if not dst_contents:
normalized_content, _, newline = decode_bytes(src_contents.encode("utf-8"))
if "\n" in normalized_content:
Expand Down
86 changes: 75 additions & 11 deletions src/black/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,28 @@ def __bool__(self) -> bool:
return bool(self.leaves or self.comments)


@dataclass
class LinesBlock:
"""Class that holds information about a block of formatted lines.
This is introduced so that the EmptyLineTracker can look behind the standalone
comments and adjust their empty lines for class or def lines.
"""

mode: Mode
previous_block: Optional["LinesBlock"]
original_line: Line
before: int = 0
content_lines: List[str] = field(default_factory=list)
after: int = 0

def all_lines(self) -> List[str]:
empty_line = str(Line(mode=self.mode))
return (
[empty_line * self.before] + self.content_lines + [empty_line * self.after]
)


@dataclass
class EmptyLineTracker:
"""Provides a stateful method that returns the number of potential extra
Expand All @@ -458,33 +480,55 @@ class EmptyLineTracker:
are consumed by `maybe_empty_lines()` and included in the computation.
"""

is_pyi: bool = False
mode: Mode
previous_line: Optional[Line] = None
previous_after: int = 0
previous_block: Optional[LinesBlock] = None
previous_defs: List[int] = field(default_factory=list)
semantic_leading_comment: Optional[LinesBlock] = None

def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
"""Return the number of extra empty lines before and after the `current_line`.
This is for separating `def`, `async def` and `class` with extra empty
lines (two on module-level).
"""
before, after = self._maybe_empty_lines(current_line)
previous_after = self.previous_block.after if self.previous_block else 0
before = (
# Black should not insert empty lines at the beginning
# of the file
0
if self.previous_line is None
else before - self.previous_after
else before - previous_after
)
self.previous_after = after
block = LinesBlock(
mode=self.mode,
previous_block=self.previous_block,
original_line=current_line,
before=before,
after=after,
)

# Maintain the semantic_leading_comment state.
if current_line.is_comment:
if self.previous_line is None or (
not self.previous_line.is_decorator
# `or before` means this comment already has an empty line before
and (not self.previous_line.is_comment or before)
and (self.semantic_leading_comment is None or before)
):
self.semantic_leading_comment = block
elif not current_line.is_decorator:
self.semantic_leading_comment = None

self.previous_line = current_line
return before, after
self.previous_block = block
return block

def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
max_allowed = 1
if current_line.depth == 0:
max_allowed = 1 if self.is_pyi else 2
max_allowed = 1 if self.mode.is_pyi else 2
if current_line.leaves:
# Consume the first leaf's extra newlines.
first_leaf = current_line.leaves[0]
Expand All @@ -495,7 +539,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
before = 0
depth = current_line.depth
while self.previous_defs and self.previous_defs[-1] >= depth:
if self.is_pyi:
if self.mode.is_pyi:
assert self.previous_line is not None
if depth and not current_line.is_def and self.previous_line.is_def:
# Empty lines between attributes and methods should be preserved.
Expand Down Expand Up @@ -563,7 +607,7 @@ def _maybe_empty_lines_for_class_or_def(
return 0, 0

if self.previous_line.is_decorator:
if self.is_pyi and current_line.is_stub_class:
if self.mode.is_pyi and current_line.is_stub_class:
# Insert an empty line after a decorated stub class
return 0, 1

Expand All @@ -574,14 +618,27 @@ def _maybe_empty_lines_for_class_or_def(
):
return 0, 0

comment_to_add_newlines: Optional[LinesBlock] = None
if (
self.previous_line.is_comment
and self.previous_line.depth == current_line.depth
and before == 0
):
return 0, 0
slc = self.semantic_leading_comment
if (
Preview.empty_lines_before_class_or_def_with_leading_comments
in current_line.mode
and slc is not None
and slc.previous_block is not None
and not slc.previous_block.original_line.is_class
and not slc.previous_block.original_line.opens_block
and slc.before <= 1
):
comment_to_add_newlines = slc
else:
return 0, 0

if self.is_pyi:
if self.mode.is_pyi:
if current_line.is_class or self.previous_line.is_class:
if self.previous_line.depth < current_line.depth:
newlines = 0
Expand Down Expand Up @@ -609,6 +666,13 @@ def _maybe_empty_lines_for_class_or_def(
newlines = 0
else:
newlines = 1 if current_line.depth else 2
if comment_to_add_newlines is not None:
previous_block = comment_to_add_newlines.previous_block
if previous_block is not None:
comment_to_add_newlines.before = (
max(comment_to_add_newlines.before, newlines) - previous_block.after
)
newlines = 0
return newlines, 0


Expand Down
1 change: 1 addition & 0 deletions src/black/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class Preview(Enum):
"""Individual preview style features."""

annotation_parens = auto()
empty_lines_before_class_or_def_with_leading_comments = auto()
long_docstring_quotes_on_newline = auto()
normalize_docstring_quotes_and_prefixes_properly = auto()
one_element_subscript = auto()
Expand Down
2 changes: 1 addition & 1 deletion test_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
coverage >= 5.3
pre-commit
pytest >= 6.1.1
pytest-xdist >= 2.2.1
pytest-xdist >= 2.2.1, < 3.0.2
pytest-cov >= 2.11.1
tox

0 comments on commit a2150e9

Please sign in to comment.