Treat comments less magically
This commit is contained in:
parent
591bedc2be
commit
b1a7600b0a
16
README.md
16
README.md
@ -183,6 +183,22 @@ explains it. The tl;dr is "it's like highway speed limits, we won't
|
|||||||
bother you if you overdo it by a few km/h".
|
bother you if you overdo it by a few km/h".
|
||||||
|
|
||||||
|
|
||||||
|
### Empty lines
|
||||||
|
|
||||||
|
*Black* will allow single empty lines left by the original editors,
|
||||||
|
except when they're added within parenthesized expressions. Since such
|
||||||
|
expressions are always reformatted to fit minimal space, this whitespace
|
||||||
|
is lost.
|
||||||
|
|
||||||
|
It will also insert proper spacing before and after function definitions.
|
||||||
|
It's one line before and after inner functions and two lines before and
|
||||||
|
after module-level functions. *Black* will put those empty lines also
|
||||||
|
between the function definition and any standalone comments that
|
||||||
|
immediately precede the given function. If you want to comment on the
|
||||||
|
entire function, use a docstring or put a leading comment in the function
|
||||||
|
body.
|
||||||
|
|
||||||
|
|
||||||
### Editor integration
|
### Editor integration
|
||||||
|
|
||||||
There is currently no integration with any text editors. Vim and
|
There is currently no integration with any text editors. Vim and
|
||||||
|
101
black.py
101
black.py
@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from asyncio.base_events import BaseEventLoop
|
from asyncio.base_events import BaseEventLoop
|
||||||
from concurrent.futures import Executor, ProcessPoolExecutor
|
from concurrent.futures import Executor, ProcessPoolExecutor
|
||||||
@ -218,7 +219,6 @@ def format_str(src_contents: str, line_length: int) -> FileContent:
|
|||||||
"""Reformats a string and returns new contents."""
|
"""Reformats a string and returns new contents."""
|
||||||
src_node = lib2to3_parse(src_contents)
|
src_node = lib2to3_parse(src_contents)
|
||||||
dst_contents = ""
|
dst_contents = ""
|
||||||
comments: List[Line] = []
|
|
||||||
lines = LineGenerator()
|
lines = LineGenerator()
|
||||||
elt = EmptyLineTracker()
|
elt = EmptyLineTracker()
|
||||||
py36 = is_python36(src_node)
|
py36 = is_python36(src_node)
|
||||||
@ -230,21 +230,8 @@ def format_str(src_contents: str, line_length: int) -> FileContent:
|
|||||||
before, after = elt.maybe_empty_lines(current_line)
|
before, after = elt.maybe_empty_lines(current_line)
|
||||||
for _ in range(before):
|
for _ in range(before):
|
||||||
dst_contents += str(empty_line)
|
dst_contents += str(empty_line)
|
||||||
if not current_line.is_comment:
|
for line in split_line(current_line, line_length=line_length, py36=py36):
|
||||||
for comment in comments:
|
dst_contents += str(line)
|
||||||
dst_contents += str(comment)
|
|
||||||
comments = []
|
|
||||||
for line in split_line(current_line, line_length=line_length, py36=py36):
|
|
||||||
dst_contents += str(line)
|
|
||||||
else:
|
|
||||||
comments.append(current_line)
|
|
||||||
if comments:
|
|
||||||
if elt.previous_defs:
|
|
||||||
# Separate postscriptum comments from the last module-level def.
|
|
||||||
dst_contents += str(empty_line)
|
|
||||||
dst_contents += str(empty_line)
|
|
||||||
for comment in comments:
|
|
||||||
dst_contents += str(comment)
|
|
||||||
return dst_contents
|
return dst_contents
|
||||||
|
|
||||||
|
|
||||||
@ -662,10 +649,6 @@ def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
(two on module-level), as well as providing an extra empty line after flow
|
(two on module-level), as well as providing an extra empty line after flow
|
||||||
control keywords to make them more prominent.
|
control keywords to make them more prominent.
|
||||||
"""
|
"""
|
||||||
if current_line.is_comment:
|
|
||||||
# Don't count standalone comments towards previous empty lines.
|
|
||||||
return 0, 0
|
|
||||||
|
|
||||||
before, after = self._maybe_empty_lines(current_line)
|
before, after = self._maybe_empty_lines(current_line)
|
||||||
before -= self.previous_after
|
before -= self.previous_after
|
||||||
self.previous_after = after
|
self.previous_after = after
|
||||||
@ -673,10 +656,14 @@ def maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
|||||||
return before, after
|
return before, after
|
||||||
|
|
||||||
def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
|
||||||
|
max_allowed = 1
|
||||||
|
if current_line.is_comment and current_line.depth == 0:
|
||||||
|
max_allowed = 2
|
||||||
if current_line.leaves:
|
if current_line.leaves:
|
||||||
# Consume the first leaf's extra newlines.
|
# Consume the first leaf's extra newlines.
|
||||||
first_leaf = current_line.leaves[0]
|
first_leaf = current_line.leaves[0]
|
||||||
before = int('\n' in first_leaf.prefix)
|
before = first_leaf.prefix.count('\n')
|
||||||
|
before = min(before, max(before, max_allowed))
|
||||||
first_leaf.prefix = ''
|
first_leaf.prefix = ''
|
||||||
else:
|
else:
|
||||||
before = 0
|
before = 0
|
||||||
@ -730,7 +717,6 @@ class LineGenerator(Visitor[Line]):
|
|||||||
in ways that will no longer stringify to valid Python code on the tree.
|
in ways that will no longer stringify to valid Python code on the tree.
|
||||||
"""
|
"""
|
||||||
current_line: Line = Factory(Line)
|
current_line: Line = Factory(Line)
|
||||||
standalone_comments: List[Leaf] = Factory(list)
|
|
||||||
|
|
||||||
def line(self, indent: int = 0) -> Iterator[Line]:
|
def line(self, indent: int = 0) -> Iterator[Line]:
|
||||||
"""Generate a line.
|
"""Generate a line.
|
||||||
@ -761,33 +747,22 @@ def visit_default(self, node: LN) -> Iterator[Line]:
|
|||||||
yield from self.line()
|
yield from self.line()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# regular standalone comment, to be processed later (see
|
# regular standalone comment
|
||||||
# docstring in `generate_comments()`
|
|
||||||
self.standalone_comments.append(comment)
|
|
||||||
normalize_prefix(node, inside_brackets=any_open_brackets)
|
|
||||||
if node.type not in WHITESPACE:
|
|
||||||
for comment in self.standalone_comments:
|
|
||||||
yield from self.line()
|
yield from self.line()
|
||||||
|
|
||||||
self.current_line.append(comment)
|
self.current_line.append(comment)
|
||||||
yield from self.line()
|
yield from self.line()
|
||||||
|
|
||||||
self.standalone_comments = []
|
normalize_prefix(node, inside_brackets=any_open_brackets)
|
||||||
|
if node.type not in WHITESPACE:
|
||||||
self.current_line.append(node)
|
self.current_line.append(node)
|
||||||
yield from super().visit_default(node)
|
yield from super().visit_default(node)
|
||||||
|
|
||||||
def visit_suite(self, node: Node) -> Iterator[Line]:
|
def visit_INDENT(self, node: Node) -> Iterator[Line]:
|
||||||
"""Body of a statement after a colon."""
|
|
||||||
children = iter(node.children)
|
|
||||||
# Process newline before indenting. It might contain an inline
|
|
||||||
# comment that should go right after the colon.
|
|
||||||
newline = next(children)
|
|
||||||
yield from self.visit(newline)
|
|
||||||
yield from self.line(+1)
|
yield from self.line(+1)
|
||||||
|
yield from self.visit_default(node)
|
||||||
|
|
||||||
for child in children:
|
def visit_DEDENT(self, node: Node) -> Iterator[Line]:
|
||||||
yield from self.visit(child)
|
|
||||||
|
|
||||||
yield from self.line(-1)
|
yield from self.line(-1)
|
||||||
|
|
||||||
def visit_stmt(self, node: Node, keywords: Set[str]) -> Iterator[Line]:
|
def visit_stmt(self, node: Node, keywords: Set[str]) -> Iterator[Line]:
|
||||||
@ -1138,30 +1113,40 @@ def generate_comments(leaf: Leaf) -> Iterator[Leaf]:
|
|||||||
Inline comments are emitted as regular token.COMMENT leaves. Standalone
|
Inline comments are emitted as regular token.COMMENT leaves. Standalone
|
||||||
are emitted with a fake STANDALONE_COMMENT token identifier.
|
are emitted with a fake STANDALONE_COMMENT token identifier.
|
||||||
"""
|
"""
|
||||||
if not leaf.prefix:
|
p = leaf.prefix
|
||||||
|
if not p:
|
||||||
return
|
return
|
||||||
|
|
||||||
if '#' not in leaf.prefix:
|
if '#' not in p:
|
||||||
return
|
return
|
||||||
|
|
||||||
before_comment, content = leaf.prefix.split('#', 1)
|
nlines = 0
|
||||||
content = content.rstrip()
|
for index, line in enumerate(p.split('\n')):
|
||||||
if content and (content[0] not in {' ', '!', '#'}):
|
|
||||||
content = ' ' + content
|
|
||||||
is_standalone_comment = (
|
|
||||||
'\n' in before_comment or '\n' in content or leaf.type == token.ENDMARKER
|
|
||||||
)
|
|
||||||
if not is_standalone_comment:
|
|
||||||
# simple trailing comment
|
|
||||||
yield Leaf(token.COMMENT, value='#' + content)
|
|
||||||
return
|
|
||||||
|
|
||||||
for line in ('#' + content).split('\n'):
|
|
||||||
line = line.lstrip()
|
line = line.lstrip()
|
||||||
|
if not line:
|
||||||
|
nlines += 1
|
||||||
if not line.startswith('#'):
|
if not line.startswith('#'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
yield Leaf(STANDALONE_COMMENT, line)
|
if index == 0 and leaf.type != token.ENDMARKER:
|
||||||
|
comment_type = token.COMMENT # simple trailing comment
|
||||||
|
else:
|
||||||
|
comment_type = STANDALONE_COMMENT
|
||||||
|
yield Leaf(comment_type, make_comment(line), prefix='\n' * nlines)
|
||||||
|
|
||||||
|
nlines = 0
|
||||||
|
|
||||||
|
|
||||||
|
def make_comment(content: str) -> str:
|
||||||
|
content = content.rstrip()
|
||||||
|
if not content:
|
||||||
|
return '#'
|
||||||
|
|
||||||
|
if content[0] == '#':
|
||||||
|
content = content[1:]
|
||||||
|
if content and content[0] not in {' ', '!', '#'}:
|
||||||
|
content = ' ' + content
|
||||||
|
return '#' + content
|
||||||
|
|
||||||
|
|
||||||
def split_line(
|
def split_line(
|
||||||
@ -1384,9 +1369,11 @@ def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
|
|||||||
you'll lose your voting rights.
|
you'll lose your voting rights.
|
||||||
"""
|
"""
|
||||||
if not inside_brackets:
|
if not inside_brackets:
|
||||||
spl = leaf.prefix.split('#', 1)
|
spl = leaf.prefix.split('#')
|
||||||
if '\\' not in spl[0]:
|
if '\\' not in spl[0]:
|
||||||
nl_count = spl[0].count('\n')
|
nl_count = spl[-1].count('\n')
|
||||||
|
if len(spl) > 1:
|
||||||
|
nl_count -= 1
|
||||||
leaf.prefix = '\n' * nl_count
|
leaf.prefix = '\n' * nl_count
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
|
|
||||||
# Some comment before a function.
|
# Some comment before a function.
|
||||||
|
|
||||||
|
|
||||||
def function(default=None):
|
def function(default=None):
|
||||||
"""Docstring comes first.
|
"""Docstring comes first.
|
||||||
|
|
||||||
@ -43,7 +45,10 @@ def function(default=None):
|
|||||||
GLOBAL_STATE = {'a': a(1), 'b': a(2), 'c': a(3)}
|
GLOBAL_STATE = {'a': a(1), 'b': a(2), 'c': a(3)}
|
||||||
|
|
||||||
|
|
||||||
# Another comment
|
# Another comment!
|
||||||
|
# This time two lines.
|
||||||
|
|
||||||
|
|
||||||
@fast(really=True)
|
@fast(really=True)
|
||||||
async def wat():
|
async def wat():
|
||||||
async with X.open_async() as x: # Some more comments
|
async with X.open_async() as x: # Some more comments
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Please keep __all__ alphabetized within each category.
|
# Please keep __all__ alphabetized within each category.
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# Super-special typing primitives.
|
# Super-special typing primitives.
|
||||||
'Any',
|
'Any',
|
||||||
@ -22,6 +23,7 @@
|
|||||||
'Generator',
|
'Generator',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Comment before function.
|
||||||
def inline_comments_in_brackets_ruin_everything():
|
def inline_comments_in_brackets_ruin_everything():
|
||||||
if typedargslist:
|
if typedargslist:
|
||||||
parameters.children = [
|
parameters.children = [
|
||||||
@ -42,11 +44,14 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
# transport hasn't been notified yet?
|
# transport hasn't been notified yet?
|
||||||
and self._proc.poll() is None):
|
and self._proc.poll() is None):
|
||||||
pass
|
pass
|
||||||
|
# no newline before or after
|
||||||
short = [
|
short = [
|
||||||
# one
|
# one
|
||||||
1,
|
1,
|
||||||
# two
|
# two
|
||||||
2]
|
2]
|
||||||
|
|
||||||
|
# no newline after
|
||||||
call(arg1, arg2, """
|
call(arg1, arg2, """
|
||||||
short
|
short
|
||||||
""", arg3=True)
|
""", arg3=True)
|
||||||
@ -85,6 +90,14 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
# right
|
# right
|
||||||
if element is not None
|
if element is not None
|
||||||
]
|
]
|
||||||
|
while True:
|
||||||
|
if False:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# and round and round we go
|
||||||
|
# and round and round we go
|
||||||
|
|
||||||
|
# let's return
|
||||||
return Node(
|
return Node(
|
||||||
syms.simple_stmt,
|
syms.simple_stmt,
|
||||||
[
|
[
|
||||||
@ -93,6 +106,12 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#######################
|
||||||
|
### SECTION COMMENT ###
|
||||||
|
#######################
|
||||||
|
|
||||||
|
|
||||||
instruction()
|
instruction()
|
||||||
|
|
||||||
# END COMMENTS
|
# END COMMENTS
|
||||||
@ -103,6 +122,7 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
|
|
||||||
|
|
||||||
# Please keep __all__ alphabetized within each category.
|
# Please keep __all__ alphabetized within each category.
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
# Super-special typing primitives.
|
# Super-special typing primitives.
|
||||||
'Any',
|
'Any',
|
||||||
@ -124,6 +144,8 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
'Generator',
|
'Generator',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Comment before function.
|
||||||
|
|
||||||
|
|
||||||
def inline_comments_in_brackets_ruin_everything():
|
def inline_comments_in_brackets_ruin_everything():
|
||||||
if typedargslist:
|
if typedargslist:
|
||||||
@ -145,12 +167,15 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
and self._proc.poll() is None
|
and self._proc.poll() is None
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
# no newline before or after
|
||||||
short = [
|
short = [
|
||||||
# one
|
# one
|
||||||
1,
|
1,
|
||||||
# two
|
# two
|
||||||
2,
|
2,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# no newline after
|
||||||
call(
|
call(
|
||||||
arg1,
|
arg1,
|
||||||
arg2,
|
arg2,
|
||||||
@ -161,6 +186,7 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
)
|
)
|
||||||
|
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
call2(
|
call2(
|
||||||
# short
|
# short
|
||||||
arg1,
|
arg1,
|
||||||
@ -192,12 +218,26 @@ def inline_comments_in_brackets_ruin_everything():
|
|||||||
# right
|
# right
|
||||||
if element is not None
|
if element is not None
|
||||||
]
|
]
|
||||||
|
while True:
|
||||||
|
if False:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# and round and round we go
|
||||||
|
# and round and round we go
|
||||||
|
|
||||||
|
# let's return
|
||||||
return Node(
|
return Node(
|
||||||
syms.simple_stmt,
|
syms.simple_stmt,
|
||||||
[Node(statement, result), Leaf(token.NEWLINE, '\n')], # FIXME: \r\n?
|
[Node(statement, result), Leaf(token.NEWLINE, '\n')], # FIXME: \r\n?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#######################
|
||||||
|
### SECTION COMMENT ###
|
||||||
|
#######################
|
||||||
|
|
||||||
|
|
||||||
instruction()
|
instruction()
|
||||||
|
|
||||||
# END COMMENTS
|
# END COMMENTS
|
||||||
# MORE END COMMENTS
|
# MORE END COMMENTS
|
||||||
|
@ -40,13 +40,9 @@ def f():
|
|||||||
syms.dictsetmaker,
|
syms.dictsetmaker,
|
||||||
}:
|
}:
|
||||||
return NO
|
return NO
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# SECTION BECAUSE SECTIONS
|
# SECTION BECAUSE SECTIONS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
NO = ''
|
NO = ''
|
||||||
SPACE = ' '
|
SPACE = ' '
|
||||||
@ -135,6 +131,8 @@ def f():
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
# SECTION BECAUSE SECTIONS
|
# SECTION BECAUSE SECTIONS
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
def g():
|
def g():
|
||||||
NO = ''
|
NO = ''
|
||||||
SPACE = ' '
|
SPACE = ' '
|
||||||
@ -145,6 +143,7 @@ def g():
|
|||||||
v = leaf.value
|
v = leaf.value
|
||||||
|
|
||||||
# Comment because comments
|
# Comment because comments
|
||||||
|
|
||||||
if t in ALWAYS_NO_SPACE:
|
if t in ALWAYS_NO_SPACE:
|
||||||
pass
|
pass
|
||||||
if t == token.COMMENT:
|
if t == token.COMMENT:
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
"""The asyncio package, tracking PEP 3156."""
|
"""The asyncio package, tracking PEP 3156."""
|
||||||
|
|
||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# This relies on each of the submodules having an __all__ variable.
|
# This relies on each of the submodules having an __all__ variable.
|
||||||
|
Loading…
Reference in New Issue
Block a user