From 83fba8b832abd7e8b0516e8623c39c8d87b8fda0 Mon Sep 17 00:00:00 2001 From: Kwankyu Lee Date: Fri, 15 Mar 2024 22:33:25 +0900 Subject: [PATCH] Add docstring transform --- src/doc/common/static/custom-furo.css | 6 ++ src/sage/misc/sagedoc_conf.py | 9 +++ src/sage_docbuild/conf.py | 80 +++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/src/doc/common/static/custom-furo.css b/src/doc/common/static/custom-furo.css index fc76a3f7c0f..629e9435de2 100644 --- a/src/doc/common/static/custom-furo.css +++ b/src/doc/common/static/custom-furo.css @@ -21,3 +21,9 @@ a.pdf:hover { text-decoration: none; } + +/* For sections INPUT, OUTPUT, EXAMPLES, etc. */ + +abbr { + font-weight: 500; +} diff --git a/src/sage/misc/sagedoc_conf.py b/src/sage/misc/sagedoc_conf.py index 2cacfcf8327..c31a0d4d195 100644 --- a/src/sage/misc/sagedoc_conf.py +++ b/src/sage/misc/sagedoc_conf.py @@ -19,6 +19,7 @@ # The reST default role (used for this markup: `text`) to use for all documents. default_role = 'math' + def process_docstring_aliases(app, what, name, obj, options, docstringlines): """ Change the docstrings for aliases to point to the original object. @@ -27,6 +28,7 @@ def process_docstring_aliases(app, what, name, obj, options, docstringlines): if hasattr(obj, '__name__') and obj.__name__ != basename: docstringlines[:] = ['See :obj:`%s`.' % name] + def process_directives(app, what, name, obj, options, docstringlines): """ Remove 'nodetex' and other directives from the first line of any @@ -39,6 +41,7 @@ def process_directives(app, what, name, obj, options, docstringlines): if 'nodetex' in directives: docstringlines.pop(0) + def process_docstring_cython(app, what, name, obj, options, docstringlines): """ Remove Cython's filename and location embedding. @@ -52,6 +55,7 @@ def process_docstring_cython(app, what, name, obj, options, docstringlines): docstringlines.pop(0) docstringlines.pop(0) + def process_docstring_module_title(app, what, name, obj, options, docstringlines): """ Removes the first line from the beginning of the module's docstring. This @@ -74,6 +78,7 @@ def process_docstring_module_title(app, what, name, obj, options, docstringlines else: break + def process_dollars(app, what, name, obj, options, docstringlines): r""" Replace dollar signs with backticks. @@ -87,6 +92,7 @@ def process_dollars(app, what, name, obj, options, docstringlines): for i in range(len(lines)): docstringlines[i] = lines[i] + def process_inherited(app, what, name, obj, options, docstringlines): """ If we're including inherited members, omit their docstrings. @@ -110,6 +116,7 @@ def process_inherited(app, what, name, obj, options, docstringlines): for i in range(len(docstringlines)): docstringlines.pop() + def skip_TESTS_block(app, what, name, obj, options, docstringlines): """ Skip blocks labeled "TESTS:". @@ -127,6 +134,7 @@ def skip_TESTS_block(app, what, name, obj, options, docstringlines): while len(docstringlines) > len(lines): del docstringlines[len(lines)] + class SagemathTransform(Transform): """ Transform for code-blocks. @@ -146,6 +154,7 @@ def apply(self): node.rawsource = source node[:] = [nodes.Text(source)] + # This is only used by sage.misc.sphinxify def setup(app): app.connect('autodoc-process-docstring', process_docstring_cython) diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index c5329e79cfd..e34cc457c90 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -853,6 +853,85 @@ def apply(self): node.parent.insert(node.parent.index(node) + 1, cell_node) +class DocstringTransform(SphinxTransform): + r""" + Transform sections in Sage docstrings for better rendering. + + The following are tests. + + AUTHORS: + + - Alice + - Bob + + INPUT: + + - one + - two + + OUTPUT: + + three + + OUTPUT: three + + EXAMPLE:: + + sage: 1 + 2 + 3 + + EXAMPLES:: + + sage: 1 + 2 + 3 + + EXAMPLE: + + We show that `1 + 2 = 3`:: + + sage: 1 + 2 + 3 + + EXAMPLES: + + We show that `1 + 2 = 3`:: + + sage: 1 + 2 + 3 + + """ + default_priority = 600 + + def apply(self): + for node in self.document.traverse(nodes.paragraph): + if isinstance(node.children[0], nodes.Text) and node.children[0].astext().strip() == 'AUTHORS:': + list_node = node.next_node(siblings=True, descend=False) + if isinstance(list_node, nodes.bullet_list): + new_node = nodes.admonition(classes=['authors'], admonitionclass='authors') + node.replace_self(new_node) + node = new_node + admonition_title = nodes.title() + admonition_title.append(nodes.Text('Authors')) + node.insert(0, admonition_title) + node.append(list_node) + node.parent.remove(list_node) + if isinstance(node.children[0], nodes.Text): + text = node.children[0].astext() + for section in ['INPUT', 'OUTPUT', 'EXAMPLES', 'EXAMPLE', 'TESTS', 'TEST', + 'ALGORITHM', 'REFERENCE', 'REFERENCES']: + if text.startswith(f'{section}:'): + parent = node.parent + index = parent.index(node) + parent.remove(node) + acronym_node = nodes.acronym() + acronym_node += nodes.Text(section) + para = nodes.paragraph() + para += acronym_node + para += nodes.Text(text[len(f'{section}:'):]) + parent.insert(index, para) + break + + # This replaces the setup() in sage.misc.sagedoc_conf def setup(app): app.connect('autodoc-process-docstring', process_docstring_cython) @@ -864,6 +943,7 @@ def setup(app): app.connect('autodoc-process-docstring', skip_TESTS_block) app.connect('autodoc-skip-member', skip_member) app.add_transform(SagemathTransform) + app.add_transform(DocstringTransform) if os.environ.get('SAGE_LIVE_DOC', 'no') == 'yes': app.add_transform(SagecodeTransform)