diff --git a/.gitignore b/.gitignore index 2149e79f..f698e90d 100644 --- a/.gitignore +++ b/.gitignore @@ -112,3 +112,6 @@ src/*/_setuptools_scm_version.py # Nix result + +# Vale styles downloaded by ``vale sync`` +styles/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7a35ad16..fdc9b955 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -309,6 +309,36 @@ repos: - *uv_version stages: [pre-commit] + # Vale enforces prose style rules, such as banning em dashes, in + # reStructuredText files. + # The rules come from the ``ClearProse`` package pinned in ``.vale.ini``, + # which ``vale sync`` downloads into the (gitignored) ``styles`` + # directory. + # Vale needs ``rst2html`` from Docutils on the ``PATH`` to parse + # reStructuredText. + # ``vale sync`` also runs when ``.vale.ini`` changes, so a package + # bump takes effect without waiting for the next reStructuredText + # change. + - id: vale-sync + name: vale sync + entry: uv run --extra=dev vale sync + language: python + pass_filenames: false + files: (\.rst$|^\.vale\.ini$) + additional_dependencies: + - *uv_version + stages: [pre-commit] + + - id: vale + name: vale + entry: uv run --extra=dev vale + language: python + types_or: [rst] + require_serial: true + additional_dependencies: + - *uv_version + stages: [pre-commit] + - id: doc8 name: doc8 entry: uv run --extra=dev -m doc8 diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 00000000..8e3f9f74 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,7 @@ +StylesPath = styles +MinAlertLevel = error + +Packages = https://github.com/adamtheturtle/vale-style-clear-prose/releases/download/v1.1.0/ClearProse.zip + +[*.rst] +BasedOnStyles = ClearProse diff --git a/pyproject.toml b/pyproject.toml index 5ee826d3..0f4e9d5e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,6 +88,7 @@ optional-dependencies.dev = [ "towncrier==25.8.0", "ty==0.0.65", "types-pyyaml==6.0.12.20260724", + "vale==3.13.0.0", "vulture==2.16", "vws-python-mock==2026.2.22.3", "vws-test-fixtures==2023.3.5", @@ -297,6 +298,7 @@ ignore = [ ".git_archival.txt", ".pre-commit-config.yaml", ".prettierrc", + ".vale.ini", ".yamlfmt", "bin", "bin/*", diff --git a/uv.lock b/uv.lock index 291d9ee8..658c9048 100644 --- a/uv.lock +++ b/uv.lock @@ -2410,6 +2410,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, ] +[[package]] +name = "vale" +version = "3.13.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/0d/6ebd7d020135888cc4d35290737871986ceabf176ba5e44827294429283a/vale-3.13.0.0.tar.gz", hash = "sha256:9c2482ecab515e58aa8d7e1a09f3d44ed674a07502786e22ff60c9d4fdc8493b", size = 5340, upload-time = "2025-10-28T13:20:41.459Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/05/92b9e4d3e3cb424d2a1aa6e070ee838f15f6739a90b06964156a24fe49ce/vale-3.13.0.0-py3-none-any.whl", hash = "sha256:b565197a5f6e430af7ccc59204e75c6067bbd091a0073d700efdd0fba21873ed", size = 5944, upload-time = "2025-10-28T13:20:40.35Z" }, +] + [[package]] name = "vcs-versioning" version = "2.1.2" @@ -2496,6 +2505,7 @@ dev = [ { name = "towncrier" }, { name = "ty" }, { name = "types-pyyaml" }, + { name = "vale" }, { name = "vulture" }, { name = "vws-python-mock" }, { name = "vws-test-fixtures" }, @@ -2558,6 +2568,7 @@ requires-dist = [ { name = "towncrier", marker = "extra == 'release'", specifier = "==25.8.0" }, { name = "ty", marker = "extra == 'dev'", specifier = "==0.0.65" }, { name = "types-pyyaml", marker = "extra == 'dev'", specifier = "==6.0.12.20260724" }, + { name = "vale", marker = "extra == 'dev'", specifier = "==3.13.0.0" }, { name = "vulture", marker = "extra == 'dev'", specifier = "==2.16" }, { name = "vws-python", specifier = "==2026.2.25.1" }, { name = "vws-python-mock", marker = "extra == 'dev'", specifier = "==2026.2.22.3" },