Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyCode "Unparse": Added support for slice objects in subscriptions #11981

Merged
merged 12 commits into from
Feb 14, 2024
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Features added
* #11892: Improved performance when resolving cross references in cpp domain.
Patch by Rouslan Korneychuk.

* #11981: Improve rendering of signatures using ``slice`` syntax,
e.g., ``def foo(arg: np.float64[:,:]) -> None: ...``.

Bugs fixed
----------

Expand Down
14 changes: 14 additions & 0 deletions sphinx/pycode/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ def visit_Name(self, node: ast.Name) -> str:
def visit_Set(self, node: ast.Set) -> str:
return "{" + ", ".join(self.visit(e) for e in node.elts) + "}"

def visit_Slice(self, node: ast.Slice) -> str:
if not node.lower and not node.upper and not node.step:
# Empty slice with default values -> [:]
return ":"

start = self.visit(node.lower) if node.lower else ""
stop = self.visit(node.upper) if node.upper else ""
if not node.step:
# Default step size -> [start:stop]
return f"{start}:{stop}"

step = self.visit(node.step) if node.step else ""
return f"{start}:{stop}:{step}"

def visit_Subscript(self, node: ast.Subscript) -> str:
def is_simple_tuple(value: ast.expr) -> bool:
return (
Expand Down
3 changes: 3 additions & 0 deletions tests/roots/test-ext-autodoc/target/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ async def asyncgenerator():

builtin_func = print
partial_builtin_func = partial(print)

def slice_arg_func(arg: 'float64[:, :]'):
pass
11 changes: 11 additions & 0 deletions tests/test_extensions/test_ext_autodoc_autofunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,14 @@ def test_async_generator(app):
' :async:',
'',
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_slice_function_arg(app):
actual = do_autodoc(app, 'function', 'target.functions.slice_arg_func')
assert list(actual) == [
'',
'.. py:function:: slice_arg_func(arg: float64[:, :])',
' :module: target.functions',
'',
]
7 changes: 7 additions & 0 deletions tests/test_pycode/test_pycode_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
"lambda x=0, /, y=1, *args, z, **kwargs: ..."), # posonlyargs
("0x1234", "0x1234"), # Constant
("1_000_000", "1_000_000"), # Constant
("Tuple[:,:]", "Tuple[:, :]"), # Index, Subscript, 2x Slice
picnixz marked this conversation as resolved.
Show resolved Hide resolved
("Tuple[1:2]", "Tuple[1:2]"), # Index, Subscript, Slice(no-step)
("Tuple[1:2:3]", "Tuple[1:2:3]"), # Index, Subscript, Slice
("x[:, np.newaxis, :, :]",
"x[:, np.newaxis, :, :]"), # Index, Subscript, numpy extended syntax
("y[:, 1:3][np.array([0, 2, 4]), :]",
"y[:, 1:3][np.array([0, 2, 4]), :]"), # Index, 2x Subscript, numpy extended syntax
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just by looking at all those identity checks, I think we should have used a sentinel value, say IDENTICAL, to indicate that the output is the same as the input. This is an easy follow-up PR though.

])
def test_unparse(source, expected):
module = ast.parse(source)
Expand Down