From 2a357b360617e3853f5c960085e90a79399494ff Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Langa?= Date: Fri, 17 Aug 2018 10:38:28 -0700 Subject: [PATCH 01/16] Nits around numeral normalization. --- black.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/black.py b/black.py index 46f9c92..d688748 100644 --- a/black.py +++ b/black.py @@ -2511,28 +2511,27 @@ def normalize_string_quotes(leaf: Leaf) -> None: def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None: - """Normalizes numeric (float, int, and complex) literals.""" - # We want all letters (e in exponents, j in complex literals, a-f - # in hex literals) to be lowercase. + """Normalizes numeric (float, int, and complex) literals. + + All letters used in the representation are normalized to lowercase, long number + literals are split using underscores. + """ text = leaf.value.lower() if text.startswith(("0o", "0x", "0b")): - # Leave octal, hex, and binary literals alone for now. + # Leave octal, hex, and binary literals alone. pass elif "e" in text: before, after = text.split("e") + sign = "" if after.startswith("-"): after = after[1:] sign = "-" elif after.startswith("+"): after = after[1:] - sign = "" - else: - sign = "" before = format_float_or_int_string(before, allow_underscores) after = format_int_string(after, allow_underscores) text = f"{before}e{sign}{after}" - # Complex numbers and Python 2 longs - elif "j" in text or "l" in text: + elif text.endswith(("j", "l")): number = text[:-1] suffix = text[-1] text = f"{format_float_or_int_string(number, allow_underscores)}{suffix}" @@ -2555,7 +2554,7 @@ def format_float_or_int_string(text: str, allow_underscores: bool) -> str: def format_int_string(text: str, allow_underscores: bool) -> str: """Normalizes underscores in a string to e.g. 1_000_000. - Input must be a string consisting only of digits and underscores. + Input must be a string of at least six digits and optional underscores. """ if not allow_underscores: return text -- 2.39.2 From 0bf683a65929cb2153ed5e6d881ab6ed21e49e8c Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Langa?= Date: Fri, 17 Aug 2018 10:59:32 -0700 Subject: [PATCH 02/16] PyPI downloads badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4ed3df8..3fcba56 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ Coverage Status License: MIT PyPI +Downloads Code style: black

-- 2.39.2 From 0c77c58722acc7b594bfb3e12aa4b78a51109b27 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Langa?= Date: Sat, 18 Aug 2018 14:01:57 -0700 Subject: [PATCH 03/16] committers += jelle --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3fcba56..96a24a1 100644 --- a/README.md +++ b/README.md @@ -1209,6 +1209,7 @@ Glued together by [Łukasz Langa](mailto:lukasz@langa.pl). Maintained with [Carol Willing](mailto:carolcode@willingconsulting.com), [Carl Meyer](mailto:carl@oddbird.net), +[Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com), [Mika Naylor](mailto:mail@autophagy.io), and [Zsolt Dollenstein](mailto:zsol.zsol@gmail.com). @@ -1220,7 +1221,6 @@ Multiple contributions by: * [Eli Treuherz](mailto:eli.treuherz@cgi.com) * Hugo van Kemenade * [Ivan Katanić](mailto:ivan.katanic@gmail.com) -* [Jelle Zijlstra](mailto:jelle.zijlstra@gmail.com) * [Jonas Obrist](mailto:ojiidotch@gmail.com) * [Luka Sterbic](mailto:luka.sterbic@gmail.com) * [Miguel Gaiowski](mailto:miggaiowski@gmail.com) -- 2.39.2 From 66b82ced502a826649f9c7172a9a1d24e415d792 Mon Sep 17 00:00:00 2001 From: ceh Date: Sun, 19 Aug 2018 14:10:06 +0200 Subject: [PATCH 04/16] Fix minor typos (#443) --- black.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/black.py b/black.py index d688748..c899bde 100644 --- a/black.py +++ b/black.py @@ -170,7 +170,7 @@ def read_pyproject_toml( "--line-length", type=int, default=DEFAULT_LINE_LENGTH, - help="How many character per line to allow.", + help="How many characters per line to allow.", show_default=True, ) @click.option( @@ -1164,7 +1164,7 @@ class Line: self.remove_trailing_comma() return True - # Otheriwsse, if the trailing one is the only one, we might mistakenly + # Otherwise, if the trailing one is the only one, we might mistakenly # change a tuple into a different type by removing the comma. depth = closing.bracket_depth + 1 commas = 0 @@ -1377,7 +1377,7 @@ class EmptyLineTracker: newlines = 1 elif current_line.is_class or self.previous_line.is_class: if current_line.is_stub_class and self.previous_line.is_stub_class: - # No blank line between classes with an emty body + # No blank line between classes with an empty body newlines = 0 else: newlines = 1 @@ -3133,7 +3133,7 @@ class Report: - otherwise return 0. """ # According to http://tldp.org/LDP/abs/html/exitcodes.html starting with - # 126 we have special returncodes reserved by the shell. + # 126 we have special return codes reserved by the shell. if self.failure_count: return 123 -- 2.39.2 From b719d85ccc330170e40b2617307a7e3b2a0bab14 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 19 Aug 2018 21:02:06 -0700 Subject: [PATCH 05/16] autodetect Python 3.6 on the basis of underscores (#461) --- README.md | 8 ++++++++ black.py | 7 ++++++- tests/test_black.py | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 96a24a1..9cb4f18 100644 --- a/README.md +++ b/README.md @@ -371,6 +371,12 @@ human-readable strings"](https://stackoverflow.com/a/56190)), you can pass `--skip-string-normalization` on the command line. This is meant as an adoption helper, avoid using this for new projects. +### Numeric literals + +*Black* standardizes all numeric literals to use lowercase letters: `0xab` +instead of `0XAB` and `1e10` instead of `1E10`. In Python 3.6+, *Black* +adds underscores to long numeric literals to aid readability: `100000000` +becomes `100_000_000`. ### Line breaks & binary operators @@ -843,6 +849,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). ### 18.8b0 +* code with `_` in numeric literals is recognized as Python 3.6+ (#461) + * numeric literals are now normalized to include `_` separators on Python 3.6+ code (#452) diff --git a/black.py b/black.py index c899bde..b65693e 100644 --- a/black.py +++ b/black.py @@ -2891,7 +2891,8 @@ def is_python36(node: Node) -> bool: """Return True if the current file is using Python 3.6+ features. Currently looking for: - - f-strings; and + - f-strings; + - underscores in numeric literals; and - trailing commas after * or ** in function signatures and calls. """ for n in node.pre_order(): @@ -2900,6 +2901,10 @@ def is_python36(node: Node) -> bool: if value_head in {'f"', 'F"', "f'", "F'", "rf", "fr", "RF", "FR"}: return True + elif n.type == token.NUMBER: + if "_" in n.value: # type: ignore + return True + elif ( n.type in {syms.typedargslist, syms.arglist} and n.children diff --git a/tests/test_black.py b/tests/test_black.py index 884d046..10d7f28 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -722,6 +722,10 @@ class BlackTestCase(unittest.TestCase): self.assertTrue(black.is_python36(node)) node = black.lib2to3_parse("def f(*, arg): f'string'\n") self.assertTrue(black.is_python36(node)) + node = black.lib2to3_parse("123_456\n") + self.assertTrue(black.is_python36(node)) + node = black.lib2to3_parse("123456\n") + self.assertFalse(black.is_python36(node)) source, expected = read_data("function") node = black.lib2to3_parse(source) self.assertTrue(black.is_python36(node)) -- 2.39.2 From 883689366ce0f0e0ddd66d81360c61abfd19b01a Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Mon, 20 Aug 2018 14:47:58 +0100 Subject: [PATCH 06/16] Support parsing of async generators in non-async functions (#165) This is a new syntax added in python3.7, so black can't verify that reformatting will not change the ast unless black itself is run with 3.7. We'll need to change the error message black gives in this case. @ambv any ideas? Fixes #125. --- blib2to3/pgen2/tokenize.py | 7 ++++--- tests/data/python37.py | 13 +++++++++++++ tests/test_black.py | 10 ++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 tests/data/python37.py diff --git a/blib2to3/pgen2/tokenize.py b/blib2to3/pgen2/tokenize.py index 9a7664b..1f51ff0 100644 --- a/blib2to3/pgen2/tokenize.py +++ b/blib2to3/pgen2/tokenize.py @@ -516,13 +516,14 @@ def generate_tokens(readline): stashed = tok continue - if token == 'def': + if token in ('def', 'for'): if (stashed and stashed[0] == NAME and stashed[1] == 'async'): - async_def = True - async_def_indent = indents[-1] + if token == 'def': + async_def = True + async_def_indent = indents[-1] yield (ASYNC, stashed[1], stashed[2], stashed[3], diff --git a/tests/data/python37.py b/tests/data/python37.py new file mode 100644 index 0000000..ae20ade --- /dev/null +++ b/tests/data/python37.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3.7 + +def f(): + return (i*2 async for i in arange(42)) + +# output + + +#!/usr/bin/env python3.7 + + +def f(): + return (i * 2 async for i in arange(42)) diff --git a/tests/test_black.py b/tests/test_black.py index 10d7f28..9c798ca 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -411,6 +411,16 @@ class BlackTestCase(unittest.TestCase): self.assertFormatEqual(expected, actual) black.assert_stable(source, actual, line_length=ll, mode=mode) + @patch("black.dump_to_file", dump_to_stderr) + def test_python37(self) -> None: + source, expected = read_data("python37") + actual = fs(source) + self.assertFormatEqual(expected, actual) + major, minor = sys.version_info[:2] + if major > 3 or (major == 3 and minor >= 7): + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) def test_fmtonoff(self) -> None: source, expected = read_data("fmtonoff") -- 2.39.2 From d4f05217546dd98f81ca472aa00e68d978c900f4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 20 Aug 2018 08:19:25 -0700 Subject: [PATCH 07/16] fix misformatting of floats with leading zeros (#464) --- black.py | 4 +++- tests/data/numeric_literals.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/black.py b/black.py index b65693e..5550b23 100644 --- a/black.py +++ b/black.py @@ -2564,7 +2564,9 @@ def format_int_string(text: str, allow_underscores: bool) -> str: # No underscores for numbers <= 6 digits long. return text - return format(int(text), "3_") + # Avoid removing leading zeros, which are important if we're formatting + # part of a number like "0.001". + return format(int("1" + text), "3_")[1:].lstrip("_") def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: diff --git a/tests/data/numeric_literals.py b/tests/data/numeric_literals.py index 8999b9d..2dc64c7 100644 --- a/tests/data/numeric_literals.py +++ b/tests/data/numeric_literals.py @@ -14,6 +14,7 @@ x = 123456789.123456789J x = 0XB1ACC x = 0B1011 x = 0O777 +x = 0.000000006 # output @@ -34,3 +35,4 @@ x = 123_456_789.123_456_789j x = 0xb1acc x = 0b1011 x = 0o777 +x = 0.000_000_006 -- 2.39.2 From 8b340e210271a8108995fd479c55dbc0a34466bd Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Tue, 21 Aug 2018 21:10:59 -0700 Subject: [PATCH 08/16] wrap atoms in invisible parens to split adjacent strings (#463) --- README.md | 2 ++ black.py | 16 ++++++++++++---- tests/data/cantfit.py | 6 ++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9cb4f18..e9937f1 100644 --- a/README.md +++ b/README.md @@ -849,6 +849,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). ### 18.8b0 +* adjacent string literals are now correctly split into multiple lines (#463) + * code with `_` in numeric literals is recognized as Python 3.6+ (#461) * numeric literals are now normalized to include `_` separators on Python 3.6+ code diff --git a/black.py b/black.py index 5550b23..85cb45b 100644 --- a/black.py +++ b/black.py @@ -2587,7 +2587,11 @@ def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: for index, child in enumerate(list(node.children)): if check_lpar: if child.type == syms.atom: - maybe_make_parens_invisible_in_atom(child) + if maybe_make_parens_invisible_in_atom(child): + lpar = Leaf(token.LPAR, "") + rpar = Leaf(token.RPAR, "") + index = child.remove() or 0 + node.insert_child(index, Node(syms.atom, [lpar, child, rpar])) elif is_one_tuple(child): # wrap child in visible parentheses lpar = Leaf(token.LPAR, "(") @@ -2695,7 +2699,11 @@ def generate_ignored_nodes(leaf: Leaf) -> Iterator[LN]: def maybe_make_parens_invisible_in_atom(node: LN) -> bool: - """If it's safe, make the parens in the atom `node` invisible, recursively.""" + """If it's safe, make the parens in the atom `node` invisible, recursively. + + Returns whether the node should itself be wrapped in invisible parentheses. + + """ if ( node.type != syms.atom or is_empty_tuple(node) @@ -2713,9 +2721,9 @@ def maybe_make_parens_invisible_in_atom(node: LN) -> bool: last.value = "" # type: ignore if len(node.children) > 1: maybe_make_parens_invisible_in_atom(node.children[1]) - return True + return False - return False + return True def is_empty_tuple(node: LN) -> bool: diff --git a/tests/data/cantfit.py b/tests/data/cantfit.py index e15e69c..2a7cde3 100644 --- a/tests/data/cantfit.py +++ b/tests/data/cantfit.py @@ -35,6 +35,7 @@ for key in """ """.split(): if key in self.connect_kwargs: raise ValueError(err.format(key)) +concatenated_strings = "some strings that are" "concatenated implicitly, so if you put them on separate" "lines it will fit" # output @@ -85,3 +86,8 @@ for key in """ """.split(): if key in self.connect_kwargs: raise ValueError(err.format(key)) +concatenated_strings = ( + "some strings that are" + "concatenated implicitly, so if you put them on separate" + "lines it will fit" +) -- 2.39.2 From b53cb9474348e13533ccba3735191a55ef3da6c4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 23 Aug 2018 04:52:07 -0700 Subject: [PATCH 09/16] fix bracket match bug (#470) * fix bracket match bug * add missing test file --- black.py | 25 +++++++++++++++++-------- tests/data/bracketmatch.py | 15 +++++++++++++++ tests/test_black.py | 8 ++++++++ 3 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 tests/data/bracketmatch.py diff --git a/black.py b/black.py index 85cb45b..0f166c6 100644 --- a/black.py +++ b/black.py @@ -877,8 +877,8 @@ class BracketTracker: bracket_match: Dict[Tuple[Depth, NodeType], Leaf] = Factory(dict) delimiters: Dict[LeafID, Priority] = Factory(dict) previous: Optional[Leaf] = None - _for_loop_variable: int = 0 - _lambda_arguments: int = 0 + _for_loop_depths: List[int] = Factory(list) + _lambda_argument_depths: List[int] = Factory(list) def mark(self, leaf: Leaf) -> None: """Mark `leaf` with bracket-related metadata. Keep track of delimiters. @@ -951,16 +951,21 @@ class BracketTracker: """ if leaf.type == token.NAME and leaf.value == "for": self.depth += 1 - self._for_loop_variable += 1 + self._for_loop_depths.append(self.depth) return True return False def maybe_decrement_after_for_loop_variable(self, leaf: Leaf) -> bool: """See `maybe_increment_for_loop_variable` above for explanation.""" - if self._for_loop_variable and leaf.type == token.NAME and leaf.value == "in": + if ( + self._for_loop_depths + and self._for_loop_depths[-1] == self.depth + and leaf.type == token.NAME + and leaf.value == "in" + ): self.depth -= 1 - self._for_loop_variable -= 1 + self._for_loop_depths.pop() return True return False @@ -973,16 +978,20 @@ class BracketTracker: """ if leaf.type == token.NAME and leaf.value == "lambda": self.depth += 1 - self._lambda_arguments += 1 + self._lambda_argument_depths.append(self.depth) return True return False def maybe_decrement_after_lambda_arguments(self, leaf: Leaf) -> bool: """See `maybe_increment_lambda_arguments` above for explanation.""" - if self._lambda_arguments and leaf.type == token.COLON: + if ( + self._lambda_argument_depths + and self._lambda_argument_depths[-1] == self.depth + and leaf.type == token.COLON + ): self.depth -= 1 - self._lambda_arguments -= 1 + self._lambda_argument_depths.pop() return True return False diff --git a/tests/data/bracketmatch.py b/tests/data/bracketmatch.py new file mode 100644 index 0000000..0aaa2d8 --- /dev/null +++ b/tests/data/bracketmatch.py @@ -0,0 +1,15 @@ +for ((x in {}) or {})['a'] in x: + pass +pem_spam = lambda l, spam = { + "x": 3 +}: not spam.get(l.strip()) +lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x + + +# output + + +for ((x in {}) or {})["a"] in x: + pass +pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip()) +lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x diff --git a/tests/test_black.py b/tests/test_black.py index 9c798ca..311f635 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -453,6 +453,14 @@ class BlackTestCase(unittest.TestCase): black.assert_equivalent(source, actual) black.assert_stable(source, actual, line_length=ll) + @patch("black.dump_to_file", dump_to_stderr) + def test_bracket_match(self) -> None: + source, expected = read_data("bracketmatch") + actual = fs(source) + self.assertFormatEqual(expected, actual) + black.assert_equivalent(source, actual) + black.assert_stable(source, actual, line_length=ll) + def test_report_verbose(self) -> None: report = black.Report(verbose=True) out_lines = [] -- 2.39.2 From c67feaf04f473d863fbc3845e527d65847f911a9 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Thu, 23 Aug 2018 12:55:04 +0100 Subject: [PATCH 10/16] add changelog entry for #468 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e9937f1..d8ef7ec 100644 --- a/README.md +++ b/README.md @@ -866,6 +866,8 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). * note: the Vim plugin stopped registering ``,=`` as a default chord as it turned out to be a bad idea (#415) +* fixed formatting of lambda expressions with default arguments (#468) + ### 18.6b4 -- 2.39.2 From a37abdcbc5d8828428cea8b9daca65d9ee0994b5 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 23 Aug 2018 11:55:29 -0700 Subject: [PATCH 11/16] change some numeric behavior (#469) --- README.md | 18 +++++++++++------- black.py | 30 ++++++++++++++++++++++-------- tests/data/numeric_literals.py | 2 ++ tests/data/numeric_literals_py2.py | 4 +++- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d8ef7ec..0231599 100644 --- a/README.md +++ b/README.md @@ -373,10 +373,11 @@ an adoption helper, avoid using this for new projects. ### Numeric literals -*Black* standardizes all numeric literals to use lowercase letters: `0xab` -instead of `0XAB` and `1e10` instead of `1E10`. In Python 3.6+, *Black* -adds underscores to long numeric literals to aid readability: `100000000` -becomes `100_000_000`. +*Black* standardizes most numeric literals to use lowercase letters: `0xab` +instead of `0XAB` and `1e10` instead of `1E10`. Python 2 long literals are +styled as `2L` instead of `2l` to avoid confusion between `l` and `1`. In +Python 3.6+, *Black* adds underscores to long numeric literals to aid +readability: `100000000` becomes `100_000_000`. ### Line breaks & binary operators @@ -851,10 +852,13 @@ More details can be found in [CONTRIBUTING](CONTRIBUTING.md). * adjacent string literals are now correctly split into multiple lines (#463) -* code with `_` in numeric literals is recognized as Python 3.6+ (#461) +* numeric literals are now formatted by *Black* (#452, #461, #464, #469): -* numeric literals are now normalized to include `_` separators on Python 3.6+ code - (#452) + * numeric literals are normalized to include `_` separators on Python 3.6+ code + + * code with `_` in numeric literals is recognized as Python 3.6+ + + * most letters in numeric literals are lowercased (e.g., in `1e10` or `0xab`) * cache is now populated when `--check` is successful for a file which speeds up consecutive checks of properly formatted unmodified files (#448) diff --git a/black.py b/black.py index 0f166c6..3a51f21 100644 --- a/black.py +++ b/black.py @@ -2522,8 +2522,8 @@ def normalize_string_quotes(leaf: Leaf) -> None: def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None: """Normalizes numeric (float, int, and complex) literals. - All letters used in the representation are normalized to lowercase, long number - literals are split using underscores. + All letters used in the representation are normalized to lowercase (except + in Python 2 long literals), and long number literals are split using underscores. """ text = leaf.value.lower() if text.startswith(("0o", "0x", "0b")): @@ -2543,6 +2543,9 @@ def normalize_numeric_literal(leaf: Leaf, allow_underscores: bool) -> None: elif text.endswith(("j", "l")): number = text[:-1] suffix = text[-1] + # Capitalize in "2L" because "l" looks too similar to "1". + if suffix == "l": + suffix = "L" text = f"{format_float_or_int_string(number, allow_underscores)}{suffix}" else: text = format_float_or_int_string(text, allow_underscores) @@ -2556,14 +2559,22 @@ def format_float_or_int_string(text: str, allow_underscores: bool) -> str: before, after = text.split(".") before = format_int_string(before, allow_underscores) if before else "0" - after = format_int_string(after, allow_underscores) if after else "0" + if after: + after = format_int_string(after, allow_underscores, count_from_end=False) + else: + after = "0" return f"{before}.{after}" -def format_int_string(text: str, allow_underscores: bool) -> str: +def format_int_string( + text: str, allow_underscores: bool, count_from_end: bool = True +) -> str: """Normalizes underscores in a string to e.g. 1_000_000. - Input must be a string of at least six digits and optional underscores. + Input must be a string of digits and optional underscores. + If count_from_end is False, we add underscores after groups of three digits + counting from the beginning instead of the end of the strings. This is used + for the fractional part of float literals. """ if not allow_underscores: return text @@ -2573,9 +2584,12 @@ def format_int_string(text: str, allow_underscores: bool) -> str: # No underscores for numbers <= 6 digits long. return text - # Avoid removing leading zeros, which are important if we're formatting - # part of a number like "0.001". - return format(int("1" + text), "3_")[1:].lstrip("_") + if count_from_end: + # Avoid removing leading zeros, which are important if we're formatting + # part of a number like "0.001". + return format(int("1" + text), "3_")[1:].lstrip("_") + else: + return "_".join(text[i : i + 3] for i in range(0, len(text), 3)) def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: diff --git a/tests/data/numeric_literals.py b/tests/data/numeric_literals.py index 2dc64c7..b812ebf 100644 --- a/tests/data/numeric_literals.py +++ b/tests/data/numeric_literals.py @@ -6,6 +6,7 @@ x = .1 x = 1. x = 1E+1 x = 1E-1 +x = 1.00000001 x = 123456789.123456789 x = 123456789.123456789E123456789 x = 123456789E123456789 @@ -27,6 +28,7 @@ x = 0.1 x = 1.0 x = 1e1 x = 1e-1 +x = 1.000_000_01 x = 123_456_789.123_456_789 x = 123_456_789.123_456_789e123_456_789 x = 123_456_789e123_456_789 diff --git a/tests/data/numeric_literals_py2.py b/tests/data/numeric_literals_py2.py index 107c39b..d2db7b0 100644 --- a/tests/data/numeric_literals_py2.py +++ b/tests/data/numeric_literals_py2.py @@ -1,6 +1,7 @@ #!/usr/bin/env python2.7 x = 123456789L +x = 123456789l x = 123456789 # output @@ -8,5 +9,6 @@ x = 123456789 #!/usr/bin/env python2.7 -x = 123456789l +x = 123456789L +x = 123456789L x = 123456789 -- 2.39.2 From 401836d02eb7516829fe1f84ca10791d04606f01 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Sun, 26 Aug 2018 21:19:22 +0100 Subject: [PATCH 12/16] add test case for preserving newlines from stdin --- tests/test_black.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/tests/test_black.py b/tests/test_black.py index 311f635..421e871 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -84,8 +84,11 @@ class BlackRunner(CliRunner): This is a hack that can be removed once we depend on Click 7.x""" - def __init__(self, stderrbuf: BinaryIO) -> None: - self.stderrbuf = stderrbuf + def __init__(self) -> None: + self.stderrbuf = BytesIO() + self.stdoutbuf = BytesIO() + self.stdout_bytes = b"" + self.stderr_bytes = b"" super().__init__() @contextmanager @@ -96,6 +99,8 @@ class BlackRunner(CliRunner): sys.stderr = TextIOWrapper(self.stderrbuf, encoding=self.charset) yield output finally: + self.stdout_bytes = sys.stdout.buffer.getvalue() + self.stderr_bytes = sys.stderr.buffer.getvalue() sys.stderr = hold_stderr @@ -160,8 +165,7 @@ class BlackTestCase(unittest.TestCase): def test_piping(self) -> None: source, expected = read_data("../black", data=False) - stderrbuf = BytesIO() - result = BlackRunner(stderrbuf).invoke( + result = BlackRunner().invoke( black.main, ["-", "--fast", f"--line-length={ll}"], input=BytesIO(source.encode("utf8")), @@ -179,9 +183,8 @@ class BlackTestCase(unittest.TestCase): source, _ = read_data("expression.py") expected, _ = read_data("expression.diff") config = THIS_DIR / "data" / "empty_pyproject.toml" - stderrbuf = BytesIO() args = ["-", "--fast", f"--line-length={ll}", "--diff", f"--config={config}"] - result = BlackRunner(stderrbuf).invoke( + result = BlackRunner().invoke( black.main, args, input=BytesIO(source.encode("utf8")) ) self.assertEqual(result.exit_code, 0) @@ -244,11 +247,8 @@ class BlackTestCase(unittest.TestCase): rf"{re.escape(str(tmp_file))}\t\d\d\d\d-\d\d-\d\d " rf"\d\d:\d\d:\d\d\.\d\d\d\d\d\d \+\d\d\d\d" ) - stderrbuf = BytesIO() try: - result = BlackRunner(stderrbuf).invoke( - black.main, ["--diff", str(tmp_file)] - ) + result = BlackRunner().invoke(black.main, ["--diff", str(tmp_file)]) self.assertEqual(result.exit_code, 0) finally: os.unlink(tmp_file) @@ -1219,6 +1219,18 @@ class BlackTestCase(unittest.TestCase): if nl == "\n": self.assertNotIn(b"\r\n", updated_contents) + def test_preserves_line_endings_via_stdin(self) -> None: + for nl in ["\n", "\r\n"]: + contents = nl.join(["def f( ):", " pass"]) + runner = BlackRunner() + result = runner.invoke( + black.main, ["-", "--fast"], input=BytesIO(contents.encode("utf8")) + ) + output = runner.stdout_bytes + self.assertIn(nl.encode("utf8"), output) + if nl == "\n": + self.assertNotIn(b"\r\n", output) + def test_assert_equivalent_different_asts(self) -> None: with self.assertRaises(AssertionError): black.assert_equivalent("{}", "None") -- 2.39.2 From 66a6be642c73a6a7fcf6229ec1fa0f1c7c7611b1 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Sun, 26 Aug 2018 21:27:33 +0100 Subject: [PATCH 13/16] fix lint errors --- tests/test_black.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_black.py b/tests/test_black.py index 421e871..85ab2b6 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -99,8 +99,8 @@ class BlackRunner(CliRunner): sys.stderr = TextIOWrapper(self.stderrbuf, encoding=self.charset) yield output finally: - self.stdout_bytes = sys.stdout.buffer.getvalue() - self.stderr_bytes = sys.stderr.buffer.getvalue() + self.stdout_bytes = sys.stdout.buffer.getvalue() # type: ignore + self.stderr_bytes = sys.stderr.buffer.getvalue() # type: ignore sys.stderr = hold_stderr @@ -1226,6 +1226,7 @@ class BlackTestCase(unittest.TestCase): result = runner.invoke( black.main, ["-", "--fast"], input=BytesIO(contents.encode("utf8")) ) + self.assertEqual(result.exit_code, 0) output = runner.stdout_bytes self.assertIn(nl.encode("utf8"), output) if nl == "\n": -- 2.39.2 From 7613a4919706387a2c6396a92963bac4ad23274a Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Mon, 27 Aug 2018 10:10:45 +0100 Subject: [PATCH 14/16] ISSUE_TEMPLATE.md: Add mention of online formatter (#481) People can try out https://black.now.sh/?version=master to test against master. That should make issue reporting easier. See https://github.com/jpadilla/black-playground/issues/6#issuecomment-416088863. Thanks @jpadilla! --- .github/ISSUE_TEMPLATE.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index b23af35..2dfd64b 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,9 +6,11 @@ Python version: *Black* version: Does also happen on master: -To answer the last question, follow these steps: -* create a new virtualenv (make sure it's the same Python version); -* clone this repository; -* run `pip install -e .`; -* make sure it's sane by running `python setup.py test`; and -* run `black` like you did last time. +To answer the last question, you have two options: +1. Use the online formatter at https://black.now.sh/?version=master, which will use the latest master branch. +2. Or run black on your machine: + * create a new virtualenv (make sure it's the same Python version); + * clone this repository; + * run `pip install -e .`; + * make sure it's sane by running `python setup.py test`; and + * run `black` like you did last time. -- 2.39.2 From 7f3fb65346aa8e818cc6e6e64c21117660b2460e Mon Sep 17 00:00:00 2001 From: Eli Treuherz <1574403+treuherz@users.noreply.github.com> Date: Tue, 28 Aug 2018 09:56:55 +0100 Subject: [PATCH 15/16] Change my email in the README (#483) Would prefer my personal email here. I realise it's still in the git log but c'est la vie. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0231599..c58f328 100644 --- a/README.md +++ b/README.md @@ -1234,7 +1234,7 @@ Multiple contributions by: * [Artem Malyshev](mailto:proofit404@gmail.com) * [Christian Heimes](mailto:christian@python.org) * [Daniel M. Capella](mailto:polycitizen@gmail.com) -* [Eli Treuherz](mailto:eli.treuherz@cgi.com) +* [Eli Treuherz](mailto:eli@treuherz.com) * Hugo van Kemenade * [Ivan Katanić](mailto:ivan.katanic@gmail.com) * [Jonas Obrist](mailto:ojiidotch@gmail.com) -- 2.39.2 From e069017178e7ea02b3bbacab63e951015621f5c4 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Tue, 28 Aug 2018 04:52:32 -0700 Subject: [PATCH 16/16] Update pypi.python.org URL to pypi.org (#488) For details on the new PyPI, see the blog post: https://pythoninsider.blogspot.ca/2018/04/new-pypi-launched-legacy-pypi-shutting.html --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c58f328..3899dc6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Documentation Status Coverage Status License: MIT -PyPI +PyPI Downloads Code style: black

-- 2.39.2