From a37abdcbc5d8828428cea8b9daca65d9ee0994b5 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 23 Aug 2018 11:55:29 -0700 Subject: [PATCH] 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.5