From b58ef001ac2337a0fa40411a80ee5611d97ef0f3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 14 Jun 2022 09:46:12 +0100 Subject: [PATCH 1/9] Remove extra space from the unparser --- sphinx/pycode/ast.py | 2 ++ tests/test_pycode_ast.py | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 755116475d6..2a896a7c32c 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -202,6 +202,8 @@ def is_simple_tuple(value: ast.AST) -> bool: return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) def visit_UnaryOp(self, node: ast.UnaryOp) -> str: + if not isinstance(node.op, ast.Not): + return "%s%s" % (self.visit(node.op), self.visit(node.operand)) return "%s %s" % (self.visit(node.op), self.visit(node.operand)) def visit_Tuple(self, node: ast.Tuple) -> str: diff --git a/tests/test_pycode_ast.py b/tests/test_pycode_ast.py index 6143105eb71..2d33a562991 100644 --- a/tests/test_pycode_ast.py +++ b/tests/test_pycode_ast.py @@ -25,7 +25,7 @@ ("...", "..."), # Ellipsis ("a // b", "a // b"), # FloorDiv ("Tuple[int, int]", "Tuple[int, int]"), # Index, Subscript - ("~ 1", "~ 1"), # Invert + ("~1", "~1"), # Invert ("lambda x, y: x + y", "lambda x, y: ..."), # Lambda ("[1, 2, 3]", "[1, 2, 3]"), # List @@ -42,9 +42,9 @@ ("{1, 2, 3}", "{1, 2, 3}"), # Set ("a - b", "a - b"), # Sub ("'str'", "'str'"), # Str - ("+ a", "+ a"), # UAdd - ("- 1", "- 1"), # UnaryOp - ("- a", "- a"), # USub + ("+a", "+a"), # UAdd + ("-1", "-1"), # UnaryOp + ("-a", "-a"), # USub ("(1, 2, 3)", "(1, 2, 3)"), # Tuple ("()", "()"), # Tuple (empty) ("(1,)", "(1,)"), # Tuple (single item) From dbe2db5df79ec4539041785c5744f70ed4a3c95e Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 14 Jun 2022 16:39:12 +0100 Subject: [PATCH 2/9] Add a comment --- sphinx/pycode/ast.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 2a896a7c32c..ac094494c48 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -202,6 +202,7 @@ def is_simple_tuple(value: ast.AST) -> bool: return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) def visit_UnaryOp(self, node: ast.UnaryOp) -> str: + # UnaryOp is one of {UAdd, USub, Invert, Not}. Only Not needs a space. if not isinstance(node.op, ast.Not): return "%s%s" % (self.visit(node.op), self.visit(node.operand)) return "%s %s" % (self.visit(node.op), self.visit(node.operand)) From 0768f22aa1a007522c8d6a65b3b3b174ddeab3c1 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 14 Jun 2022 16:40:42 +0100 Subject: [PATCH 3/9] Add CHANGES entry --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index e823bdf0c12..858c7493a77 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,9 @@ Features added Bugs fixed ---------- +* #10031: pycode: Fix spurious whitespace in unparsing unary operators (``+``, + ``-``, ``~``). Patch by Adam Turner. + Testing -------- From eae646504fdbecb6d06b0d5f401fedc84975b720 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 14 Jun 2022 18:29:18 +0100 Subject: [PATCH 4/9] Switch check --- sphinx/pycode/ast.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index ac094494c48..7d0389ceec0 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -203,9 +203,9 @@ def is_simple_tuple(value: ast.AST) -> bool: def visit_UnaryOp(self, node: ast.UnaryOp) -> str: # UnaryOp is one of {UAdd, USub, Invert, Not}. Only Not needs a space. - if not isinstance(node.op, ast.Not): - return "%s%s" % (self.visit(node.op), self.visit(node.operand)) - return "%s %s" % (self.visit(node.op), self.visit(node.operand)) + if isinstance(node.op, ast.Not): + return "%s %s" % (self.visit(node.op), self.visit(node.operand)) + return "%s%s" % (self.visit(node.op), self.visit(node.operand)) def visit_Tuple(self, node: ast.Tuple) -> str: if len(node.elts) == 0: From 3dc6ed166f903bb0b32c69fd3c7bfea4a5efac2f Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 15 Jun 2022 09:29:35 +0100 Subject: [PATCH 5/9] Add higher level test --- tests/test_domain_py.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 014067e8459..4b1b3f633c5 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -452,6 +452,24 @@ def test_pyfunction_signature_full(app): [desc_sig_name, pending_xref, "str"])])]) +def test_pyfunction_with_unary_operators(app): + text = ".. py:function:: menu(egg=+1, bacon=-1, sausage=~1, spam=not spam)" + doctree = restructuredtext.parse(app, text) + assert_node(doctree[1][0][1], + [desc_parameterlist, ([desc_parameter, ([desc_sig_name, "egg"], + [desc_sig_operator, "="], + [nodes.inline, "+1"])], + [desc_parameter, ([desc_sig_name, "bacon"], + [desc_sig_operator, "="], + [nodes.inline, "-1"])], + [desc_parameter, ([desc_sig_name, "sausage"], + [desc_sig_operator, "="], + [nodes.inline, "~1"])], + [desc_parameter, ([desc_sig_name, "spam"], + [desc_sig_operator, "="], + [nodes.inline, "not spam"])])]) + + @pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.') def test_pyfunction_signature_full_py38(app): # case: separator at head From 05b835114baf1886ae140fb430f3622c58d2ab46 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 15 Jun 2022 09:31:25 +0100 Subject: [PATCH 6/9] Expand comment --- sphinx/pycode/ast.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 7d0389ceec0..b2a00db809a 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -202,7 +202,8 @@ def is_simple_tuple(value: ast.AST) -> bool: return "%s[%s]" % (self.visit(node.value), self.visit(node.slice)) def visit_UnaryOp(self, node: ast.UnaryOp) -> str: - # UnaryOp is one of {UAdd, USub, Invert, Not}. Only Not needs a space. + # UnaryOp is one of {UAdd, USub, Invert, Not}, which refer to ``+x``, + # ``-x``, ``~x``, and ``not x``. Only Not needs a space. if isinstance(node.op, ast.Not): return "%s %s" % (self.visit(node.op), self.visit(node.operand)) return "%s%s" % (self.visit(node.op), self.visit(node.operand)) From b8a38f037be69229fdb8caf811f0cb04759e43e3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 15 Jun 2022 10:15:53 +0100 Subject: [PATCH 7/9] Special case `**` --- CHANGES | 4 ++-- sphinx/pycode/ast.py | 3 +++ tests/test_domain_py.py | 9 +++++++++ tests/test_pycode_ast.py | 2 +- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 858c7493a77..4bc0cf3133b 100644 --- a/CHANGES +++ b/CHANGES @@ -16,8 +16,8 @@ Features added Bugs fixed ---------- -* #10031: pycode: Fix spurious whitespace in unparsing unary operators (``+``, - ``-``, ``~``). Patch by Adam Turner. +* #10031: pycode: Fix spurious whitespace in unparsing various operators (``+``, + ``-``, ``~``, and ``**``). Patch by Adam Turner. Testing -------- diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index b2a00db809a..51af563c4ab 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -141,6 +141,9 @@ def visit_Attribute(self, node: ast.Attribute) -> str: return "%s.%s" % (self.visit(node.value), node.attr) def visit_BinOp(self, node: ast.BinOp) -> str: + # Special case ``**`` to now have surrounding spaces. + if isinstance(node.op, ast.Pow): + return "".join(map(self.visit, (node.left, node.op, node.right))) return " ".join(self.visit(e) for e in [node.left, node.op, node.right]) def visit_BoolOp(self, node: ast.BoolOp) -> str: diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 4b1b3f633c5..baad0c2daa2 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -470,6 +470,15 @@ def test_pyfunction_with_unary_operators(app): [nodes.inline, "not spam"])])]) +def test_pyfunction_with_binary_operators(app): + text = ".. py:function:: menu(spam=2**64)" + doctree = restructuredtext.parse(app, text) + assert_node(doctree[1][0][1], + [desc_parameterlist, ([desc_parameter, ([desc_sig_name, "spam"], + [desc_sig_operator, "="], + [nodes.inline, "2**64"])])]) + + @pytest.mark.skipif(sys.version_info < (3, 8), reason='python 3.8+ is required.') def test_pyfunction_signature_full_py38(app): # case: separator at head diff --git a/tests/test_pycode_ast.py b/tests/test_pycode_ast.py index 2d33a562991..31018bacaa3 100644 --- a/tests/test_pycode_ast.py +++ b/tests/test_pycode_ast.py @@ -37,7 +37,7 @@ ("1234", "1234"), # Num ("not a", "not a"), # Not ("a or b", "a or b"), # Or - ("a ** b", "a ** b"), # Pow + ("a**b", "a**b"), # Pow ("a >> b", "a >> b"), # RShift ("{1, 2, 3}", "{1, 2, 3}"), # Set ("a - b", "a - b"), # Sub From 2b9461a753c2965f2d852c45c3e475710b296404 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:15:01 +0100 Subject: [PATCH 8/9] Typo --- sphinx/pycode/ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 51af563c4ab..d4646f0b729 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -141,7 +141,7 @@ def visit_Attribute(self, node: ast.Attribute) -> str: return "%s.%s" % (self.visit(node.value), node.attr) def visit_BinOp(self, node: ast.BinOp) -> str: - # Special case ``**`` to now have surrounding spaces. + # Special case ``**`` to not have surrounding spaces. if isinstance(node.op, ast.Pow): return "".join(map(self.visit, (node.left, node.op, node.right))) return " ".join(self.visit(e) for e in [node.left, node.op, node.right]) From bed8e94cfc6fdd619d7141f1c918060fca1ae732 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Thu, 16 Jun 2022 18:52:48 +0100 Subject: [PATCH 9/9] Update CHANGES Co-authored-by: Takeshi KOMIYA --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4bc0cf3133b..e88dc6a23c0 100644 --- a/CHANGES +++ b/CHANGES @@ -16,7 +16,7 @@ Features added Bugs fixed ---------- -* #10031: pycode: Fix spurious whitespace in unparsing various operators (``+``, +* #10031: py domain: Fix spurious whitespace in unparsing various operators (``+``, ``-``, ``~``, and ``**``). Patch by Adam Turner. Testing