From aab83a4f183f5e0e47b4222d04d6042806cc8fd2 Mon Sep 17 00:00:00 2001 From: Kazuya Takei Date: Sat, 16 Mar 2024 21:48:10 +0900 Subject: [PATCH] feat: 'only' decorator set warning for builder restricts. --- src/atsphinx/helpers/decorators.py | 56 ++++++++++++++++++++++++++++++ tests/test-root/conf.py | 7 ++++ tests/test_it.py | 5 +-- 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/atsphinx/helpers/decorators.py diff --git a/src/atsphinx/helpers/decorators.py b/src/atsphinx/helpers/decorators.py new file mode 100644 index 0000000..a8852f2 --- /dev/null +++ b/src/atsphinx/helpers/decorators.py @@ -0,0 +1,56 @@ +"""Helpful decorators.""" + +import functools +from typing import Callable, List, Optional, Union + +from sphinx.application import Sphinx +from sphinx.util.logging import getLogger + +Logger = getLogger(__name__) + + +def only(*, builders: Optional[List[str]] = None, formats: Optional[List[str]] = None): + """Restict extension by builder types or formats. + + This is decorator function. + You can message for users that this extension is created for specify builders. + + .. code-block:: python + :caption: your_extension.py + :name: your_extension.py + + # Display warning when user runs by not 'html' builders. + @only(builder=["html"]) + def setup(app): + ... + + :params builders: List of builder names for restrict target. + :params formats: List of format types for restrict target. + """ + if builders is None and formats is None: + Logger.warning( + "To use @only, you should set argument builders or formats at least." + ) + + def _only(func: Callable[[Sphinx], Union[dict, None]]): + logger = getLogger(func.__module__ or "confpy") + + def _restrict_builder(app: Sphinx): + target = func.__module__ or "setup() on conf.py" + if builders and app.builder.name not in builders: + logger.warning( + f"{target} is not supported '{app.builder.name}' builder." + ) + if formats and app.builder.format not in formats: + logger.warning( + f"{target} is not supported '{app.builder.format}' format." + ) + + @functools.wraps(func) + def __only(app: Sphinx): + app.connect("builder-inited", _restrict_builder) + func(app) + + return __only + + return _only diff --git a/tests/test-root/conf.py b/tests/test-root/conf.py index d03c8b6..fa92713 100644 --- a/tests/test-root/conf.py +++ b/tests/test-root/conf.py @@ -1 +1,8 @@ +from atsphinx.helpers.decorators import only + extensions = [] + + +@only(builders=["linkcheck"]) +def setup(app): + pass diff --git a/tests/test_it.py b/tests/test_it.py index b8bca08..11690aa 100644 --- a/tests/test_it.py +++ b/tests/test_it.py @@ -7,6 +7,7 @@ @pytest.mark.sphinx("html") -def test__it(app: SphinxTestApp, status: StringIO, warning: StringIO): - """Test to pass.""" +def test__print_warning(app: SphinxTestApp, warning: StringIO): app.build() + expected = "is not supported 'html' builder." + assert expected in warning.getvalue()