Skip to content

Commit 82f1b98

Browse files
committed
ENH: enable multiline signatures when too long.
1 parent 29e12ec commit 82f1b98

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

sphinx/addnodes.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ class desc_content(nodes.General, nodes.Element):
183183
"""
184184

185185

186+
class desc_compact_content(nodes.General, nodes.Element):
187+
"""Node for compact object description content.
188+
189+
Must be the last child node in a :py:class:`desc` node.
190+
"""
191+
192+
186193
class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement):
187194
"""Node for a signature fragment in inline text.
188195

sphinx/domains/python.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,21 +251,22 @@ def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
251251

252252

253253
def _parse_arglist(
254-
arglist: str, env: BuildEnvironment | None = None
254+
arglist: str, env: BuildEnvironment | None = None, multiline=False
255255
) -> addnodes.desc_parameterlist:
256256
"""Parse a list of arguments using AST parser"""
257257
params = addnodes.desc_parameterlist(arglist)
258258
sig = signature_from_str('(%s)' % arglist)
259259
last_kind = None
260260
for param in sig.parameters.values():
261+
param_node = addnodes.desc_compact_content() if multiline else params
261262
if param.kind != param.POSITIONAL_ONLY and last_kind == param.POSITIONAL_ONLY:
262263
# PEP-570: Separator for Positional Only Parameter: /
263-
params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
264+
param_node += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '/'))
264265
if param.kind == param.KEYWORD_ONLY and last_kind in (param.POSITIONAL_OR_KEYWORD,
265266
param.POSITIONAL_ONLY,
266267
None):
267268
# PEP-3102: Separator for Keyword Only Parameter: *
268-
params += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '*'))
269+
param_node += addnodes.desc_parameter('', '', addnodes.desc_sig_operator('', '*'))
269270

270271
node = addnodes.desc_parameter()
271272
if param.kind == param.VAR_POSITIONAL:
@@ -292,7 +293,9 @@ def _parse_arglist(
292293
node += nodes.inline('', param.default, classes=['default_value'],
293294
support_smartquotes=False)
294295

295-
params += node
296+
param_node += node
297+
if multiline:
298+
params += param_node
296299
last_kind = param.kind
297300

298301
if last_kind == Parameter.POSITIONAL_ONLY:
@@ -452,6 +455,7 @@ class PyObject(ObjectDescription[Tuple[str, str]]):
452455
'noindex': directives.flag,
453456
'noindexentry': directives.flag,
454457
'nocontentsentry': directives.flag,
458+
'singlelinesig': directives.flag,
455459
'module': directives.unchanged,
456460
'canonical': directives.unchanged,
457461
'annotation': directives.unchanged,
@@ -533,6 +537,13 @@ def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]
533537
signode['module'] = modname
534538
signode['class'] = classname
535539
signode['fullname'] = fullname
540+
max_len = self.env.config.python_maximum_signature_line_length
541+
multiline = (
542+
max_len >= 0
543+
and 'singlelinesig' not in self.options
544+
and len(sig) > max_len
545+
)
546+
signode['is_multiline'] = multiline
536547

537548
sig_prefix = self.get_signature_prefix(sig)
538549
if sig_prefix:
@@ -553,7 +564,7 @@ def handle_signature(self, sig: str, signode: desc_signature) -> tuple[str, str]
553564
signode += addnodes.desc_name(name, name)
554565
if arglist:
555566
try:
556-
signode += _parse_arglist(arglist, self.env)
567+
signode += _parse_arglist(arglist, self.env, multiline=multiline)
557568
except SyntaxError:
558569
# fallback to parse arglist original parser.
559570
# it supports to represent optional arguments (ex. "func(foo [, bar])")
@@ -1510,6 +1521,7 @@ def setup(app: Sphinx) -> dict[str, Any]:
15101521

15111522
app.add_domain(PythonDomain)
15121523
app.add_config_value('python_use_unqualified_type_names', False, 'env')
1524+
app.add_config_value('python_maximum_signature_line_length', -1, 'env')
15131525
app.connect('object-description-transform', filter_meta_fields)
15141526
app.connect('missing-reference', builtin_resolver, priority=900)
15151527

sphinx/themes/basic/static/basic.css_t

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,11 @@ dd {
670670
margin-left: 30px;
671671
}
672672

673+
dd.compact {
674+
margin-top: 0px;
675+
margin-bottom: 0px;
676+
}
677+
673678
dl > dd:last-child,
674679
dl > dd:last-child > :last-child {
675680
margin-bottom: 0;

sphinx/writers/html5.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ def visit_desc_content(self, node: Element) -> None:
114114
def depart_desc_content(self, node: Element) -> None:
115115
self.body.append('</dd>')
116116

117+
def visit_desc_compact_content(self, node: Element) -> None:
118+
self.body.append(self.starttag(node, 'dd', '', classes=['compact']))
119+
120+
def depart_desc_compact_content(self, node: Element) -> None:
121+
self.body.append('</dd>')
122+
117123
def visit_desc_inline(self, node: Element) -> None:
118124
self.body.append(self.starttag(node, 'span', ''))
119125

0 commit comments

Comments
 (0)