From 50f32c26184fd73590117ef6a7cd952c74bf307b Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 10:25:53 -0400 Subject: [PATCH 1/8] convert to hatchling for build backend --- pyproject.toml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2934b1d..91dcf51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [build-system] -requires = ["setuptools", "setuptools_scm[toml]>=6.2"] -build-backend = "setuptools.build_meta" +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" [project] name = "sphinxcontrib-spelling" @@ -42,11 +42,9 @@ spelling = "sphinxcontrib.spelling" homepage = "https://sphinxcontrib-spelling.readthedocs.io/en/latest/" repository = "https://github.com/sphinx-contrib/spelling" -# https://github.com/pypa/setuptools_scm/ -[tool.setuptools_scm] -write_to = "sphinxcontrib/spelling/version.py" +[tool.hatch.version] +source = "vcs" +path = "sphinxcontrib/spelling/version.py" -[tool.setuptools] -# Be explicit to avoid an error because build finds cover, -# sphinxcontrib, and integration_tests as potential packages. +[tool.hatch.build] packages = ["sphinxcontrib.spelling"] From 6dccaec8623479a9393ae8aaca3907ca636674fa Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 10:55:51 -0400 Subject: [PATCH 2/8] rename README to README.rst for packaging --- README => README.rst | 0 pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename README => README.rst (100%) diff --git a/README b/README.rst similarity index 100% rename from README rename to README.rst diff --git a/pyproject.toml b/pyproject.toml index 91dcf51..a338119 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "sphinxcontrib-spelling" -readme = "README" +readme = "README.rst" authors = [{ name = "Doug Hellmann", email = "doug@doughellmann.com" }] description = "Sphinx spelling extension" dynamic = ["version"] From 811c53acbc6690719521814bab140348718c0c45 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 10:56:35 -0400 Subject: [PATCH 3/8] move tox settings into pyproject.toml for use with hatch --- pyproject.toml | 36 ++++++++++++++++++++++-- tox.ini | 75 -------------------------------------------------- 2 files changed, 34 insertions(+), 77 deletions(-) delete mode 100644 tox.ini diff --git a/pyproject.toml b/pyproject.toml index a338119..51e4f79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,5 +46,37 @@ repository = "https://github.com/sphinx-contrib/spelling" source = "vcs" path = "sphinxcontrib/spelling/version.py" -[tool.hatch.build] -packages = ["sphinxcontrib.spelling"] +[tool.hatch.build.targets.sdist] +exclude = [".github", "cover", ".mergify.yml", ".gitignore"] +[tool.hatch.build.targets.wheel] +only-include = ["sphinxcontrib"] + +[tool.hatch.envs.docs] +dependencies = ["sphinx"] +[tool.hatch.envs.docs.env] +ENABLE_SPELLING = "1" +[tool.hatch.envs.docs.scripts] +build = [ + "sphinx-build -W -j auto -b html -d docs/build/doctrees docs/source docs/build/html", + "sphinx-build -W -j auto -b linkcheck -d docs/build/doctrees docs/source docs/build/linkcheck", + "sphinx-build -W -j auto -b spelling -d docs/build/doctrees docs/source docs/build/spelling", +] +check = "sphinx-build -W -j auto -b spelling -d docs/build/doctrees docs/source docs/build/spelling" + +[tool.hatch.envs.test] +dependencies = [ + "pytest", + "pytest-cov", + "coverage!=4.4,>=4.0", + "ruff", + "twine", + "check-python-versions", +] +[tool.hatch.envs.test.scripts] +test = "python -m pytest --cov=sphinxcontrib.spelling --cov-report term-missing --log-level DEBUG tests" +lint = "ruff check sphinxcontrib integration_tests tests" +pkglint = [ + "hatch build", + "twine check dist/*.tar.gz dist/*.whl", + "check-python-versions --only pyproject.toml,.github/workflows/test.yml", +] diff --git a/tox.ini b/tox.ini deleted file mode 100644 index f323c92..0000000 --- a/tox.ini +++ /dev/null @@ -1,75 +0,0 @@ -[tox] -minversion = 3.2.0 -envlist=py,linter,docs - -[testenv] -extras = - test -commands= - python -m pytest \ - --cov=sphinxcontrib.spelling \ - --cov-report term-missing \ - --log-level DEBUG -passenv= - # Let the caller point to where libenchant is on their system, in - # case it's in an unusual place. For example, on macOS with - # Homebrew installing python 3.9 by default but tox being run from - # the python.org distribution of 3.10, set - # PYENCHANT_LIBRARY_PATH=/opt/homebrew/lib/libenchant-2.dylib in - # the shell environment before running tox. - PYENCHANT_LIBRARY_PATH - -[testenv:isolated] -isolated_build=true -changedir={envtmpdir} -allowlist_externals = - /bin/cp - /bin/rm -commands= - /bin/rm -rf tests - /bin/cp -a {toxinidir}/tests . - python -m pytest \ - --cov=sphinxcontrib.spelling \ - --cov-report term-missing \ - --log-level DEBUG - -[testenv:linter] -deps = -r requirements-dev.txt -setenv = - BUILD=linter -commands = - ruff check sphinxcontrib integration_tests tests -skip_install = true - -[testenv:pkglint] -deps= - build - twine - check-python-versions -commands= - python -m build - twine check dist/*.tar.gz dist/*.whl - check-python-versions --only pyproject.toml,.github/workflows/test.yml - -[flake8] -show-source = True -exclude = .tox,dist,doc,*.egg,build -ignore = W504 -per-file-ignores = - integration_tests/build_django.py: DB100 - -[testenv:docs] -setenv = - BUILD=docs - ENABLE_SPELLING=1 -commands = - sphinx-build -W -j auto -b html -d docs/build/doctrees docs/source docs/build/html - sphinx-build -W -j auto -b linkcheck -d docs/build/doctrees docs/source docs/build/linkcheck - sphinx-build -W -j auto -b spelling -d docs/build/doctrees docs/source docs/build/spelling - -[testenv:spelling] -setenv = - BUILD=docs - ENABLE_SPELLING=1 -commands = - sphinx-build -W -j auto -b spelling -d docs/build/doctrees docs/source docs/build/spelling From 0e714fed180befc49fd05671a8b8dc67d6c9348e Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 11:09:17 -0400 Subject: [PATCH 4/8] move integration test to hatch --- .github/workflows/integration.yaml | 6 +++--- pyproject.toml | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 43d0f18..d742330 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -23,7 +23,7 @@ jobs: python-version: '3.x' - name: Install dependencies - run: python3 -m pip install tox + run: python3 -m pip install hatch - - name: Build docs - run: python3 ./integration_tests/build_django.py + - name: Test + run: hatch run integration:django diff --git a/pyproject.toml b/pyproject.toml index 51e4f79..5a99676 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,3 +80,8 @@ pkglint = [ "twine check dist/*.tar.gz dist/*.whl", "check-python-versions --only pyproject.toml,.github/workflows/test.yml", ] + +[tool.hatch.envs.integration] +dependencies = ["tox"] +[tool.hatch.envs.integration.scripts] +django = "./integration_tests/build_django.py" From bc2b1c9d238bd5aaffb664947efb6a0626892658 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 11:09:37 -0400 Subject: [PATCH 5/8] move github actions to hatch --- .github/workflows/check.yml | 15 +++++++-------- .github/workflows/test.yml | 4 ++-- .mergify.yml | 7 +++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 34e92cd..3da69a7 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -12,12 +12,11 @@ jobs: strategy: fail-fast: false matrix: - tox-environment: - - docs - - linter - - pkglint - - spelling - - isolated + hatch-environment: + - docs:build + - docs:check + - test:lint + - test:pkglint steps: - uses: actions/checkout@v4 @@ -30,7 +29,7 @@ jobs: python-version: '3.x' - name: Install dependencies - run: python -m pip install tox + run: python -m pip install hatch - name: Run - run: tox -e ${{ matrix.tox-environment }} + run: hatch run ${{ matrix.hatch-environment }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f8cef2..c12cb24 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,7 +28,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies - run: python -m pip install tox + run: python -m pip install hatch - name: Run tests - run: tox -e py + run: hatch run test:test diff --git a/.mergify.yml b/.mergify.yml index b8bab2c..f7fd10c 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -24,10 +24,9 @@ pull_request_rules: - name: Automatic merge on approval conditions: - and: - - "check-success=build (docs)" - - "check-success=build (isolated)" - - "check-success=build (linter)" - - "check-success=build (spelling)" + - "check-success=build (docs:build)" + - "check-success=build (test:linter)" + - "check-success=build (docs:spelling)" - "check-success=django" - "check-success=build (3.10)" - "check-success=build (3.11)" From 11e2997ac58e630c8be807822df2e4b408581036 Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 11:12:41 -0400 Subject: [PATCH 6/8] update release notes --- docs/source/history.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/history.rst b/docs/source/history.rst index de22101..7aec773 100644 --- a/docs/source/history.rst +++ b/docs/source/history.rst @@ -24,8 +24,7 @@ Next ==== -- Modernize packaging using setuptools, build, and setuptools_scm - instead of pbr. +- Modernize packaging using hatch and hatchling. Bug Fixes --------- From 92c0fca568e5071fc105dab6563663210ca2ff1b Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 11:45:57 -0400 Subject: [PATCH 7/8] fix version file writing --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5a99676..115d56a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,9 @@ repository = "https://github.com/sphinx-contrib/spelling" [tool.hatch.version] source = "vcs" -path = "sphinxcontrib/spelling/version.py" + +[tool.hatch.build.hooks.vcs] +version-file = "sphinxcontrib/spelling/version.py" [tool.hatch.build.targets.sdist] exclude = [".github", "cover", ".mergify.yml", ".gitignore"] From ab84297567c8fcfda904eb7e929c11f00184a18e Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Sun, 25 May 2025 11:51:37 -0400 Subject: [PATCH 8/8] pass code through ruff --- integration_tests/build_django.py | 66 ++++++++++------- pyproject.toml | 9 ++- sphinxcontrib/spelling/__init__.py | 38 +++++----- sphinxcontrib/spelling/asset.py | 3 +- sphinxcontrib/spelling/builder.py | 109 +++++++++++++--------------- sphinxcontrib/spelling/checker.py | 26 ++++--- sphinxcontrib/spelling/directive.py | 15 ++-- sphinxcontrib/spelling/domain.py | 18 ++--- sphinxcontrib/spelling/role.py | 6 +- tests/helpers.py | 4 +- 10 files changed, 147 insertions(+), 147 deletions(-) diff --git a/integration_tests/build_django.py b/integration_tests/build_django.py index 27814f9..cc6e220 100755 --- a/integration_tests/build_django.py +++ b/integration_tests/build_django.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -"""Try to build the Django documentation. -""" +"""Try to build the Django documentation.""" import argparse import os @@ -10,59 +9,72 @@ import tempfile -def doit(*cmd, description='', cwd=None): - print(f'\n[{description}]\nrunning: {" ".join(cmd)}') +def doit(*cmd, description="", cwd=None): + print(f"\n[{description}]\nrunning: {' '.join(cmd)}") completed = subprocess.run(cmd, cwd=cwd) try: completed.check_returncode() except subprocess.CalledProcessError as err: - raise RuntimeError(f'command failed {description}') from err + raise RuntimeError(f"command failed {description}") from err def try_build(workdir, srcdir, django_repo): - print(f'working in {workdir}') + print(f"working in {workdir}") doit( - 'git', 'clone', '--depth', '1', django_repo, 'django', - description='clone django', + "git", + "clone", + "--depth", + "1", + django_repo, + "django", + description="clone django", cwd=workdir, ) - djangodir = workdir + '/django' + djangodir = workdir + "/django" doit( - 'tox', '-e', 'docs', '--notest', - description='build django docs virtualenv', + "tox", + "-e", + "docs", + "--notest", + description="build django docs virtualenv", cwd=djangodir, ) doit( - '.tox/docs/bin/pip', 'uninstall', '-y', 'sphinxcontrib-spelling', - description='uninstall packaged sphinxcontrib-spelling', + ".tox/docs/bin/pip", + "uninstall", + "-y", + "sphinxcontrib-spelling", + description="uninstall packaged sphinxcontrib-spelling", cwd=djangodir, ) doit( - '.tox/docs/bin/pip', 'install', srcdir, - description='install sphinxcontrib-spelling from source', + ".tox/docs/bin/pip", + "install", + srcdir, + description="install sphinxcontrib-spelling from source", cwd=djangodir, ) doit( - 'tox', '-e', 'docs', - description='build django docs', + "tox", + "-e", + "docs", + description="build django docs", cwd=djangodir, ) def main(args=sys.argv[1:]): parser = argparse.ArgumentParser() - parser.add_argument('--debug', action='store_true', default=False, - help='show full tracebacks') - parser.add_argument('--src', help='source directory') - parser.add_argument('--django-repo', - default='https://github.com/django/django.git') + parser.add_argument( + "--debug", action="store_true", default=False, help="show full tracebacks" + ) + parser.add_argument("--src", help="source directory") + parser.add_argument("--django-repo", default="https://github.com/django/django.git") parsed = parser.parse_args(args) srcdir = parsed.src if not srcdir: - srcdir = os.path.realpath( - os.path.dirname(os.path.dirname(sys.argv[0])) - ) + srcdir = os.path.realpath(os.path.dirname(os.path.dirname(sys.argv[0]))) try: with tempfile.TemporaryDirectory() as dirname: @@ -70,10 +82,10 @@ def main(args=sys.argv[1:]): except Exception as err: if parsed.debug: raise - print(f'ERROR: {err}') + print(f"ERROR: {err}") return 1 return 0 -if __name__ == '__main__': +if __name__ == "__main__": sys.exit(main()) diff --git a/pyproject.toml b/pyproject.toml index 115d56a..33b7004 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,7 +76,11 @@ dependencies = [ ] [tool.hatch.envs.test.scripts] test = "python -m pytest --cov=sphinxcontrib.spelling --cov-report term-missing --log-level DEBUG tests" -lint = "ruff check sphinxcontrib integration_tests tests" +lint = [ + "ruff check sphinxcontrib integration_tests tests", + "ruff format --check sphinxcontrib integration_tests tests", +] +lint-fix = ["ruff format sphinxcontrib integration_tests tests"] pkglint = [ "hatch build", "twine check dist/*.tar.gz dist/*.whl", @@ -87,3 +91,6 @@ pkglint = [ dependencies = ["tox"] [tool.hatch.envs.integration.scripts] django = "./integration_tests/build_django.py" + +[tool.ruff] +exclude = ["sphinxcontrib/spelling/version.py"] diff --git a/sphinxcontrib/spelling/__init__.py b/sphinxcontrib/spelling/__init__.py index 460251b..2e0db5d 100644 --- a/sphinxcontrib/spelling/__init__.py +++ b/sphinxcontrib/spelling/__init__.py @@ -13,51 +13,51 @@ def setup(app): - version = importlib_metadata.version('sphinxcontrib-spelling') - logger.info('Initializing Spelling Checker %s', version) + version = importlib_metadata.version("sphinxcontrib-spelling") + logger.info("Initializing Spelling Checker %s", version) app.add_builder(builder.SpellingBuilder) # Register the 'spelling' directive for setting parameters within # a document - app.add_directive('spelling', directive.LegacySpellingDirective) + app.add_directive("spelling", directive.LegacySpellingDirective) app.add_domain(domain.SpellingDomain) # Register an environment collector to merge data gathered by the # directive in parallel builds app.add_env_collector(asset.SpellingCollector) # Report guesses about correct spelling - app.add_config_value('spelling_show_suggestions', False, 'env') + app.add_config_value("spelling_show_suggestions", False, "env") # Limit the number of suggestions output - app.add_config_value('spelling_suggestion_limit', 0, 'env') + app.add_config_value("spelling_suggestion_limit", 0, "env") # Report the whole line that has the error - app.add_config_value('spelling_show_whole_line', True, 'env') + app.add_config_value("spelling_show_whole_line", True, "env") # Emit misspelling as a sphinx warning instead of info message - app.add_config_value('spelling_warning', False, 'env') + app.add_config_value("spelling_warning", False, "env") # Set the language for the text - app.add_config_value('spelling_lang', 'en_US', 'env') + app.add_config_value("spelling_lang", "en_US", "env") # Set the language for the tokenizer - app.add_config_value('tokenizer_lang', 'en_US', 'env') + app.add_config_value("tokenizer_lang", "en_US", "env") # Set a user-provided list of words known to be spelled properly - app.add_config_value('spelling_word_list_filename', None, 'env') + app.add_config_value("spelling_word_list_filename", None, "env") # Assume anything that looks like a PyPI package name is spelled properly - app.add_config_value('spelling_ignore_pypi_package_names', False, 'env') + app.add_config_value("spelling_ignore_pypi_package_names", False, "env") # Assume words that look like wiki page names are spelled properly - app.add_config_value('spelling_ignore_wiki_words', True, 'env') + app.add_config_value("spelling_ignore_wiki_words", True, "env") # Assume words that are all caps, or all caps with trailing s, are # spelled properly - app.add_config_value('spelling_ignore_acronyms', True, 'env') + app.add_config_value("spelling_ignore_acronyms", True, "env") # Assume words that are part of __builtins__ are spelled properly - app.add_config_value('spelling_ignore_python_builtins', True, 'env') + app.add_config_value("spelling_ignore_python_builtins", True, "env") # Assume words that look like the names of importable modules are # spelled properly - app.add_config_value('spelling_ignore_importable_modules', True, 'env') + app.add_config_value("spelling_ignore_importable_modules", True, "env") # Treat contributor names from git history as spelled correctly - app.add_config_value('spelling_ignore_contributor_names', True, 'env') + app.add_config_value("spelling_ignore_contributor_names", True, "env") # Add any user-defined filter classes - app.add_config_value('spelling_filters', [], 'env') + app.add_config_value("spelling_filters", [], "env") # Set a user-provided list of files to ignore - app.add_config_value('spelling_exclude_patterns', [], 'env') + app.add_config_value("spelling_exclude_patterns", [], "env") # Choose whether or not the misspelled output should be displayed # in the terminal - app.add_config_value('spelling_verbose', True, 'env') + app.add_config_value("spelling_verbose", True, "env") return { "parallel_read_safe": True, "parallel_write_safe": True, diff --git a/sphinxcontrib/spelling/asset.py b/sphinxcontrib/spelling/asset.py index 7934efc..6082726 100644 --- a/sphinxcontrib/spelling/asset.py +++ b/sphinxcontrib/spelling/asset.py @@ -13,7 +13,6 @@ class SpellingCollector(EnvironmentCollector): - def clear_doc(self, app, env, docname) -> None: with contextlib.suppress(AttributeError, KeyError): del env.spelling_document_words[docname] @@ -24,7 +23,7 @@ def merge_other(self, app, env, docnames, other): except AttributeError: other_words = {} - if not hasattr(env, 'spelling_document_words'): + if not hasattr(env, "spelling_document_words"): env.spelling_document_words = collections.defaultdict(list) env.spelling_document_words.update(other_words) diff --git a/sphinxcontrib/spelling/builder.py b/sphinxcontrib/spelling/builder.py index 549834d..9c309ab 100644 --- a/sphinxcontrib/spelling/builder.py +++ b/sphinxcontrib/spelling/builder.py @@ -1,8 +1,7 @@ # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # -"""Spelling checker extension for Sphinx. -""" +"""Spelling checker extension for Sphinx.""" import collections import importlib @@ -35,18 +34,19 @@ class SpellingBuilder(Builder): """ Spell checks a document """ - name = 'spelling' + + name = "spelling" def init(self): if enchant_import_error is not None: raise RuntimeError( - 'Cannot initialize spelling builder ' - 'without PyEnchant installed') from enchant_import_error + "Cannot initialize spelling builder without PyEnchant installed" + ) from enchant_import_error self.misspelling_count = 0 self.env.settings["smart_quotes"] = False # Initialize the per-document filters - if not hasattr(self.env, 'spelling_document_words'): + if not hasattr(self.env, "spelling_document_words"): self.env.spelling_document_words = collections.defaultdict(list) # Initialize the global filters @@ -55,22 +55,22 @@ def init(self): EmailFilter, ] if self.config.spelling_ignore_wiki_words: - logger.info('Ignoring wiki words') + logger.info("Ignoring wiki words") f.append(WikiWordFilter) if self.config.spelling_ignore_acronyms: - logger.info('Ignoring acronyms') + logger.info("Ignoring acronyms") f.append(filters.AcronymFilter) if self.config.spelling_ignore_pypi_package_names: - logger.info('Adding package names from PyPI to local dictionary…') + logger.info("Adding package names from PyPI to local dictionary…") f.append(filters.PyPIFilterFactory()) if self.config.spelling_ignore_python_builtins: - logger.info('Ignoring Python builtins') + logger.info("Ignoring Python builtins") f.append(filters.PythonBuiltinsFilter) if self.config.spelling_ignore_importable_modules: - logger.info('Ignoring importable module names') + logger.info("Ignoring importable module names") f.append(filters.ImportableModuleFilter) if self.config.spelling_ignore_contributor_names: - logger.info('Ignoring contributor names') + logger.info("Ignoring contributor names") f.append(filters.ContributorFilter) f.extend(self._load_filter_classes(self.config.spelling_filters)) @@ -78,7 +78,7 @@ def init(self): os.mkdir(self.outdir) word_list = self.get_wordlist_filename() - logger.info('Looking for custom word list in %s', word_list) + logger.info("Looking for custom word list in %s", word_list) self.checker = checker.SpellingChecker( lang=self.config.spelling_lang, @@ -97,7 +97,7 @@ def _load_filter_classes(self, filters): if not isinstance(filter_, str): yield filter_ continue - module_name, _, class_name = filter_.rpartition('.') + module_name, _, class_name = filter_.rpartition(".") mod = importlib.import_module(module_name) yield getattr(mod, class_name) @@ -105,17 +105,14 @@ def get_configured_wordlist_filenames(self): "Returns the configured wordlist filenames." word_list = self.config.spelling_word_list_filename if word_list is None: - word_list = ['spelling_wordlist.txt'] + word_list = ["spelling_wordlist.txt"] if isinstance(word_list, str): # Wordlist is a string. Split on comma in case it came # from the command line, via -D, and has multiple values. - word_list = word_list.split(',') + word_list = word_list.split(",") - return [ - os.path.join(self.srcdir, p) - for p in word_list - ] + return [os.path.join(self.srcdir, p) for p in word_list] def get_wordlist_filename(self): "Returns the filename of the wordlist to use when checking content." @@ -131,33 +128,31 @@ def _build_combined_wordlist(self): # from the other lists. Otherwise, word_list is assumed to just be a # string. temp_dir = tempfile.mkdtemp() - combined_word_list = os.path.join(temp_dir, - 'spelling_wordlist.txt') + combined_word_list = os.path.join(temp_dir, "spelling_wordlist.txt") - with open(combined_word_list, 'w', encoding='UTF-8') as outfile: + with open(combined_word_list, "w", encoding="UTF-8") as outfile: for word_file in self.get_configured_wordlist_filenames(): # Paths are relative long_word_file = os.path.join(self.srcdir, word_file) - logger.info('Adding contents of %s to custom word list', - long_word_file) - with open(long_word_file, encoding='UTF-8') as infile: + logger.info("Adding contents of %s to custom word list", long_word_file) + with open(long_word_file, encoding="UTF-8") as infile: infile_contents = infile.readlines() outfile.writelines(infile_contents) # Check for newline, and add one if not present - if infile_contents and not infile_contents[-1].endswith('\n'): - outfile.write('\n') + if infile_contents and not infile_contents[-1].endswith("\n"): + outfile.write("\n") return combined_word_list def get_outdated_docs(self): - return 'all documents' + return "all documents" def prepare_writing(self, docnames): return def get_target_uri(self, docname, typ=None): - return '' + return "" def get_suggestions_to_show(self, suggestions): if not self.config.spelling_show_suggestions or not suggestions: @@ -174,31 +169,30 @@ def get_suggestions_to_show(self, suggestions): def format_suggestions(self, suggestions): to_show = self.get_suggestions_to_show(suggestions) if not to_show: - return '' - return '[' + ', '.join('"%s"' % s for s in to_show) + ']' + return "" + return "[" + ", ".join('"%s"' % s for s in to_show) + "]" TEXT_NODES = { - 'block_quote', - 'caption', - 'paragraph', - 'list_item', - 'term', - 'definition_list_item', - 'title', + "block_quote", + "caption", + "paragraph", + "list_item", + "term", + "definition_list_item", + "title", } def write_doc(self, docname, doctree): lines = list(self._find_misspellings(docname, doctree)) self.misspelling_count += len(lines) if lines: - output_filename = os.path.join(self.outdir, f'{docname}.spelling') - logger.info('Writing %s', output_filename) + output_filename = os.path.join(self.outdir, f"{docname}.spelling") + logger.info("Writing %s", output_filename) ensuredir(os.path.dirname(output_filename)) - with open(output_filename, 'w', encoding='UTF-8') as output: + with open(output_filename, "w", encoding="UTF-8") as output: output.writelines(lines) def _find_misspellings(self, docname, doctree): - excluded = Matcher(self.config.spelling_exclude_patterns) if excluded(self.env.doc2path(docname, None)): return @@ -210,16 +204,16 @@ def _find_misspellings(self, docname, doctree): doc_filters = [] good_words = self.env.spelling_document_words.get(docname) if good_words: - logger.debug('Extending local dictionary for %s', docname) + logger.debug("Extending local dictionary for %s", docname) doc_filters.append(filters.IgnoreWordsFilterFactory(good_words)) self.checker.push_filters(doc_filters) # Set up a filter for the types of nodes to ignore during # traversal. def filter(n): - if n.tagname != '#text': + if n.tagname != "#text": return False - if (n.parent and n.parent.tagname not in self.TEXT_NODES): + if n.parent and n.parent.tagname not in self.TEXT_NODES: return False # Nodes marked by the spelling:ignore role if hasattr(n, "spellingIgnore"): @@ -237,13 +231,7 @@ def filter(n): # Check the text of the node. misspellings = self.checker.check(node.astext()) - for ( - word, - suggestions, - context_line, - line_offset - ) in misspellings: - + for word, suggestions, context_line, line_offset in misspellings: # Avoid TypeError on nodes lacking a line number # This happens for some node originating from docstrings lineno = node_lineno @@ -251,20 +239,22 @@ def filter(n): lineno += line_offset msg_parts = [ - f'{source}:{lineno}: ', - 'Spell check', + f"{source}:{lineno}: ", + "Spell check", red(word), ] - if self.format_suggestions(suggestions) != '': + if self.format_suggestions(suggestions) != "": msg_parts.append(self.format_suggestions(suggestions)) msg_parts.append(context_line) - msg = ': '.join(msg_parts) + '.' + msg = ": ".join(msg_parts) + "." if self.config.spelling_warning: logger.warning(msg) elif self.config.spelling_verbose: logger.info(msg) yield "%s:%s: (%s) %s %s\n" % ( - source, lineno, word, + source, + lineno, + word, self.format_suggestions(suggestions), context_line, ) @@ -274,5 +264,4 @@ def filter(n): def finish(self): if self.misspelling_count: - logger.warning('Found %d misspelled words', - self.misspelling_count) + logger.warning("Found %d misspelled words", self.misspelling_count) diff --git a/sphinxcontrib/spelling/checker.py b/sphinxcontrib/spelling/checker.py index ddd0bd5..9d6cea7 100644 --- a/sphinxcontrib/spelling/checker.py +++ b/sphinxcontrib/spelling/checker.py @@ -1,8 +1,7 @@ # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # -"""Spelling checker extension for Sphinx. -""" +"""Spelling checker extension for Sphinx.""" try: import enchant @@ -20,12 +19,18 @@ class SpellingChecker: the checking and filtering behavior. """ - def __init__(self, lang, suggest, word_list_filename, - tokenizer_lang='en_US', filters=None, context_line=False): + def __init__( + self, + lang, + suggest, + word_list_filename, + tokenizer_lang="en_US", + filters=None, + context_line=False, + ): if enchant_import_error is not None: raise RuntimeError( - 'Cannot instantiate SpellingChecker ' - 'without PyEnchant installed', + "Cannot instantiate SpellingChecker without PyEnchant installed", ) from enchant_import_error if filters is None: filters = [] @@ -36,21 +41,18 @@ def __init__(self, lang, suggest, word_list_filename, self.context_line = context_line def push_filters(self, new_filters): - """Add a filter to the tokenizer chain. - """ + """Add a filter to the tokenizer chain.""" t = self.tokenizer for f in new_filters: t = f(t) self.tokenizer = t def pop_filters(self): - """Remove the filters pushed during the last call to push_filters(). - """ + """Remove the filters pushed during the last call to push_filters().""" self.tokenizer = self.original_tokenizer def check(self, text): - """Yields bad words and suggested alternate spellings. - """ + """Yields bad words and suggested alternate spellings.""" for word, pos in self.tokenizer(text): correct = self.dictionary.check(word) if correct: diff --git a/sphinxcontrib/spelling/directive.py b/sphinxcontrib/spelling/directive.py index 142f090..7d1a796 100644 --- a/sphinxcontrib/spelling/directive.py +++ b/sphinxcontrib/spelling/directive.py @@ -1,8 +1,7 @@ # # Copyright (c) 2010 Doug Hellmann. All rights reserved. # -"""Spelling checker extension for Sphinx. -""" +"""Spelling checker extension for Sphinx.""" import collections @@ -14,10 +13,9 @@ def add_good_words_to_document(env, docname, good_words): # Initialize the per-document good words list - if not hasattr(env, 'spelling_document_words'): + if not hasattr(env, "spelling_document_words"): env.spelling_document_words = collections.defaultdict(list) - logger.debug('Extending local dictionary for %s with %s', - env.docname, good_words) + logger.debug("Extending local dictionary for %s with %s", env.docname, good_words) env.spelling_document_words[env.docname].extend(good_words) @@ -48,8 +46,9 @@ def run(self): class LegacySpellingDirective(SpellingDirective): - def run(self): - logger.info('direct use of the spelling directive is deprecated, ' - 'replace ".. spelling::" with ".. spelling:word-list::"') + logger.info( + "direct use of the spelling directive is deprecated, " + 'replace ".. spelling::" with ".. spelling:word-list::"' + ) return super().run() diff --git a/sphinxcontrib/spelling/domain.py b/sphinxcontrib/spelling/domain.py index 866245e..c3fe994 100644 --- a/sphinxcontrib/spelling/domain.py +++ b/sphinxcontrib/spelling/domain.py @@ -4,26 +4,20 @@ class SpellingDomain(Domain): - - name = 'spelling' - label = 'Spelling Checker' + name = "spelling" + label = "Spelling Checker" directives = { - 'word-list': directive.SpellingDirective, - } - roles = { - 'word': role.spelling_word, - 'ignore': role.spelling_ignore + "word-list": directive.SpellingDirective, } + roles = {"word": role.spelling_word, "ignore": role.spelling_ignore} def get_objects(self): return [] - def resolve_xref(self, env, fromdocname, builder, typ, target, node, - contnode): + def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): return None - def resolve_any_xref(self, env, fromdocname, builder, target, node, - contnode): + def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode): return [] def merge_domaindata(self, docnames, otherdata): diff --git a/sphinxcontrib/spelling/role.py b/sphinxcontrib/spelling/role.py index c77ba92..5d0e162 100644 --- a/sphinxcontrib/spelling/role.py +++ b/sphinxcontrib/spelling/role.py @@ -3,8 +3,7 @@ from . import directive -def spelling_word(role, rawtext, text, lineno, inliner, - options={}, content=[]): +def spelling_word(role, rawtext, text, lineno, inliner, options={}, content=[]): """Let the user indicate that inline text is spelled correctly.""" env = inliner.document.settings.env docname = env.docname @@ -14,8 +13,7 @@ def spelling_word(role, rawtext, text, lineno, inliner, return [node], [] -def spelling_ignore(role, rawtext, text, lineno, inliner, - options={}, content=[]): +def spelling_ignore(role, rawtext, text, lineno, inliner, options={}, content=[]): """Let the user indicate that inline text is to not be spellchecked.""" node = nodes.Text(text) setattr(node, "spellingIgnore", True) diff --git a/tests/helpers.py b/tests/helpers.py index e4cf463..7f252f0 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -8,5 +8,5 @@ def require_git_repo(f): return pytest.mark.skipif( - not (pathlib.Path(os.getcwd()) / '.git').is_dir(), - reason='Not a git repo')(f) + not (pathlib.Path(os.getcwd()) / ".git").is_dir(), reason="Not a git repo" + )(f)