From 026c81b83454f176a9f9253cbfb70be2c159d822 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Langa?= Date: Thu, 14 Mar 2019 18:09:10 +0100 Subject: [PATCH 01/16] v19.3b0 --- black.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/black.py b/black.py index 24ff781..b727666 100644 --- a/black.py +++ b/black.py @@ -49,7 +49,7 @@ from blib2to3.pgen2.grammar import Grammar from blib2to3.pgen2.parse import ParseError -__version__ = "18.9b0" +__version__ = "19.3b0" DEFAULT_LINE_LENGTH = 88 DEFAULT_EXCLUDES = ( r"/(\.eggs|\.git|\.hg|\.mypy_cache|\.nox|\.tox|\.venv|_build|buck-out|build|dist)/" diff --git a/pyproject.toml b/pyproject.toml index 1cb3822..3b192bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ exclude = ''' [tool.poetry] name = "black" -version = "18.9b0" +version = "19.3b0" description = "The uncompromising code formatter." readme = "README.md" authors = [ -- 2.39.5 From d6db1c12a8e14833fe22da377cddc2bd1f43dc14 Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Thu, 14 Mar 2019 16:42:54 -0700 Subject: [PATCH 02/16] Fix print() function on Python 2 (#754) Fixes #752 --- black.py | 4 ++-- tests/data/python2_print_function.py | 16 ++++++++++++++++ tests/test_black.py | 8 ++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100755 tests/data/python2_print_function.py diff --git a/black.py b/black.py index b727666..c44bc9b 100644 --- a/black.py +++ b/black.py @@ -726,13 +726,13 @@ def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: if not target_versions: return GRAMMARS elif all(not version.is_python2() for version in target_versions): - # Python 2-compatible code, so don't try Python 3 grammar. + # Python 3-compatible code, so don't try Python 2 grammar return [ pygram.python_grammar_no_print_statement_no_exec_statement, pygram.python_grammar_no_print_statement, ] else: - return [pygram.python_grammar] + return [pygram.python_grammar_no_print_statement, pygram.python_grammar] def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node: diff --git a/tests/data/python2_print_function.py b/tests/data/python2_print_function.py new file mode 100755 index 0000000..81b8d8a --- /dev/null +++ b/tests/data/python2_print_function.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python2 +from __future__ import print_function + +print('hello') +print(u'hello') +print(a, file=sys.stderr) + +# output + + +#!/usr/bin/env python2 +from __future__ import print_function + +print("hello") +print(u"hello") +print(a, file=sys.stderr) diff --git a/tests/test_black.py b/tests/test_black.py index 7c99f00..645eec7 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -461,6 +461,14 @@ class BlackTestCase(unittest.TestCase): # black.assert_equivalent(source, actual) black.assert_stable(source, actual, black.FileMode()) + @patch("black.dump_to_file", dump_to_stderr) + def test_python2_print_function(self) -> None: + source, expected = read_data("python2_print_function") + mode = black.FileMode(target_versions={black.TargetVersion.PY27}) + actual = fs(source, mode=mode) + self.assertFormatEqual(expected, actual) + black.assert_stable(source, actual, mode) + @patch("black.dump_to_file", dump_to_stderr) def test_python2_unicode_literals(self) -> None: source, expected = read_data("python2_unicode_literals") -- 2.39.5 From b396f137618e4eb7c73b49033530383c45b160f3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 15 Mar 2019 10:39:08 -0700 Subject: [PATCH 03/16] fix incorrect call (#762) --- black.py | 2 +- tests/data/composition.py | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/black.py b/black.py index c44bc9b..680b1f4 100644 --- a/black.py +++ b/black.py @@ -2206,7 +2206,7 @@ def split_line( # All splits failed, best effort split with no omits. # This mostly happens to multiline strings that are by definition # reported as not fitting a single line. - yield from right_hand_split(line, supports_trailing_commas) + yield from right_hand_split(line, line_length, supports_trailing_commas) if line.inside_brackets: split_funcs = [delimiter_split, standalone_comment_split, rhs] diff --git a/tests/data/composition.py b/tests/data/composition.py index ac63e46..31f5bd5 100644 --- a/tests/data/composition.py +++ b/tests/data/composition.py @@ -166,17 +166,14 @@ class C: _C.__init__.__code__.co_firstlineno + 1, ) - assert ( - expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect - == { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - ) + assert expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect == { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } -- 2.39.5 From f92cd878ad038c40e1059fafed71ad9aafa1ef12 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 15 Mar 2019 11:42:24 -0700 Subject: [PATCH 04/16] add change log entry (#764) --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 2574c55..dbb7922 100644 --- a/README.md +++ b/README.md @@ -951,6 +951,11 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). ## Change Log +### 19.3b1 + +* fix bug that led *Black* format some code with a line length target of 1 + (#762) + ### 19.3b0 * new option `--target-version` to control which Python versions -- 2.39.5 From f68500497f19958067d3e81461ce934ed1351003 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Sat, 16 Mar 2019 14:00:59 +0000 Subject: [PATCH 05/16] Use new github token for appveyor release --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6dadfb3..948c53b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,9 +18,9 @@ artifacts: deploy: provider: GitHub - description: '' + description: 'Windows binary' auth_token: - secure: caPP8BcGffPuTopDfdI4ZVKZkpD9l9UAcjO7rwm5/fFSMbsqh1v4S38nmMn4uSuD + secure: uplI9CJ2dTGcEBCbZuIn+Qb4rC38hOoRSH9lcwuGCr5g9fSnhK1MZdNT6Cjf/mFL on: appveyor_repo_tag: true -- 2.39.5 From 2410213857d3cfb08a40350a9302b62d05df3c62 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Sat, 16 Mar 2019 16:26:50 +0000 Subject: [PATCH 06/16] fix appveyor deploy section --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 948c53b..6389f45 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,9 +18,9 @@ artifacts: deploy: provider: GitHub - description: 'Windows binary' + description: '' auth_token: secure: uplI9CJ2dTGcEBCbZuIn+Qb4rC38hOoRSH9lcwuGCr5g9fSnhK1MZdNT6Cjf/mFL on: - appveyor_repo_tag: true + APPVEYOR_REPO_TAG: true -- 2.39.5 From ba64fc757c12e59fb35f2306eb4fa75fdc566647 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sat, 16 Mar 2019 11:35:18 -0700 Subject: [PATCH 07/16] redo grammar selection, add test (#765) --- black.py | 18 +++++++----------- tests/test_black.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/black.py b/black.py index 680b1f4..2dee826 100644 --- a/black.py +++ b/black.py @@ -715,24 +715,20 @@ def decode_bytes(src: bytes) -> Tuple[FileContent, Encoding, NewLine]: return tiow.read(), encoding, newline -GRAMMARS = [ - pygram.python_grammar_no_print_statement_no_exec_statement, - pygram.python_grammar_no_print_statement, - pygram.python_grammar, -] - - def get_grammars(target_versions: Set[TargetVersion]) -> List[Grammar]: if not target_versions: - return GRAMMARS - elif all(not version.is_python2() for version in target_versions): - # Python 3-compatible code, so don't try Python 2 grammar + # No target_version specified, so try all grammars. return [ pygram.python_grammar_no_print_statement_no_exec_statement, pygram.python_grammar_no_print_statement, + pygram.python_grammar, ] - else: + elif all(version.is_python2() for version in target_versions): + # Python 2-only code, so try Python 2 grammars. return [pygram.python_grammar_no_print_statement, pygram.python_grammar] + else: + # Python 3-compatible code, so only try Python 3 grammar. + return [pygram.python_grammar_no_print_statement_no_exec_statement] def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) -> Node: diff --git a/tests/test_black.py b/tests/test_black.py index 645eec7..a3e2ff8 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -28,7 +28,7 @@ from click import unstyle from click.testing import CliRunner import black -from black import Feature +from black import Feature, TargetVersion try: import blackd @@ -464,7 +464,7 @@ class BlackTestCase(unittest.TestCase): @patch("black.dump_to_file", dump_to_stderr) def test_python2_print_function(self) -> None: source, expected = read_data("python2_print_function") - mode = black.FileMode(target_versions={black.TargetVersion.PY27}) + mode = black.FileMode(target_versions={TargetVersion.PY27}) actual = fs(source, mode=mode) self.assertFormatEqual(expected, actual) black.assert_stable(source, actual, mode) @@ -828,6 +828,31 @@ class BlackTestCase(unittest.TestCase): "2 files would fail to reformat.", ) + def test_lib2to3_parse(self) -> None: + with self.assertRaises(black.InvalidInput): + black.lib2to3_parse("invalid syntax") + + straddling = "x + y" + black.lib2to3_parse(straddling) + black.lib2to3_parse(straddling, {TargetVersion.PY27}) + black.lib2to3_parse(straddling, {TargetVersion.PY36}) + black.lib2to3_parse(straddling, {TargetVersion.PY27, TargetVersion.PY36}) + + py2_only = "print x" + black.lib2to3_parse(py2_only) + black.lib2to3_parse(py2_only, {TargetVersion.PY27}) + with self.assertRaises(black.InvalidInput): + black.lib2to3_parse(py2_only, {TargetVersion.PY36}) + with self.assertRaises(black.InvalidInput): + black.lib2to3_parse(py2_only, {TargetVersion.PY27, TargetVersion.PY36}) + + py3_only = "exec(x, end=y)" + black.lib2to3_parse(py3_only) + with self.assertRaises(black.InvalidInput): + black.lib2to3_parse(py3_only, {TargetVersion.PY27}) + black.lib2to3_parse(py3_only, {TargetVersion.PY36}) + black.lib2to3_parse(py3_only, {TargetVersion.PY27, TargetVersion.PY36}) + def test_get_features_used(self) -> None: node = black.lib2to3_parse("def f(*, arg): ...\n") self.assertEqual(black.get_features_used(node), set()) -- 2.39.5 From a2f6706a1ea026cbe0e7d83caffa6c13c463bfe1 Mon Sep 17 00:00:00 2001 From: Thom Lu Date: Sun, 17 Mar 2019 11:27:50 -0500 Subject: [PATCH 08/16] fix vim plugin for 19.3b0 (#755) (#766) --- plugin/black.vim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plugin/black.vim b/plugin/black.vim index f0b55b2..36825cf 100644 --- a/plugin/black.vim +++ b/plugin/black.vim @@ -98,15 +98,14 @@ if _initialize_black_env(): def Black(): start = time.time() fast = bool(int(vim.eval("g:black_fast"))) - line_length = int(vim.eval("g:black_linelength")) - mode = black.FileMode.AUTO_DETECT - if bool(int(vim.eval("g:black_skip_string_normalization"))): - mode |= black.FileMode.NO_STRING_NORMALIZATION - if vim.current.buffer.name.endswith('.pyi'): - mode |= black.FileMode.PYI + mode = black.FileMode( + line_length=int(vim.eval("g:black_linelength")), + string_normalization=not bool(int(vim.eval("g:black_skip_string_normalization"))), + is_pyi=vim.current.buffer.name.endswith('.pyi'), + ) buffer_str = '\n'.join(vim.current.buffer) + '\n' try: - new_buffer_str = black.format_file_contents(buffer_str, line_length=line_length, fast=fast, mode=mode) + new_buffer_str = black.format_file_contents(buffer_str, fast=fast, mode=mode) except black.NothingChanged: print(f'Already well formatted, good job. (took {time.time() - start:.4f}s)') except Exception as exc: -- 2.39.5 From 0b7913f904a0be6c0e48df1c5a6de29e4ea38d81 Mon Sep 17 00:00:00 2001 From: Daniele Esposti Date: Wed, 20 Mar 2019 15:40:01 +0000 Subject: [PATCH 09/16] Terget version option kebab-style (#770) --- README.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dbb7922..540960e 100644 --- a/README.md +++ b/README.md @@ -577,7 +577,7 @@ to denote a significant space character. ```toml [tool.black] line-length = 88 -target_version = ['py37'] +target-version = ['py37'] include = '\.pyi?$' exclude = ''' diff --git a/pyproject.toml b/pyproject.toml index 3b192bf..d88fabe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ [tool.black] line-length = 88 -target_version = ['py36', 'py37', 'py38'] +target-version = ['py36', 'py37', 'py38'] include = '\.pyi?$' exclude = ''' /( -- 2.39.5 From cea13f498418784e22f8fbd78db3f9240a2bad11 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 25 Mar 2019 08:22:02 -0700 Subject: [PATCH 10/16] Split the TRAILING_COMMA feature (#763) --- black.py | 98 ++++++++++++++++++++++----------------------- tests/test_black.py | 23 ++++++----- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/black.py b/black.py index 2dee826..0ea9b9a 100644 --- a/black.py +++ b/black.py @@ -68,7 +68,7 @@ LeafID = int Priority = int Index = int LN = Union[Leaf, Node] -SplitFunc = Callable[["Line", bool], Iterator["Line"]] +SplitFunc = Callable[["Line", Collection["Feature"]], Iterator["Line"]] Timestamp = float FileSize = int CacheInfo = Tuple[Timestamp, FileSize] @@ -133,31 +133,35 @@ class Feature(Enum): UNICODE_LITERALS = 1 F_STRINGS = 2 NUMERIC_UNDERSCORES = 3 - TRAILING_COMMA = 4 + TRAILING_COMMA_IN_CALL = 4 + TRAILING_COMMA_IN_DEF = 5 VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = { TargetVersion.PY27: set(), TargetVersion.PY33: {Feature.UNICODE_LITERALS}, TargetVersion.PY34: {Feature.UNICODE_LITERALS}, - TargetVersion.PY35: {Feature.UNICODE_LITERALS, Feature.TRAILING_COMMA}, + TargetVersion.PY35: {Feature.UNICODE_LITERALS, Feature.TRAILING_COMMA_IN_CALL}, TargetVersion.PY36: { Feature.UNICODE_LITERALS, Feature.F_STRINGS, Feature.NUMERIC_UNDERSCORES, - Feature.TRAILING_COMMA, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, }, TargetVersion.PY37: { Feature.UNICODE_LITERALS, Feature.F_STRINGS, Feature.NUMERIC_UNDERSCORES, - Feature.TRAILING_COMMA, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, }, TargetVersion.PY38: { Feature.UNICODE_LITERALS, Feature.F_STRINGS, Feature.NUMERIC_UNDERSCORES, - Feature.TRAILING_COMMA, + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, }, } @@ -683,6 +687,11 @@ def format_str(src_contents: str, *, mode: FileMode) -> FileContent: elt = EmptyLineTracker(is_pyi=mode.is_pyi) empty_line = Line() after = 0 + split_line_features = { + feature + for feature in {Feature.TRAILING_COMMA_IN_CALL, Feature.TRAILING_COMMA_IN_DEF} + if supports_feature(versions, feature) + } for current_line in lines.visit(src_node): for _ in range(after): dst_contents += str(empty_line) @@ -690,9 +699,7 @@ def format_str(src_contents: str, *, mode: FileMode) -> FileContent: for _ in range(before): dst_contents += str(empty_line) for line in split_line( - current_line, - line_length=mode.line_length, - supports_trailing_commas=supports_feature(versions, Feature.TRAILING_COMMA), + current_line, line_length=mode.line_length, features=split_line_features ): dst_contents += str(line) return dst_contents @@ -2158,7 +2165,7 @@ def split_line( line: Line, line_length: int, inner: bool = False, - supports_trailing_commas: bool = False, + features: Collection[Feature] = (), ) -> Iterator[Line]: """Split a `line` into potentially many lines. @@ -2167,7 +2174,7 @@ def split_line( current `line`, possibly transitively. This means we can fallback to splitting by delimiters if the LHS/RHS don't yield any results. - If `supports_trailing_commas` is True, splitting may use the TRAILING_COMMA feature. + `features` are syntactical features that may be used in the output. """ if line.is_comment: yield line @@ -2188,13 +2195,9 @@ def split_line( split_funcs = [left_hand_split] else: - def rhs(line: Line, supports_trailing_commas: bool = False) -> Iterator[Line]: + def rhs(line: Line, features: Collection[Feature]) -> Iterator[Line]: for omit in generate_trailers_to_omit(line, line_length): - lines = list( - right_hand_split( - line, line_length, supports_trailing_commas, omit=omit - ) - ) + lines = list(right_hand_split(line, line_length, features, omit=omit)) if is_line_short_enough(lines[0], line_length=line_length): yield from lines return @@ -2202,7 +2205,7 @@ def split_line( # All splits failed, best effort split with no omits. # This mostly happens to multiline strings that are by definition # reported as not fitting a single line. - yield from right_hand_split(line, line_length, supports_trailing_commas) + yield from right_hand_split(line, line_length, features=features) if line.inside_brackets: split_funcs = [delimiter_split, standalone_comment_split, rhs] @@ -2214,16 +2217,13 @@ def split_line( # split altogether. result: List[Line] = [] try: - for l in split_func(line, supports_trailing_commas): + for l in split_func(line, features): if str(l).strip("\n") == line_str: raise CannotSplit("Split function returned an unchanged result") result.extend( split_line( - l, - line_length=line_length, - inner=True, - supports_trailing_commas=supports_trailing_commas, + l, line_length=line_length, inner=True, features=features ) ) except CannotSplit: @@ -2237,9 +2237,7 @@ def split_line( yield line -def left_hand_split( - line: Line, supports_trailing_commas: bool = False -) -> Iterator[Line]: +def left_hand_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: """Split line into many lines, starting with the first matching bracket pair. Note: this usually looks weird, only use this for function definitions. @@ -2278,7 +2276,7 @@ def left_hand_split( def right_hand_split( line: Line, line_length: int, - supports_trailing_commas: bool = False, + features: Collection[Feature] = (), omit: Collection[LeafID] = (), ) -> Iterator[Line]: """Split line into many lines, starting with the last matching bracket pair. @@ -2337,12 +2335,7 @@ def right_hand_split( ): omit = {id(closing_bracket), *omit} try: - yield from right_hand_split( - line, - line_length, - supports_trailing_commas=supports_trailing_commas, - omit=omit, - ) + yield from right_hand_split(line, line_length, features=features, omit=omit) return except CannotSplit: @@ -2431,10 +2424,8 @@ def dont_increase_indentation(split_func: SplitFunc) -> SplitFunc: """ @wraps(split_func) - def split_wrapper( - line: Line, supports_trailing_commas: bool = False - ) -> Iterator[Line]: - for l in split_func(line, supports_trailing_commas): + def split_wrapper(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: + for l in split_func(line, features): normalize_prefix(l.leaves[0], inside_brackets=True) yield l @@ -2442,13 +2433,11 @@ def dont_increase_indentation(split_func: SplitFunc) -> SplitFunc: @dont_increase_indentation -def delimiter_split( - line: Line, supports_trailing_commas: bool = False -) -> Iterator[Line]: +def delimiter_split(line: Line, features: Collection[Feature] = ()) -> Iterator[Line]: """Split according to delimiters of the highest priority. - If `supports_trailing_commas` is True, the split will add trailing commas - also in function signatures that contain `*` and `**`. + If the appropriate Features are given, the split will add trailing commas + also in function signatures and calls that contain `*` and `**`. """ try: last_leaf = line.leaves[-1] @@ -2487,10 +2476,16 @@ def delimiter_split( yield from append_to_line(comment_after) lowest_depth = min(lowest_depth, leaf.bracket_depth) - if leaf.bracket_depth == lowest_depth and is_vararg( - leaf, within=VARARGS_PARENTS - ): - trailing_comma_safe = trailing_comma_safe and supports_trailing_commas + if leaf.bracket_depth == lowest_depth: + if is_vararg(leaf, within={syms.typedargslist}): + trailing_comma_safe = ( + trailing_comma_safe and Feature.TRAILING_COMMA_IN_DEF in features + ) + elif is_vararg(leaf, within={syms.arglist, syms.argument}): + trailing_comma_safe = ( + trailing_comma_safe and Feature.TRAILING_COMMA_IN_CALL in features + ) + leaf_priority = bt.delimiters.get(id(leaf)) if leaf_priority == delimiter_priority: yield current_line @@ -2509,7 +2504,7 @@ def delimiter_split( @dont_increase_indentation def standalone_comment_split( - line: Line, supports_trailing_commas: bool = False + line: Line, features: Collection[Feature] = () ) -> Iterator[Line]: """Split standalone comments from the rest of the line.""" if not line.contains_standalone_comments(0): @@ -3059,14 +3054,19 @@ def get_features_used(node: Node) -> Set[Feature]: and n.children and n.children[-1].type == token.COMMA ): + if n.type == syms.typedargslist: + feature = Feature.TRAILING_COMMA_IN_DEF + else: + feature = Feature.TRAILING_COMMA_IN_CALL + for ch in n.children: if ch.type in STARS: - features.add(Feature.TRAILING_COMMA) + features.add(feature) if ch.type == syms.argument: for argch in ch.children: if argch.type in STARS: - features.add(Feature.TRAILING_COMMA) + features.add(feature) return features diff --git a/tests/test_black.py b/tests/test_black.py index a3e2ff8..3e0b8a1 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -857,7 +857,11 @@ class BlackTestCase(unittest.TestCase): node = black.lib2to3_parse("def f(*, arg): ...\n") self.assertEqual(black.get_features_used(node), set()) node = black.lib2to3_parse("def f(*, arg,): ...\n") - self.assertEqual(black.get_features_used(node), {Feature.TRAILING_COMMA}) + self.assertEqual(black.get_features_used(node), {Feature.TRAILING_COMMA_IN_DEF}) + node = black.lib2to3_parse("f(*arg,)\n") + self.assertEqual( + black.get_features_used(node), {Feature.TRAILING_COMMA_IN_CALL} + ) node = black.lib2to3_parse("def f(*, arg): f'string'\n") self.assertEqual(black.get_features_used(node), {Feature.F_STRINGS}) node = black.lib2to3_parse("123_456\n") @@ -866,13 +870,14 @@ class BlackTestCase(unittest.TestCase): self.assertEqual(black.get_features_used(node), set()) source, expected = read_data("function") node = black.lib2to3_parse(source) - self.assertEqual( - black.get_features_used(node), {Feature.TRAILING_COMMA, Feature.F_STRINGS} - ) + expected_features = { + Feature.TRAILING_COMMA_IN_CALL, + Feature.TRAILING_COMMA_IN_DEF, + Feature.F_STRINGS, + } + self.assertEqual(black.get_features_used(node), expected_features) node = black.lib2to3_parse(expected) - self.assertEqual( - black.get_features_used(node), {Feature.TRAILING_COMMA, Feature.F_STRINGS} - ) + self.assertEqual(black.get_features_used(node), expected_features) source, expected = read_data("expression") node = black.lib2to3_parse(source) self.assertEqual(black.get_features_used(node), set()) @@ -1524,8 +1529,8 @@ class BlackTestCase(unittest.TestCase): await check("3.6", 200) await check("py3.6", 200) - await check("3.5,3.7", 200) - await check("3.5,py3.7", 200) + await check("3.6,3.7", 200) + await check("3.6,py3.7", 200) await check("2", 204) await check("2.7", 204) -- 2.39.5 From acafdcb5945cda8d424b2dbd0f9d0d56cf658533 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 2 May 2019 19:03:02 +0200 Subject: [PATCH 11/16] minor: remove wrong comment in .flake8 (#788) This is there since the initial commit, which did not have a setup.cfg. --- .flake8 | 3 --- 1 file changed, 3 deletions(-) diff --git a/.flake8 b/.flake8 index c286ad0..c321e71 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,3 @@ -# This is an example .flake8 config, used when developing *Black* itself. -# Keep in sync with setup.cfg which is used for source packages. - [flake8] ignore = E203, E266, E501, W503 max-line-length = 80 -- 2.39.5 From 597a0e102cce49a61b4bb01645f313bbbc86487e Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 2 May 2019 22:09:49 +0300 Subject: [PATCH 12/16] Fix B011 (#820) Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError(). --- black.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/black.py b/black.py index 0ea9b9a..234bfb5 100644 --- a/black.py +++ b/black.py @@ -3146,7 +3146,7 @@ def get_future_imports(node: Node) -> Set[str]: elif child.type == syms.import_as_names: yield from get_imports_from_children(child.children) else: - assert False, "Invalid syntax parsing imports" + raise AssertionError("Invalid syntax parsing imports") for child in node.children: if child.type != syms.simple_stmt: -- 2.39.5 From 4a953b7241ce5f8bcac985fa33fdf3af4f42c0de Mon Sep 17 00:00:00 2001 From: Hugo Date: Thu, 2 May 2019 22:19:52 +0300 Subject: [PATCH 13/16] ambv/black -> python/black (#819) --- .travis.yml | 2 +- CONTRIBUTING.md | 2 +- README.md | 26 +++++++++++++------------- black.py | 6 +++--- docs/conf.py | 2 +- docs/environment.yml | 2 +- pyproject.toml | 2 +- setup.py | 2 +- 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index c0cd5ab..d594373 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,5 +49,5 @@ deploy: skip_cleanup: true on: condition: $TRAVIS_PYTHON_VERSION == '3.6' - repo: ambv/black + repo: python/black tags: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b0b3a75..7661f45 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,7 +11,7 @@ In terms of inspiration, *Black* is about as configurable as *gofmt*. This is deliberate. Bug reports and fixes are always welcome! Please follow the [issue -template on GitHub](https://github.com/ambv/black/issues/new) for best +template on GitHub](https://github.com/python/black/issues/new) for best results. Before you suggest a new feature or configuration knob, ask yourself why diff --git a/README.md b/README.md index 540960e..7e3c01d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -![Black Logo](https://raw.githubusercontent.com/ambv/black/master/docs/_static/logo2-readme.png) +![Black Logo](https://raw.githubusercontent.com/python/black/master/docs/_static/logo2-readme.png)

The Uncompromising Code Formatter

-Build Status +Build Status Documentation Status -Coverage Status -License: MIT +Coverage Status +License: MIT PyPI Downloads -Code style: black +Code style: black

> “Any color you like.” @@ -370,7 +370,7 @@ The main reason to standardize on a single form of quotes is aesthetics. Having one kind of quotes everywhere reduces reader distraction. It will also enable a future version of *Black* to merge consecutive string literals that ended up on the same line (see -[#26](https://github.com/ambv/black/issues/26) for details). +[#26](https://github.com/python/black/issues/26) for details). Why settle on double quotes? They anticipate apostrophes in English text. They match the docstring standard described in [PEP 257](https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring). @@ -694,16 +694,16 @@ Configuration: To install with [vim-plug](https://github.com/junegunn/vim-plug): ``` -Plug 'ambv/black' +Plug 'python/black' ``` or with [Vundle](https://github.com/VundleVim/Vundle.vim): ``` -Plugin 'ambv/black' +Plugin 'python/black' ``` -or you can copy the plugin from [plugin/black.vim](https://github.com/ambv/black/tree/master/plugin/black.vim). +or you can copy the plugin from [plugin/black.vim](https://github.com/python/black/tree/master/plugin/black.vim). Let me know if this requires any changes to work with Vim 8's builtin `packadd`, or Pathogen, and so on. @@ -856,7 +856,7 @@ installed](https://pre-commit.com/#install), add this to the `.pre-commit-config.yaml` in your repository: ```yaml repos: -- repo: https://github.com/ambv/black +- repo: https://github.com/python/black rev: stable hooks: - id: black @@ -916,16 +916,16 @@ and [`pipenv`](https://docs.pipenv.org/): Use the badge in your project's README.md: ```markdown -[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) +[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black) ``` Using the badge in README.rst: ``` .. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/ambv/black + :target: https://github.com/python/black ``` -Looks like this: [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) +Looks like this: [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black) ## License diff --git a/black.py b/black.py index 234bfb5..90aaf38 100644 --- a/black.py +++ b/black.py @@ -3386,7 +3386,7 @@ def assert_equivalent(src: str, dst: str) -> None: log = dump_to_file("".join(traceback.format_tb(exc.__traceback__)), dst) raise AssertionError( f"INTERNAL ERROR: Black produced invalid code: {exc}. " - f"Please report a bug on https://github.com/ambv/black/issues. " + f"Please report a bug on https://github.com/python/black/issues. " f"This invalid output might be helpful: {log}" ) from None @@ -3397,7 +3397,7 @@ def assert_equivalent(src: str, dst: str) -> None: raise AssertionError( f"INTERNAL ERROR: Black produced code that is not equivalent to " f"the source. " - f"Please report a bug on https://github.com/ambv/black/issues. " + f"Please report a bug on https://github.com/python/black/issues. " f"This diff might be helpful: {log}" ) from None @@ -3413,7 +3413,7 @@ def assert_stable(src: str, dst: str, mode: FileMode) -> None: raise AssertionError( f"INTERNAL ERROR: Black produced different code on the second pass " f"of the formatter. " - f"Please report a bug on https://github.com/ambv/black/issues. " + f"Please report a bug on https://github.com/python/black/issues. " f"This diff might be helpful: {log}" ) from None diff --git a/docs/conf.py b/docs/conf.py index 7d2b0b1..0ddca26 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -161,7 +161,7 @@ html_theme_options = { "show_related": False, "description": "“Any color you like.”", "github_button": True, - "github_user": "ambv", + "github_user": "python", "github_repo": "black", "github_type": "star", "show_powered_by": True, diff --git a/docs/environment.yml b/docs/environment.yml index a60f92c..d098a9d 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -6,4 +6,4 @@ dependencies: - Sphinx==1.7.2 - pip: - recommonmark==0.4.0 - - git+https://git@github.com/ambv/black.git + - git+https://git@github.com/python/black.git diff --git a/pyproject.toml b/pyproject.toml index d88fabe..186bd0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ authors = [ "Mika Naylor ", "Zsolt Dollenstein ", ] -homepage = "https://github.com/ambv/black/" +homepage = "https://github.com/python/black/" documentation = "https://black.readthedocs.io/en/stable/" license = "MIT" keywords = ["automation", "formatter", "yapf", "autopep8", "gofmt"] diff --git a/setup.py b/setup.py index 620124f..b12d4ac 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ setup( keywords="automation formatter yapf autopep8 pyfmt gofmt rustfmt", author="Łukasz Langa", author_email="lukasz@langa.pl", - url="https://github.com/ambv/black", + url="https://github.com/python/black", license="MIT", py_modules=["black", "blackd"], packages=["blib2to3", "blib2to3.pgen2"], -- 2.39.5 From e6ddb68c786256e1cb0c76b42d10c212ef34cb2a Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sun, 5 May 2019 19:58:26 +0100 Subject: [PATCH 14/16] Wrap `loop.run_in_executor` up in `asyncio.ensure_future` for reliable cross-platform berhavior. (#679) Closes #494 Task completion should also remove the task from `pending`. Only replicates on some platforms. (eg. Can replicate on Python 3.7+, with either Windows or whatever default Linux distro Travis uses.) --- black.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/black.py b/black.py index 90aaf38..dd6e372 100644 --- a/black.py +++ b/black.py @@ -526,12 +526,14 @@ async def schedule_formatting( manager = Manager() lock = manager.Lock() tasks = { - loop.run_in_executor( - executor, format_file_in_place, src, fast, mode, write_back, lock + asyncio.ensure_future( + loop.run_in_executor( + executor, format_file_in_place, src, fast, mode, write_back, lock + ) ): src for src in sorted(sources) } - pending: Iterable[asyncio.Task] = tasks.keys() + pending: Iterable[asyncio.Future] = tasks.keys() try: loop.add_signal_handler(signal.SIGINT, cancel, pending) loop.add_signal_handler(signal.SIGTERM, cancel, pending) -- 2.39.5 From 6b994fdb8ab70ce4c2eafb8f2f0ff2648f3ff1ef Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 6 May 2019 09:13:25 -0400 Subject: [PATCH 15/16] fix handling of comments in from imports (#829) Fixes #671 --- black.py | 13 ++++++++--- tests/data/comments7.py | 51 +++++++++++++++++++++++++++++++++++++++++ tests/test_black.py | 8 +++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 tests/data/comments7.py diff --git a/black.py b/black.py index dd6e372..9ecfbe1 100644 --- a/black.py +++ b/black.py @@ -2405,10 +2405,17 @@ def bracket_split_build_line( if leaves: # Since body is a new indent level, remove spurious leading whitespace. normalize_prefix(leaves[0], inside_brackets=True) - # Ensure a trailing comma when expected. + # Ensure a trailing comma for imports, but be careful not to add one after + # any comments. if original.is_import: - if leaves[-1].type != token.COMMA: - leaves.append(Leaf(token.COMMA, ",")) + for i in range(len(leaves) - 1, -1, -1): + if leaves[i].type == STANDALONE_COMMENT: + continue + elif leaves[i].type == token.COMMA: + break + else: + leaves.insert(i + 1, Leaf(token.COMMA, ",")) + break # Populate the line for leaf in leaves: result.append(leaf, preformatted=True) diff --git a/tests/data/comments7.py b/tests/data/comments7.py new file mode 100644 index 0000000..4159d84 --- /dev/null +++ b/tests/data/comments7.py @@ -0,0 +1,51 @@ +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + +# output + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + Path, + # String, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) + + +from .config import ( + Any, + Bool, + ConfigType, + ConfigTypeAttributes, + Int, + no_comma_here_yet, + # and some comments, + # resolve_to_config_type, + # DEFAULT_TYPE_ATTRIBUTES, +) diff --git a/tests/test_black.py b/tests/test_black.py index 3e0b8a1..86175aa 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -388,6 +388,14 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, black.FileMode()) + @patch("black.dump_to_file", dump_to_stderr) + def test_comments7(self) -> None: + source, expected = read_data("comments7") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, black.FileMode()) + @patch("black.dump_to_file", dump_to_stderr) def test_cantfit(self) -> None: source, expected = read_data("cantfit") -- 2.39.5 From dd5777af0671e0657531236cbad3bb423fbd2b2d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 6 May 2019 11:09:04 -0400 Subject: [PATCH 16/16] add to CHANGELOG --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 7e3c01d..edf187f 100644 --- a/README.md +++ b/README.md @@ -953,6 +953,14 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). ### 19.3b1 +* don't produce invalid code for `from` ... `import` blocks with comments + (#829) + +* fix grammar selection (#765) + +* fix feature detection for trailing commas in function definitions and + call sites (#763) + * fix bug that led *Black* format some code with a line length target of 1 (#762) -- 2.39.5