mkdocs-spellcheck 1.1.2__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/CHANGELOG.md +8 -0
  2. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/PKG-INFO +27 -4
  3. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/README.md +25 -1
  4. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/pytest.ini +2 -0
  5. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/duties.py +22 -46
  6. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/mkdocs.yml +1 -4
  7. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/pyproject.toml +2 -3
  8. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/scripts/make.py +32 -9
  9. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/words.py +22 -4
  10. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/tests/test_api.py +3 -1
  11. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/tests/test_words.py +37 -0
  12. mkdocs_spellcheck-1.1.2/docs/.overrides/main.html +0 -14
  13. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/CODE_OF_CONDUCT.md +0 -0
  14. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/CONTRIBUTING.md +0 -0
  15. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/LICENSE +0 -0
  16. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/coverage.ini +0 -0
  17. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/git-changelog.toml +0 -0
  18. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/mypy.ini +0 -0
  19. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/ruff.toml +0 -0
  20. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/vscode/launch.json +0 -0
  21. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/vscode/settings.json +0 -0
  22. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/config/vscode/tasks.json +0 -0
  23. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/.overrides/partials/comments.html +0 -0
  24. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/.overrides/partials/path-item.html +0 -0
  25. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/changelog.md +0 -0
  26. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/code_of_conduct.md +0 -0
  27. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/contributing.md +0 -0
  28. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/credits.md +0 -0
  29. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/css/material.css +0 -0
  30. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/css/mkdocstrings.css +0 -0
  31. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/index.md +0 -0
  32. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/js/feedback.js +0 -0
  33. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/known_words.txt +0 -0
  34. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/license.md +0 -0
  35. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/reference/api.md +0 -0
  36. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/docs/schema.json +0 -0
  37. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/scripts/gen_credits.py +0 -0
  38. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/scripts/get_version.py +0 -0
  39. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/scripts/make +0 -0
  40. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/__init__.py +0 -0
  41. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/__init__.py +0 -0
  42. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/backends/__init__.py +0 -0
  43. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/backends/codespell.py +0 -0
  44. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/backends/symspellpy.py +0 -0
  45. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/debug.py +0 -0
  46. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/_internal/plugin.py +0 -0
  47. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/backends/__init__.py +0 -0
  48. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/backends/codespell.py +0 -0
  49. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/backends/symspellpy.py +0 -0
  50. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/plugin.py +0 -0
  51. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/py.typed +0 -0
  52. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/src/mkdocs_spellcheck/words.py +0 -0
  53. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/tests/__init__.py +0 -0
  54. {mkdocs_spellcheck-1.1.2 → mkdocs_spellcheck-1.2.0}/tests/conftest.py +0 -0
@@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  <!-- insertion marker -->
8
+ ## [1.2.0](https://github.com/pawamoy/mkdocs-spellcheck/releases/tag/1.2.0) - 2025-12-01
9
+
10
+ <small>[Compare with 1.1.2](https://github.com/pawamoy/mkdocs-spellcheck/compare/1.1.2...1.2.0)</small>
11
+
12
+ ### Features
13
+
14
+ - Allow disabling spellcheck in specific regions thanks to HTML comments ([17e4ff3](https://github.com/pawamoy/mkdocs-spellcheck/commit/17e4ff307c9b9c71db8462b3d46463c02185235f) by Tobias Langer). [Issue #33](https://github.com/pawamoy/mkdocs-spellcheck/issues/33), [PR-34](https://github.com/pawamoy/mkdocs-spellcheck/pull/34)
15
+
8
16
  ## [1.1.2](https://github.com/pawamoy/mkdocs-spellcheck/releases/tag/1.1.2) - 2025-08-05
9
17
 
10
18
  <small>[Compare with 1.1.1](https://github.com/pawamoy/mkdocs-spellcheck/compare/1.1.1...1.1.2)</small>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs-spellcheck
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: A spell checker plugin for MkDocs.
5
5
  Author-Email: =?utf-8?q?Timoth=C3=A9e_Mazzucotelli?= <dev@pawamoy.fr>
6
6
  License-Expression: ISC
@@ -10,7 +10,6 @@ Classifier: Intended Audience :: Developers
10
10
  Classifier: Programming Language :: Python
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3 :: Only
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
@@ -29,7 +28,7 @@ Project-URL: Issues, https://github.com/pawamoy/mkdocs-spellcheck/issues
29
28
  Project-URL: Discussions, https://github.com/pawamoy/mkdocs-spellcheck/discussions
30
29
  Project-URL: Gitter, https://gitter.im/mkdocs-spellcheck/community
31
30
  Project-URL: Funding, https://github.com/sponsors/pawamoy
32
- Requires-Python: >=3.9
31
+ Requires-Python: >=3.10
33
32
  Requires-Dist: mkdocs>=1.5
34
33
  Provides-Extra: all
35
34
  Requires-Dist: mkdocs-spellcheck[codespell,symspellpy]; extra == "all"
@@ -42,10 +41,13 @@ Description-Content-Type: text/markdown
42
41
 
43
42
  # MkDocs SpellCheck
44
43
 
44
+ > [!WARNING]
45
+ > This project is in maintenance mode. I'm now dedicating my time to [Zensical](https://zensical.org/). Feel free to reach out for a responsible transfer of maintainership.
46
+
45
47
  [![ci](https://github.com/pawamoy/mkdocs-spellcheck/workflows/ci/badge.svg)](https://github.com/pawamoy/mkdocs-spellcheck/actions?query=workflow%3Aci)
46
48
  [![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://pawamoy.github.io/mkdocs-spellcheck/)
47
49
  [![pypi version](https://img.shields.io/pypi/v/mkdocs-spellcheck.svg)](https://pypi.org/project/mkdocs-spellcheck/)
48
- [![gitter](https://badges.gitter.im/join%20chat.svg)](https://app.gitter.im/#/room/#mkdocs-spellcheck:gitter.im)
50
+ [![gitter](https://img.shields.io/badge/matrix-chat-4DB798.svg?style=flat)](https://app.gitter.im/#/room/#mkdocs-spellcheck:gitter.im)
49
51
 
50
52
  A spell checker plugin for MkDocs.
51
53
 
@@ -120,3 +122,24 @@ The builtin dictionaries are:
120
122
  to be typos in other contexts (such as `uint`)
121
123
  - `names` for valid proper names that might be typos
122
124
  - `en-GB_to_en-US` for corrections from `en-GB` to `en-US`
125
+
126
+ ### On-off regions
127
+
128
+ In some situations it can be useful to temporarily disable spell checking for a document.
129
+ To this end, MkDocs SpellCheck recognizes special guards `mkdocs-spellcheck-{on,off}`:
130
+
131
+ ```md
132
+ Here MkDocs SpellCheck checks for correct spelling.
133
+
134
+ <!-- mkdocs-spellcheck-off -->
135
+ In this block it doesn't.
136
+ <!-- mkdocs-spellcheck-on -->
137
+
138
+ Here spelling checks are performed again.
139
+ ```
140
+
141
+ ## Sponsors
142
+
143
+ <!-- sponsors-start -->
144
+ <!-- sponsors-end -->
145
+
@@ -1,9 +1,12 @@
1
1
  # MkDocs SpellCheck
2
2
 
3
+ > [!WARNING]
4
+ > This project is in maintenance mode. I'm now dedicating my time to [Zensical](https://zensical.org/). Feel free to reach out for a responsible transfer of maintainership.
5
+
3
6
  [![ci](https://github.com/pawamoy/mkdocs-spellcheck/workflows/ci/badge.svg)](https://github.com/pawamoy/mkdocs-spellcheck/actions?query=workflow%3Aci)
4
7
  [![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://pawamoy.github.io/mkdocs-spellcheck/)
5
8
  [![pypi version](https://img.shields.io/pypi/v/mkdocs-spellcheck.svg)](https://pypi.org/project/mkdocs-spellcheck/)
6
- [![gitter](https://badges.gitter.im/join%20chat.svg)](https://app.gitter.im/#/room/#mkdocs-spellcheck:gitter.im)
9
+ [![gitter](https://img.shields.io/badge/matrix-chat-4DB798.svg?style=flat)](https://app.gitter.im/#/room/#mkdocs-spellcheck:gitter.im)
7
10
 
8
11
  A spell checker plugin for MkDocs.
9
12
 
@@ -78,3 +81,24 @@ The builtin dictionaries are:
78
81
  to be typos in other contexts (such as `uint`)
79
82
  - `names` for valid proper names that might be typos
80
83
  - `en-GB_to_en-US` for corrections from `en-GB` to `en-US`
84
+
85
+ ### On-off regions
86
+
87
+ In some situations it can be useful to temporarily disable spell checking for a document.
88
+ To this end, MkDocs SpellCheck recognizes special guards `mkdocs-spellcheck-{on,off}`:
89
+
90
+ ```md
91
+ Here MkDocs SpellCheck checks for correct spelling.
92
+
93
+ <!-- mkdocs-spellcheck-off -->
94
+ In this block it doesn't.
95
+ <!-- mkdocs-spellcheck-on -->
96
+
97
+ Here spelling checks are performed again.
98
+ ```
99
+
100
+ ## Sponsors
101
+
102
+ <!-- sponsors-start -->
103
+ <!-- sponsors-end -->
104
+
@@ -10,5 +10,7 @@ testpaths =
10
10
  # action:message_regex:warning_class:module_regex:line
11
11
  filterwarnings =
12
12
  error
13
+ default::EncodingWarning
14
+ error::EncodingWarning:mkdocs_spellcheck
13
15
  # TODO: remove once pytest-xdist 4 is released
14
16
  ignore:.*rsyncdir:DeprecationWarning:xdist
@@ -5,16 +5,12 @@ from __future__ import annotations
5
5
  import os
6
6
  import re
7
7
  import sys
8
- from contextlib import contextmanager
9
- from importlib.metadata import version as pkgversion
10
8
  from pathlib import Path
11
9
  from typing import TYPE_CHECKING
12
10
 
13
11
  from duty import duty, tools
14
12
 
15
13
  if TYPE_CHECKING:
16
- from collections.abc import Iterator
17
-
18
14
  from duty.context import Context
19
15
 
20
16
 
@@ -25,6 +21,8 @@ CI = os.environ.get("CI", "0") in {"1", "true", "yes", ""}
25
21
  WINDOWS = os.name == "nt"
26
22
  PTY = not WINDOWS and not CI
27
23
  MULTIRUN = os.environ.get("MULTIRUN", "0") == "1"
24
+ PY_VERSION = f"{sys.version_info.major}{sys.version_info.minor}"
25
+ PY_DEV = "314"
28
26
 
29
27
 
30
28
  def pyprefix(title: str) -> str:
@@ -34,18 +32,6 @@ def pyprefix(title: str) -> str:
34
32
  return title
35
33
 
36
34
 
37
- @contextmanager
38
- def material_insiders() -> Iterator[bool]:
39
- if "+insiders" in pkgversion("mkdocs-material"):
40
- os.environ["MATERIAL_INSIDERS"] = "true"
41
- try:
42
- yield True
43
- finally:
44
- os.environ.pop("MATERIAL_INSIDERS")
45
- else:
46
- yield False
47
-
48
-
49
35
  def _get_changelog_version() -> str:
50
36
  changelog_version_re = re.compile(r"^## \[(\d+\.\d+\.\d+)\].*$")
51
37
  with Path(__file__).parent.joinpath("CHANGELOG.md").open("r", encoding="utf8") as file:
@@ -68,7 +54,7 @@ def check(ctx: Context) -> None:
68
54
  """Check it all!"""
69
55
 
70
56
 
71
- @duty
57
+ @duty(nofail=PY_VERSION == PY_DEV)
72
58
  def check_quality(ctx: Context) -> None:
73
59
  """Check the code quality."""
74
60
  ctx.run(
@@ -77,19 +63,18 @@ def check_quality(ctx: Context) -> None:
77
63
  )
78
64
 
79
65
 
80
- @duty
66
+ @duty(nofail=PY_VERSION == PY_DEV)
81
67
  def check_docs(ctx: Context) -> None:
82
68
  """Check if the documentation builds correctly."""
83
69
  Path("htmlcov").mkdir(parents=True, exist_ok=True)
84
70
  Path("htmlcov/index.html").touch(exist_ok=True)
85
- with material_insiders():
86
- ctx.run(
87
- tools.mkdocs.build(strict=True, verbose=True),
88
- title=pyprefix("Building documentation"),
89
- )
71
+ ctx.run(
72
+ tools.mkdocs.build(strict=True, verbose=True),
73
+ title=pyprefix("Building documentation"),
74
+ )
90
75
 
91
76
 
92
- @duty
77
+ @duty(nofail=PY_VERSION == PY_DEV)
93
78
  def check_types(ctx: Context) -> None:
94
79
  """Check that the code is correctly typed."""
95
80
  os.environ["FORCE_COLOR"] = "1"
@@ -99,7 +84,7 @@ def check_types(ctx: Context) -> None:
99
84
  )
100
85
 
101
86
 
102
- @duty
87
+ @duty(nofail=PY_VERSION == PY_DEV)
103
88
  def check_api(ctx: Context, *cli_args: str) -> None:
104
89
  """Check for API breaking changes."""
105
90
  ctx.run(
@@ -117,22 +102,18 @@ def docs(ctx: Context, *cli_args: str, host: str = "127.0.0.1", port: int = 8000
117
102
  host: The host to serve the docs from.
118
103
  port: The port to serve the docs on.
119
104
  """
120
- with material_insiders():
121
- ctx.run(
122
- tools.mkdocs.serve(dev_addr=f"{host}:{port}").add_args(*cli_args),
123
- title="Serving documentation",
124
- capture=False,
125
- )
105
+ ctx.run(
106
+ tools.mkdocs.serve(dev_addr=f"{host}:{port}").add_args(*cli_args),
107
+ title="Serving documentation",
108
+ capture=False,
109
+ )
126
110
 
127
111
 
128
112
  @duty
129
113
  def docs_deploy(ctx: Context) -> None:
130
114
  """Deploy the documentation to GitHub pages."""
131
115
  os.environ["DEPLOY"] = "true"
132
- with material_insiders() as insiders:
133
- if not insiders:
134
- ctx.run(lambda: False, title="Not deploying docs without Material for MkDocs Insiders!")
135
- ctx.run(tools.mkdocs.gh_deploy(), title="Deploying documentation")
116
+ ctx.run(tools.mkdocs.gh_deploy(force=True), title="Deploying documentation")
136
117
 
137
118
 
138
119
  @duty
@@ -179,7 +160,7 @@ def release(ctx: Context, version: str = "") -> None:
179
160
  ctx.run("false", title="A version must be provided")
180
161
  ctx.run("git add pyproject.toml CHANGELOG.md", title="Staging files", pty=PTY)
181
162
  ctx.run(["git", "commit", "-m", f"chore: Prepare release {version}"], title="Committing changes", pty=PTY)
182
- ctx.run(f"git tag {version}", title="Tagging commit", pty=PTY)
163
+ ctx.run(f"git tag -m '' -a {version}", title="Tagging commit", pty=PTY)
183
164
  ctx.run("git push", title="Pushing commits", pty=False)
184
165
  ctx.run("git push --tags", title="Pushing tags", pty=False)
185
166
 
@@ -192,20 +173,15 @@ def coverage(ctx: Context) -> None:
192
173
  ctx.run(tools.coverage.html(rcfile="config/coverage.ini"))
193
174
 
194
175
 
195
- @duty
196
- def test(ctx: Context, *cli_args: str, match: str = "") -> None: # noqa: PT028
197
- """Run the test suite.
198
-
199
- Parameters:
200
- match: A pytest expression to filter selected tests.
201
- """
202
- py_version = f"{sys.version_info.major}{sys.version_info.minor}"
203
- os.environ["COVERAGE_FILE"] = f".coverage.{py_version}"
176
+ @duty(nofail=PY_VERSION == PY_DEV)
177
+ def test(ctx: Context, *cli_args: str) -> None:
178
+ """Run the test suite."""
179
+ os.environ["COVERAGE_FILE"] = f".coverage.{PY_VERSION}"
180
+ os.environ["PYTHONWARNDEFAULTENCODING"] = "1"
204
181
  ctx.run(
205
182
  tools.pytest(
206
183
  "tests",
207
184
  config_file="config/pytest.ini",
208
- select=match,
209
185
  color="yes",
210
186
  ).add_args("-n", "auto", *cli_args),
211
187
  title=pyprefix("Running tests"),
@@ -153,10 +153,7 @@ plugins:
153
153
  type: timeago
154
154
  - minify:
155
155
  minify_html: !ENV [DEPLOY, false]
156
- - group:
157
- enabled: !ENV [MATERIAL_INSIDERS, false]
158
- plugins:
159
- - typeset
156
+ - typeset
160
157
 
161
158
  extra:
162
159
  social:
@@ -15,7 +15,7 @@ license-files = [
15
15
  "LICENSE",
16
16
  ]
17
17
  readme = "README.md"
18
- requires-python = ">=3.9"
18
+ requires-python = ">=3.10"
19
19
  keywords = []
20
20
  dynamic = []
21
21
  classifiers = [
@@ -24,7 +24,6 @@ classifiers = [
24
24
  "Programming Language :: Python",
25
25
  "Programming Language :: Python :: 3",
26
26
  "Programming Language :: Python :: 3 :: Only",
27
- "Programming Language :: Python :: 3.9",
28
27
  "Programming Language :: Python :: 3.10",
29
28
  "Programming Language :: Python :: 3.11",
30
29
  "Programming Language :: Python :: 3.12",
@@ -39,7 +38,7 @@ classifiers = [
39
38
  dependencies = [
40
39
  "mkdocs>=1.5",
41
40
  ]
42
- version = "1.1.2"
41
+ version = "1.2.0"
43
42
 
44
43
  [project.optional-dependencies]
45
44
  all = [
@@ -14,7 +14,8 @@ if TYPE_CHECKING:
14
14
  from collections.abc import Iterator
15
15
 
16
16
 
17
- PYTHON_VERSIONS = os.getenv("PYTHON_VERSIONS", "3.9 3.10 3.11 3.12 3.13 3.14").split()
17
+ PYTHON_VERSIONS = os.getenv("PYTHON_VERSIONS", "3.10 3.11 3.12 3.13 3.14 3.15").split()
18
+ PYTHON_DEV = "3.15"
18
19
 
19
20
 
20
21
  def shell(cmd: str, *, capture_output: bool = False, **kwargs: Any) -> str | None:
@@ -67,16 +68,31 @@ def setup() -> None:
67
68
  uv_install(venv_path)
68
69
 
69
70
 
71
+ class _RunError(subprocess.CalledProcessError):
72
+ def __init__(self, *args: Any, python_version: str, **kwargs: Any):
73
+ super().__init__(*args, **kwargs)
74
+ self.python_version = python_version
75
+
76
+
70
77
  def run(version: str, cmd: str, *args: str, **kwargs: Any) -> None:
71
78
  """Run a command in a virtual environment."""
72
79
  kwargs = {"check": True, **kwargs}
73
80
  uv_run = ["uv", "run", "--no-sync"]
74
- if version == "default":
75
- with environ(UV_PROJECT_ENVIRONMENT=".venv"):
76
- subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510
77
- else:
78
- with environ(UV_PROJECT_ENVIRONMENT=f".venvs/{version}", MULTIRUN="1"):
79
- subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510
81
+ try:
82
+ if version == "default":
83
+ with environ(UV_PROJECT_ENVIRONMENT=".venv"):
84
+ subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510
85
+ else:
86
+ with environ(UV_PROJECT_ENVIRONMENT=f".venvs/{version}", MULTIRUN="1"):
87
+ subprocess.run([*uv_run, cmd, *args], **kwargs) # noqa: S603, PLW1510
88
+ except subprocess.CalledProcessError as process:
89
+ raise _RunError(
90
+ returncode=process.returncode,
91
+ python_version=version,
92
+ cmd=process.cmd,
93
+ output=process.output,
94
+ stderr=process.stderr,
95
+ ) from process
80
96
 
81
97
 
82
98
  def multirun(cmd: str, *args: str, **kwargs: Any) -> None:
@@ -195,7 +211,14 @@ def main() -> int:
195
211
  if __name__ == "__main__":
196
212
  try:
197
213
  sys.exit(main())
198
- except subprocess.CalledProcessError as process:
214
+ except _RunError as process:
199
215
  if process.output:
200
216
  print(process.output, file=sys.stderr)
201
- sys.exit(process.returncode)
217
+ if (code := process.returncode) == 139: # noqa: PLR2004
218
+ print(
219
+ f"✗ (python{process.python_version}) '{' '.join(process.cmd)}' failed with return code {code} (segfault)",
220
+ file=sys.stderr,
221
+ )
222
+ if process.python_version == PYTHON_DEV:
223
+ code = 0
224
+ sys.exit(code)
@@ -8,6 +8,9 @@ from functools import partial
8
8
  from html.parser import HTMLParser
9
9
  from io import StringIO
10
10
 
11
+ _spell_check_guard_on = "mkdocs-spellcheck-on"
12
+ _spell_check_guard_off = "mkdocs-spellcheck-off"
13
+
11
14
 
12
15
  class _MLStripper(HTMLParser):
13
16
  def __init__(self, ignore_code: bool = True) -> None: # noqa: FBT001,FBT002
@@ -18,6 +21,7 @@ class _MLStripper(HTMLParser):
18
21
  self.text = StringIO()
19
22
  self.ignore_code = ignore_code
20
23
  self.in_code_tag = False
24
+ self.in_guard = False
21
25
 
22
26
  def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: # noqa: ARG002
23
27
  if tag == "code":
@@ -28,15 +32,29 @@ class _MLStripper(HTMLParser):
28
32
  if tag == "code":
29
33
  self.in_code_tag = False
30
34
 
35
+ def handle_comment(self, data: str) -> None:
36
+ data = data.strip()
37
+
38
+ if not self.in_code_tag:
39
+ if data == _spell_check_guard_off:
40
+ self.in_guard = True
41
+ elif data == _spell_check_guard_on:
42
+ self.in_guard = False
43
+
31
44
  def handle_data(self, data: str) -> None:
32
- if not (self.ignore_code and self.in_code_tag):
33
- self.text.write(data)
45
+ if self.ignore_code and self.in_code_tag:
46
+ return
47
+
48
+ if self.in_guard:
49
+ return
50
+
51
+ self.text.write(data)
34
52
 
35
53
  def get_data(self) -> str:
36
54
  return self.text.getvalue()
37
55
 
38
56
 
39
- def _strip_tags(html: str, ignore_code: bool) -> str: # noqa: FBT001
57
+ def _strip(html: str, ignore_code: bool) -> str: # noqa: FBT001
40
58
  stripper = _MLStripper(ignore_code)
41
59
  stripper.feed(html)
42
60
  return stripper.get_data()
@@ -94,6 +112,6 @@ def get_words(
94
112
  """
95
113
  known_words = known_words or set()
96
114
  keep = partial(_keep_word, min_length=min_length, max_capital=max_capital)
97
- filtered = filter(keep, _normalize(_strip_tags(html, ignore_code), allow_unicode).split("-"))
115
+ filtered = filter(keep, _normalize(_strip(html, ignore_code), allow_unicode).split("-"))
98
116
  words = {word.lower() for word in filtered}
99
117
  return sorted(words - known_words)
@@ -137,7 +137,9 @@ def test_api_matches_inventory(inventory: Inventory, public_objects: list[griffe
137
137
  """All public objects are added to the inventory."""
138
138
  ignore_names = {"__getattr__", "__init__", "__repr__", "__str__", "__post_init__"}
139
139
  not_in_inventory = [
140
- obj.path for obj in public_objects if obj.name not in ignore_names and obj.path not in inventory
140
+ f"{obj.relative_filepath}:{obj.lineno}: {obj.path}"
141
+ for obj in public_objects
142
+ if obj.name not in ignore_names and obj.path not in inventory
141
143
  ]
142
144
  msg = "Objects not in the inventory (try running `make run mkdocs build`):\n{paths}"
143
145
  assert not not_in_inventory, msg.format(paths="\n".join(sorted(not_in_inventory)))
@@ -27,6 +27,43 @@ def test_remove_single_tags() -> None:
27
27
  assert "img" not in words
28
28
 
29
29
 
30
+ def test_remove_guarded_blocks() -> None:
31
+ """Assert guarded text blocks are removed from HTML text."""
32
+ html = """\
33
+ before
34
+ <!-- mkdocs-spellcheck-off -->
35
+ between
36
+ <!-- mkdocs-spellcheck-on -->
37
+ after
38
+ """
39
+ words = get_words(html, min_length=1)
40
+ assert "before" in words
41
+ assert "between" not in words
42
+ assert "after" in words
43
+
44
+
45
+ @pytest.mark.parametrize(
46
+ ("ignore_code", "expected"),
47
+ [
48
+ (True, {"before", "after"}),
49
+ (False, {"before", "some", "guarded", "text", "after"}),
50
+ ],
51
+ )
52
+ def test_guarded_blocks_disabled_in_code_blocks(ignore_code: bool, expected: set[str]) -> None:
53
+ """Assert guarded blocks are disabled in code blocks."""
54
+ html = """\
55
+ before
56
+ <code>
57
+ <!-- mkdocs-spellcheck-off -->
58
+ some guarded text
59
+ <!-- mkdocs-spellcheck-on -->
60
+ </code>
61
+ after
62
+ """
63
+ words = get_words(html, ignore_code=ignore_code)
64
+ assert set(words) == expected
65
+
66
+
30
67
  @pytest.mark.parametrize(
31
68
  ("text", "known_words", "expected"),
32
69
  [
@@ -1,14 +0,0 @@
1
- {% extends "base.html" %}
2
-
3
- {% block announce %}
4
-
5
- Follow
6
- <strong>@pawamoy</strong> on
7
- <a rel="me" href="https://fosstodon.org/@pawamoy">
8
- <span class="twemoji mastodon">
9
- {% include ".icons/fontawesome/brands/mastodon.svg" %}
10
- </span>
11
- <strong>Fosstodon</strong>
12
- </a>
13
- for updates
14
- {% endblock %}