From 2367a83443d8ee61e8c3942d53cdb26010bec208 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Nov 2023 20:41:05 +0200 Subject: [PATCH 1/4] extensions: add functions for direct usage for cli and testing It's not easy to adapt the Sphinx extensions for usage in the cli or parser tests without Sphinx. Instead, add direct process_docstring() functions for the simple use cases without extension setup or configuration. --- src/hawkmoth/ext/javadoc/__init__.py | 6 ++++++ src/hawkmoth/ext/napoleon/__init__.py | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/hawkmoth/ext/javadoc/__init__.py b/src/hawkmoth/ext/javadoc/__init__.py index ac8e7be6..dff40432 100644 --- a/src/hawkmoth/ext/javadoc/__init__.py +++ b/src/hawkmoth/ext/javadoc/__init__.py @@ -11,6 +11,12 @@ def _process_docstring(app, lines, transform, options): comment = javadoc_liberal(comment) lines[:] = comment.splitlines()[:] +def process_docstring(lines): + """Simple interface for CLI and testing.""" + comment = '\n'.join(lines) + comment = javadoc_liberal(comment) + lines[:] = comment.splitlines()[:] + def setup(app): app.setup_extension('hawkmoth') diff --git a/src/hawkmoth/ext/napoleon/__init__.py b/src/hawkmoth/ext/napoleon/__init__.py index 2a3a59a3..3e5b89e5 100644 --- a/src/hawkmoth/ext/napoleon/__init__.py +++ b/src/hawkmoth/ext/napoleon/__init__.py @@ -1,7 +1,7 @@ # Copyright (c) 2023, Jani Nikula # Licensed under the terms of BSD 2-Clause, see LICENSE for details. -from sphinx.ext.napoleon import _process_docstring +from sphinx.ext import napoleon def _process_docstring_proxy(app, lines, transform, options): if transform != app.config.hawkmoth_napoleon_transform: @@ -12,7 +12,14 @@ def _process_docstring_proxy(app, lines, transform, options): # directly, but the alternative is duplicating all it does, which is also # ugly. - return _process_docstring(app, None, None, None, options, lines) + return napoleon._process_docstring(app, None, None, None, options, lines) + +def process_docstring(lines): + """Simple interface for CLI and testing.""" + comment = '\n'.join(lines) + config = napoleon.Config(napoleon_use_rtype=False) + comment = str(napoleon.docstring.GoogleDocstring(comment, config)) + lines[:] = comment.splitlines()[:] def setup(app): app.setup_extension('sphinx.ext.napoleon') From 9801fbb1fb54768629259e47ce82ebc1906ee8df Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Nov 2023 20:49:17 +0200 Subject: [PATCH 2/4] test: use extensions for parser test process docstring calls Move away from doccompat, and use the extensions for docstring processing. --- test/test_parser.py | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/test/test_parser.py b/test/test_parser.py index 27c92040..4ecf8a90 100755 --- a/test/test_parser.py +++ b/test/test_parser.py @@ -4,28 +4,23 @@ import os -from sphinx.ext import napoleon import pytest from hawkmoth import docstring +from hawkmoth.ext import javadoc +from hawkmoth.ext import napoleon from hawkmoth.parser import parse -from hawkmoth.util import doccompat from test import testenv -def napoleon_transform(comment): - config = napoleon.Config(napoleon_use_rtype=False) - return str(napoleon.docstring.GoogleDocstring(comment, config)) - -parser_transformations = { - 'napoleon': napoleon_transform, - 'javadoc': doccompat.javadoc_liberal, -} - def _process_docstring(transform, lines): - if transform: - text = '\n'.join(lines) - text = transform(text) - lines[:] = [line for line in text.splitlines()] + transformations = { + 'napoleon': napoleon.process_docstring, + 'javadoc': javadoc.process_docstring, + } + + fn = transformations.get(transform) + if fn: + fn(lines) def _filter_types(directive): types = { @@ -104,12 +99,7 @@ def get_output(self): if filter_clang_args is not None and root.get_clang_args() not in filter_clang_args: continue - tropt = directive.options.get('transform') - if tropt is not None: - transform = parser_transformations[tropt] - else: - transform = None - + transform = directive.options.get('transform') process_docstring = lambda lines: _process_docstring(transform, lines) for docstrings in root.walk(recurse=False, filter_types=_filter_types(directive), From da2a686285e699ca326dbca47dd00b5f63a5e00e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Nov 2023 20:57:18 +0200 Subject: [PATCH 3/4] cli: add --process-docstring for extension based docstring processing Add --process-docstring option to use the extension for docstring processing. Leave the --compat option in place for now, but we might want to deprecate and remove it going forward. --- src/hawkmoth/__main__.py | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/hawkmoth/__main__.py b/src/hawkmoth/__main__.py index d68b407e..70c4b573 100644 --- a/src/hawkmoth/__main__.py +++ b/src/hawkmoth/__main__.py @@ -11,6 +11,8 @@ import os import sys +from hawkmoth.ext import javadoc +from hawkmoth.ext import napoleon from hawkmoth.parser import parse from hawkmoth.util import doccompat @@ -19,7 +21,17 @@ def filename(file): return file raise ValueError -def _process_docstring(args, lines): +def _process_docstring(transform, lines): + transformations = { + 'napoleon': napoleon.process_docstring, + 'javadoc': javadoc.process_docstring, + } + + fn = transformations.get(transform) + if fn: + fn(lines) + +def _process_docstring_compat(args, lines): text = '\n'.join(lines) text = doccompat.convert(text, transform=args.compat) lines[:] = [line for line in text.splitlines()] @@ -45,11 +57,20 @@ def main(): choices=['c', 'cpp'], default='c', help='Sphinx domain to be used.') - parser.add_argument('--compat', - choices=['none', - 'javadoc-basic', - 'javadoc-liberal', - 'kernel-doc'], + compat = parser.add_mutually_exclusive_group() + compat.add_argument('--process-docstring', + choices=[ + 'javadoc', + 'napoleon', + ], + help='Process docstring.') + compat.add_argument('--compat', + choices=[ + 'none', + 'javadoc-basic', + 'javadoc-liberal', + 'kernel-doc' + ], help='Compatibility options. See cautodoc_compat.') parser.add_argument('--clang', metavar='PARAM', action='append', help='Argument to pass to Clang. May be specified multiple times. See cautodoc_clang.') # noqa: E501 @@ -62,7 +83,10 @@ def main(): comments, errors = parse(args.file, domain=args.domain, clang_args=args.clang) - process_docstring = lambda lines: _process_docstring(args, lines) + if args.process_docstring: + process_docstring = lambda lines: _process_docstring(args.process_docstring, lines) + else: + process_docstring = lambda lines: _process_docstring_compat(args, lines) for comment in comments.walk(): if args.verbose: From f6b73d3d1294b71889e39eeed9932cb2bd38358e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 13 Nov 2023 20:59:35 +0200 Subject: [PATCH 4/4] test: handle process docstring in cli tests Now that the cli supports --process-docstring, we can handle transform also in the cli tests, and skip two fewer tests. --- test/test_cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_cli.py b/test/test_cli.py index 1ab7110b..554559d3 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -65,7 +65,7 @@ def get_output(self): transform = directive.options.get('transform') if transform is not None: - pytest.skip('cli does not support generic transformations') + args += [f'--process-docstring={transform}'] clang_args = directive.get_clang_args() if clang_args: