diff --git a/docs/conf.py b/docs/conf.py index 5cf155d845..a5103f5cd8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -37,16 +37,10 @@ 'sphinx_tabs.tabs', 'sphinxcontrib.apidoc', 'sphinxcontrib.towncrier.ext', # provides `.. towncrier-draft-entries::` -] -# Conditional third-party extensions: -try: - import sphinxcontrib.spelling as _sphinxcontrib_spelling -except ImportError: - extensions.append('spelling_stub_ext') -else: - del _sphinxcontrib_spelling # noqa: WPS100 - extensions.append('sphinxcontrib.spelling') + # In-tree extensions: + 'spelling_stub_ext', # auto-loads `sphinxcontrib.spelling` if installed +] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/spelling_stub_ext.py b/docs/spelling_stub_ext.py index f04c55ded6..0eda52b3f6 100644 --- a/docs/spelling_stub_ext.py +++ b/docs/spelling_stub_ext.py @@ -3,11 +3,54 @@ from typing import List from sphinx.application import Sphinx +from sphinx.config import Config as _SphinxConfig +from sphinx.util import logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import nodes from cheroot import __version__ +try: + from enchant.tokenize import ( # noqa: WPS433 + Filter as _EnchantTokenizeFilterBase, + ) +except ImportError: + _EnchantTokenizeFilterBase = object # noqa: WPS440 + + +logger = logging.getLogger(__name__) + + +def _configure_spelling_ext(app: Sphinx, config: _SphinxConfig) -> None: + class VersionFilter(_EnchantTokenizeFilterBase): # noqa: WPS431 + # NOTE: It's nested because we need to reference the config by closure. + """Filter for treating version words as known.""" + + def _skip(self, word: str) -> bool: + # NOTE: Only accessing the config values in the method since they + # NOTE: aren't yet populated when the config-inited event happens. + known_version_words = { + config.release, + config.version, + __version__, + } + if word not in known_version_words: + return False + + logger.debug( + 'Known version words: %r', # noqa: WPS323 + known_version_words, + ) + logger.debug( + 'Ignoring %r because it is a known version', # noqa: WPS323 + word, + ) + + return True + + app.config.spelling_filters = [VersionFilter] + app.setup_extension('sphinxcontrib.spelling') + class SpellingNoOpDirective(SphinxDirective): """Definition of the stub spelling directive.""" @@ -21,7 +64,10 @@ def run(self) -> List[nodes.Node]: def setup(app: Sphinx) -> None: """Initialize the extension.""" - app.add_directive('spelling', SpellingNoOpDirective) + if _EnchantTokenizeFilterBase is object: + app.add_directive('spelling', SpellingNoOpDirective) + else: + app.connect('config-inited', _configure_spelling_ext) return { 'parallel_read_safe': True,