From 777cae55b601f8a501e2138cec99361929b128ea Mon Sep 17 00:00:00 2001 From: Shivansh-007 Date: Fri, 28 Jan 2022 11:01:50 +0530 Subject: [PATCH] Use parentheses on method access on float and int literals (#2799) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Co-authored-by: Jelle Zijlstra Co-authored-by: Felix Hildén --- CHANGES.md | 3 ++ src/black/linegen.py | 22 +++++++++ src/black/nodes.py | 7 +-- .../attribute_access_on_number_literals.py | 47 +++++++++++++++++++ tests/data/expression.diff | 9 ++-- tests/data/expression.py | 4 +- .../expression_skip_magic_trailing_comma.diff | 9 ++-- tests/test_format.py | 1 + 8 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 tests/data/attribute_access_on_number_literals.py diff --git a/CHANGES.md b/CHANGES.md index 0dc4952..6966a91 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -42,6 +42,9 @@ - Make passing `SRC` or `--code` mandatory and mutually exclusive (#2804) - Work around bug that causes unstable formatting in some cases in the presence of the magic trailing comma (#2807) +- Use parentheses for attribute access on decimal float and int literals (#2799) +- Don't add whitespace for attribute access on hexadecimal, binary, octal, and complex + literals (#2799) - Deprecate the `black-primer` tool (#2809) ### Packaging diff --git a/src/black/linegen.py b/src/black/linegen.py index ac60ed1..b572ed0 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -197,6 +197,28 @@ class LineGenerator(Visitor[Line]): yield from self.line() yield from self.visit(child) + def visit_power(self, node: Node) -> Iterator[Line]: + for idx, leaf in enumerate(node.children[:-1]): + next_leaf = node.children[idx + 1] + + if not isinstance(leaf, Leaf): + continue + + value = leaf.value.lower() + if ( + leaf.type == token.NUMBER + and next_leaf.type == syms.trailer + # Ensure that we are in an attribute trailer + and next_leaf.children[0].type == token.DOT + # It shouldn't wrap hexadecimal, binary and octal literals + and not value.startswith(("0x", "0b", "0o")) + # It shouldn't wrap complex literals + and "j" not in value + ): + wrap_in_parentheses(node, leaf) + + yield from self.visit_default(node) + def visit_SEMI(self, leaf: Leaf) -> Iterator[Line]: """Remove a semicolon and put the other statement on a separate line.""" yield from self.line() diff --git a/src/black/nodes.py b/src/black/nodes.py index 74dfa89..51d4cb8 100644 --- a/src/black/nodes.py +++ b/src/black/nodes.py @@ -306,12 +306,7 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa: C901 return NO if not prev: - if t == token.DOT: - prevp = preceding_leaf(p) - if not prevp or prevp.type != token.NUMBER: - return NO - - elif t == token.LSQB: + if t == token.DOT or t == token.LSQB: return NO elif prev.type != token.COMMA: diff --git a/tests/data/attribute_access_on_number_literals.py b/tests/data/attribute_access_on_number_literals.py new file mode 100644 index 0000000..7c16bdf --- /dev/null +++ b/tests/data/attribute_access_on_number_literals.py @@ -0,0 +1,47 @@ +x = 123456789 .bit_count() +x = (123456).__abs__() +x = .1.is_integer() +x = 1. .imag +x = 1E+1.imag +x = 1E-1.real +x = 123456789.123456789.hex() +x = 123456789.123456789E123456789 .real +x = 123456789E123456789 .conjugate() +x = 123456789J.real +x = 123456789.123456789J.__add__(0b1011.bit_length()) +x = 0XB1ACC.conjugate() +x = 0B1011 .conjugate() +x = 0O777 .real +x = 0.000000006 .hex() +x = -100.0000J + +if 10 .real: + ... + +y = 100[no] +y = 100(no) + +# output + +x = (123456789).bit_count() +x = (123456).__abs__() +x = (0.1).is_integer() +x = (1.0).imag +x = (1e1).imag +x = (1e-1).real +x = (123456789.123456789).hex() +x = (123456789.123456789e123456789).real +x = (123456789e123456789).conjugate() +x = 123456789j.real +x = 123456789.123456789j.__add__(0b1011.bit_length()) +x = 0xB1ACC.conjugate() +x = 0b1011.conjugate() +x = 0o777.real +x = (0.000000006).hex() +x = -100.0000j + +if (10).real: + ... + +y = 100[no] +y = 100(no) diff --git a/tests/data/expression.diff b/tests/data/expression.diff index 5f29a18..2eaaeb4 100644 --- a/tests/data/expression.diff +++ b/tests/data/expression.diff @@ -11,7 +11,7 @@ True False 1 -@@ -21,71 +21,104 @@ +@@ -21,99 +21,135 @@ Name1 or (Name2 and Name3) or Name4 Name1 or Name2 and Name3 or Name4 v1 << 2 @@ -144,8 +144,11 @@ call(**self.screen_kwargs) call(b, **self.screen_kwargs) lukasz.langa.pl -@@ -94,26 +127,29 @@ - 1.0 .real + call.me(maybe) +-1 .real +-1.0 .real ++(1).real ++(1.0).real ....__class__ list[str] dict[str, int] diff --git a/tests/data/expression.py b/tests/data/expression.py index b056841..06096c5 100644 --- a/tests/data/expression.py +++ b/tests/data/expression.py @@ -382,8 +382,8 @@ call(**self.screen_kwargs) call(b, **self.screen_kwargs) lukasz.langa.pl call.me(maybe) -1 .real -1.0 .real +(1).real +(1.0).real ....__class__ list[str] dict[str, int] diff --git a/tests/data/expression_skip_magic_trailing_comma.diff b/tests/data/expression_skip_magic_trailing_comma.diff index 5b722c9..eba3fd2 100644 --- a/tests/data/expression_skip_magic_trailing_comma.diff +++ b/tests/data/expression_skip_magic_trailing_comma.diff @@ -11,7 +11,7 @@ True False 1 -@@ -21,71 +21,92 @@ +@@ -21,99 +21,118 @@ Name1 or (Name2 and Name3) or Name4 Name1 or Name2 and Name3 or Name4 v1 << 2 @@ -132,8 +132,11 @@ call(**self.screen_kwargs) call(b, **self.screen_kwargs) lukasz.langa.pl -@@ -94,26 +115,24 @@ - 1.0 .real + call.me(maybe) +-1 .real +-1.0 .real ++(1).real ++(1.0).real ....__class__ list[str] dict[str, int] diff --git a/tests/test_format.py b/tests/test_format.py index 88f084e..aef2254 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -15,6 +15,7 @@ from tests.util import ( ) SIMPLE_CASES: List[str] = [ + "attribute_access_on_number_literals", "beginning_backslash", "bracketmatch", "class_blank_parentheses", -- 2.39.2