From 28e12c61332c6e97a9375144ccf85f5f5e4a730b Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 20:25:39 +0100 Subject: [PATCH 1/7] Enforce semantic line breaks with Snapper --- .github/workflows/semantic-line-breaks.yml | 29 ++++++++++++++++++++++ .snapperrc.toml | 7 ++++++ docs/source/ci-setup.rst | 3 +-- docs/source/contributing.rst | 9 +++---- docs/source/unreleased.rst | 4 +-- 5 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/semantic-line-breaks.yml create mode 100644 .snapperrc.toml diff --git a/.github/workflows/semantic-line-breaks.yml b/.github/workflows/semantic-line-breaks.yml new file mode 100644 index 000000000..16647cd2d --- /dev/null +++ b/.github/workflows/semantic-line-breaks.yml @@ -0,0 +1,29 @@ +name: Semantic line breaks + +on: + pull_request: + push: + branches: + - main + +permissions: {} + +jobs: + semantic-line-breaks: + name: Snapper + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 + - name: Check semantic line breaks + run: >- + git ls-files -z -- '*.md' '*.rst' ':(exclude)vendored/**' + | xargs -0 --no-run-if-empty + uvx + --from + 'git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1' + snapper --max-width 0 --check + diff --git a/.snapperrc.toml b/.snapperrc.toml new file mode 100644 index 000000000..53d7fbb56 --- /dev/null +++ b/.snapperrc.toml @@ -0,0 +1,7 @@ +# These files contain markup constructs that Snapper main does not yet preserve. +ignore = [ + "CHANGELOG.rst", + "docs/source/differences-to-vws.rst", + "docs/source/unverified-behavior.rst", +] + diff --git a/docs/source/ci-setup.rst b/docs/source/ci-setup.rst index e1b401bb7..d4d663010 100644 --- a/docs/source/ci-setup.rst +++ b/docs/source/ci-setup.rst @@ -24,8 +24,7 @@ Create environment variable files for secrets: $ cp vuforia_secrets.env.example ci_secrets/vuforia_secrets_1.env $ ... -Populate every variable listed in :file:`vuforia_secrets.env.example`. -Each file needs distinct active Cloud database credentials so concurrent jobs do not modify the same database. +Populate every variable listed in :file:`vuforia_secrets.env.example`. Each file needs distinct active Cloud database credentials so concurrent jobs do not modify the same database. The files can share the inactive Cloud, active and inactive VuMark, and Model Target credentials. Add at least as many consecutively numbered files, starting at zero, as there are builds in the GitHub test matrix. diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst index 885f62462..175fcb6f3 100644 --- a/docs/source/contributing.rst +++ b/docs/source/contributing.rst @@ -56,8 +56,7 @@ Create an environment variable file for secrets: $ cp vuforia_secrets.env.example vuforia_secrets.env Some tests require Vuforia credentials. -To run these tests, add the Vuforia credentials to the file :file:`vuforia_secrets.env`. -See :ref:`connecting-to-vuforia`. +To run these tests, add the Vuforia credentials to the file :file:`vuforia_secrets.env`. See :ref:`connecting-to-vuforia`. Then run ``pytest``: @@ -73,14 +72,12 @@ Connecting to Vuforia To connect to Vuforia, Vuforia target databases must be created via the Vuforia Web UI. Then, secret keys must be set as environment variables. -The test infrastructure allows those keys to be set in the file :file:`vuforia_secrets.env`. -See :file:`vuforia_secrets.env.example` for the environment variables to set. +The test infrastructure allows those keys to be set in the file :file:`vuforia_secrets.env`. See :file:`vuforia_secrets.env.example` for the environment variables to set. Do not use a target database that you are using for other purposes. This is because the test suite adds and deletes targets. -To create a target database, first create a license key in the `Vuforia License Manager`_. -Then, add a database from the `Vuforia Target Manager`_. +To create a target database, first create a license key in the `Vuforia License Manager`_. Then, add a database from the `Vuforia Target Manager`_. To find the environment variables to set in the :file:`vuforia_secrets.env` file, visit the Target Database in the `Vuforia Target Manager`_ and view the "Database Access Keys". diff --git a/docs/source/unreleased.rst b/docs/source/unreleased.rst index 22ac74723..d297d1976 100644 --- a/docs/source/unreleased.rst +++ b/docs/source/unreleased.rst @@ -1,8 +1,8 @@ Unreleased changes ================== -Changes that have landed on the main branch but are not yet part of a -tagged release. These entries are assembled into the +Changes that have landed on the main branch but are not yet part of a tagged release. +These entries are assembled into the :doc:`changelog` when the next release is published. .. towncrier-draft-entries:: From 7876811802cc9b67a73f2ac8ca5abb05e7e8b384 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 20:53:55 +0100 Subject: [PATCH 2/7] Run Snapper through Prek --- .github/workflows/semantic-line-breaks.yml | 29 ---------------------- prek.toml | 13 ++++++++++ pyproject.toml | 1 + uv.lock | 7 ++++++ 4 files changed, 21 insertions(+), 29 deletions(-) delete mode 100644 .github/workflows/semantic-line-breaks.yml diff --git a/.github/workflows/semantic-line-breaks.yml b/.github/workflows/semantic-line-breaks.yml deleted file mode 100644 index 16647cd2d..000000000 --- a/.github/workflows/semantic-line-breaks.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Semantic line breaks - -on: - pull_request: - push: - branches: - - main - -permissions: {} - -jobs: - semantic-line-breaks: - name: Snapper - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 - - name: Check semantic line breaks - run: >- - git ls-files -z -- '*.md' '*.rst' ':(exclude)vendored/**' - | xargs -0 --no-run-if-empty - uvx - --from - 'git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1' - snapper --max-width 0 --check - diff --git a/prek.toml b/prek.toml index a39e7de79..9f7c0bda7 100644 --- a/prek.toml +++ b/prek.toml @@ -407,6 +407,19 @@ hooks = [ additional_dependencies = ["uv==0.11.7"], stages = ["pre-commit"] }, + { + id = "snapper", + name = "snapper", + entry = "uv run --group=dev snapper --max-width 0 --in-place", + language = "python", + types_or = [ + "rst", + "markdown" + ], + require_serial = true, + additional_dependencies = ["uv==0.11.7"], + stages = ["pre-commit"] + }, { id = "vale", name = "vale", diff --git a/pyproject.toml b/pyproject.toml index 583e2f3ba..491cab39a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", + "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", diff --git a/uv.lock b/uv.lock index 7daf19bfa..75550f026 100644 --- a/uv.lock +++ b/uv.lock @@ -2129,6 +2129,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "snapper-fmt" +version = "0.11.0" +source = { git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1#bcd3458e27e4156ce4e0a0b55a227400328fb3b1" } + [[package]] name = "sniffio" version = "1.3.1" @@ -2860,6 +2865,7 @@ dev = [ { name = "ruff" }, { name = "shellcheck-py" }, { name = "shfmt-py" }, + { name = "snapper-fmt" }, { name = "sphinx" }, { name = "sphinx-copybutton" }, { name = "sphinx-lint" }, @@ -2951,6 +2957,7 @@ dev = [ { name = "ruff", specifier = "==0.16.6" }, { name = "shellcheck-py", specifier = "==0.11.0.1" }, { name = "shfmt-py", specifier = "==4.1.0" }, + { name = "snapper-fmt", git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1" }, { name = "sphinx", specifier = "==9.1.0" }, { name = "sphinx-copybutton", specifier = "==0.5.2" }, { name = "sphinx-lint", specifier = "==1.0.2" }, From de40552fc96f014844fb0fdbcf7f3c649f3ae872 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:05:47 +0100 Subject: [PATCH 3/7] Normalize Snapper configuration --- .snapperrc.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/.snapperrc.toml b/.snapperrc.toml index 53d7fbb56..1fe1477d4 100644 --- a/.snapperrc.toml +++ b/.snapperrc.toml @@ -4,4 +4,3 @@ ignore = [ "docs/source/differences-to-vws.rst", "docs/source/unverified-behavior.rst", ] - From be611d3486fa5fafdc9429573165aed5810410f9 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:15:48 +0100 Subject: [PATCH 4/7] Isolate the Snapper dependency group --- prek.toml | 2 +- pyproject.toml | 4 +++- uv.lock | 6 ++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/prek.toml b/prek.toml index 9f7c0bda7..da03e5a16 100644 --- a/prek.toml +++ b/prek.toml @@ -410,7 +410,7 @@ hooks = [ { id = "snapper", name = "snapper", - entry = "uv run --group=dev snapper --max-width 0 --in-place", + entry = "uv run --group=snapper snapper --max-width 0 --in-place", language = "python", types_or = [ "rst", diff --git a/pyproject.toml b/pyproject.toml index 491cab39a..89b017228 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,7 +99,6 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", - "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", @@ -130,6 +129,9 @@ dev = [ "zizmor==1.30.0", ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] +snapper = [ + "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", +] [tool.setuptools] packages.find.where = [ diff --git a/uv.lock b/uv.lock index 75550f026..4ca4f9269 100644 --- a/uv.lock +++ b/uv.lock @@ -2865,7 +2865,6 @@ dev = [ { name = "ruff" }, { name = "shellcheck-py" }, { name = "shfmt-py" }, - { name = "snapper-fmt" }, { name = "sphinx" }, { name = "sphinx-copybutton" }, { name = "sphinx-lint" }, @@ -2897,6 +2896,9 @@ release = [ { name = "check-wheel-contents" }, { name = "towncrier" }, ] +snapper = [ + { name = "snapper-fmt" }, +] [package.metadata] requires-dist = [ @@ -2957,7 +2959,6 @@ dev = [ { name = "ruff", specifier = "==0.16.6" }, { name = "shellcheck-py", specifier = "==0.11.0.1" }, { name = "shfmt-py", specifier = "==4.1.0" }, - { name = "snapper-fmt", git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1" }, { name = "sphinx", specifier = "==9.1.0" }, { name = "sphinx-copybutton", specifier = "==0.5.2" }, { name = "sphinx-lint", specifier = "==1.0.2" }, @@ -2989,6 +2990,7 @@ release = [ { name = "check-wheel-contents", specifier = "==0.6.3" }, { name = "towncrier", specifier = "==26.9.0" }, ] +snapper = [{ name = "snapper-fmt", git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1" }] [[package]] name = "vws-test-fixtures" From cfd49755c5113e3bff4395053ae33d20d84ea552 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:33:43 +0100 Subject: [PATCH 5/7] Enable Snapper Vale rules --- .vale.ini | 3 ++- styles/snapper/LongProseLine.yml | 11 +++++++++++ styles/snapper/SemanticLineBreaks.yml | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 styles/snapper/LongProseLine.yml create mode 100644 styles/snapper/SemanticLineBreaks.yml diff --git a/.vale.ini b/.vale.ini index 654ec3a10..cf374785e 100644 --- a/.vale.ini +++ b/.vale.ini @@ -4,7 +4,8 @@ MinAlertLevel = error Packages = https://github.com/tbhb/vale-ai-tells/releases/download/v1.29.0/ai-tells.zip [*.{rst,md}] -BasedOnStyles = ai-tells +BasedOnStyles = ai-tells, snapper +snapper.SemanticLineBreaks = error # These rules misclassify established technical, example, or release-note prose # in this repository. All other ai-tells rules remain enforced. diff --git a/styles/snapper/LongProseLine.yml b/styles/snapper/LongProseLine.yml new file mode 100644 index 000000000..1f5029f7d --- /dev/null +++ b/styles/snapper/LongProseLine.yml @@ -0,0 +1,11 @@ +--- +# Vale style rule: flag prose lines that are suspiciously long. +# Likely indicates wrapped text that should use semantic line breaks. +extends: existence +message: Prose line exceeds 120 characters. Consider running 'snapper' to break at + sentence boundaries. +level: suggestion +scope: paragraph +# This catches lines > 120 chars that contain a period followed by a space. +# Pure code or URLs are less likely to match. +tokens: ['.{120,}'] diff --git a/styles/snapper/SemanticLineBreaks.yml b/styles/snapper/SemanticLineBreaks.yml new file mode 100644 index 000000000..3f4edaf55 --- /dev/null +++ b/styles/snapper/SemanticLineBreaks.yml @@ -0,0 +1,11 @@ +--- +# Vale style rule: flag lines containing multiple sentences. +# These should be broken at sentence boundaries. +extends: existence +message: Line contains multiple sentences. Run 'snapper --check' or reformat with + 'snapper --in-place'. +level: warning +scope: paragraph +# Match a sentence-ending punctuation followed by a space and a capital letter +# on the same line (indicating two sentences on one line). +tokens: ['[.!?]\\s+[A-Z]'] From 348239de9214235f10caf023a1efdea9e6eeac35 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 21:57:20 +0100 Subject: [PATCH 6/7] Use the Snapper 0.11.0 release --- pyproject.toml | 2 +- uv.lock | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 89b017228..773e90a8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -130,7 +130,7 @@ dev = [ ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] snapper = [ - "snapper-fmt @ git+https://github.com/TurtleTech-ehf/snapper.git@bcd3458e27e4156ce4e0a0b55a227400328fb3b1", + "snapper-fmt==0.11.0", ] [tool.setuptools] diff --git a/uv.lock b/uv.lock index 4ca4f9269..ce97423e8 100644 --- a/uv.lock +++ b/uv.lock @@ -2132,7 +2132,15 @@ wheels = [ [[package]] name = "snapper-fmt" version = "0.11.0" -source = { git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1#bcd3458e27e4156ce4e0a0b55a227400328fb3b1" } +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/b7/22229f6fe3fd821fac544093acec7a56e4a31f194d174d266f4b74e03b75/snapper_fmt-0.11.0.tar.gz", hash = "sha256:43dd09debff923670e599422d100a5303db31ea12c96e2842832c37e54926ae1", size = 211613, upload-time = "2026-09-08T18:15:48.981Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/75/53d978f7ffc63e40a01d431dfb077ae6c457e1adebb37c3d32dbed42eb6e/snapper_fmt-0.11.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:aa760101012b9786b30bcd7ac5ffda2783beda0cfde7f98df725526130292f31", size = 16287991, upload-time = "2026-09-08T18:15:37.424Z" }, + { url = "https://files.pythonhosted.org/packages/5e/d1/7450839bd35e192f06a75079f6099095cc6118c09106e1fc71eb2661e91b/snapper_fmt-0.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:54f0c231258c69c5464f7dd4247c279f6df53b1e7bb1074d90466eb69d36bbc9", size = 15218993, upload-time = "2026-09-08T18:15:40.164Z" }, + { url = "https://files.pythonhosted.org/packages/82/f9/f495c45653e33047c9a6ade91b9145df1322db91129c7eee764ec645d373/snapper_fmt-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:802efad11aad7636e0abd16ae0fb84a75e5ecd2c3e8955b2fd22d25ef7574efd", size = 16945383, upload-time = "2026-09-08T18:15:42.158Z" }, + { url = "https://files.pythonhosted.org/packages/bb/59/74d0b2cfd7c93e219bfb03f40b312f32155503cbbfb82f87316ba78d018a/snapper_fmt-0.11.0-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:d7c55fe52dc33d88060586323bb49dee2b47c810f7f659da4e483553fe625678", size = 15558319, upload-time = "2026-09-08T18:15:44.404Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/ac99137b907c37d47e282e0a0e96f9d7f26bf7e4880cd2b66094bb011457/snapper_fmt-0.11.0-py3-none-win_amd64.whl", hash = "sha256:5e2ef4b5c6ecbff9449ba44c6b3057a2e54d290be1a0a180b1b0c7bf0a1ba3f5", size = 17704912, upload-time = "2026-09-08T18:15:46.981Z" }, +] [[package]] name = "sniffio" @@ -2990,7 +2998,7 @@ release = [ { name = "check-wheel-contents", specifier = "==0.6.3" }, { name = "towncrier", specifier = "==26.9.0" }, ] -snapper = [{ name = "snapper-fmt", git = "https://github.com/TurtleTech-ehf/snapper.git?rev=bcd3458e27e4156ce4e0a0b55a227400328fb3b1" }] +snapper = [{ name = "snapper-fmt", specifier = "==0.11.0" }] [[package]] name = "vws-test-fixtures" From 3ca6041294a06d2024f15e2a8e16723c659b19ea Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Tue, 8 Sep 2026 22:05:01 +0100 Subject: [PATCH 7/7] Use the development dependency group for Snapper --- prek.toml | 2 +- pyproject.toml | 4 +--- uv.lock | 6 ++---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/prek.toml b/prek.toml index da03e5a16..9f7c0bda7 100644 --- a/prek.toml +++ b/prek.toml @@ -410,7 +410,7 @@ hooks = [ { id = "snapper", name = "snapper", - entry = "uv run --group=snapper snapper --max-width 0 --in-place", + entry = "uv run --group=dev snapper --max-width 0 --in-place", language = "python", types_or = [ "rst", diff --git a/pyproject.toml b/pyproject.toml index 773e90a8e..bf282414d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ dev = [ # use it to lint shell commands in GitHub workflow files. "shellcheck-py==0.11.0.1", "shfmt-py==4.1.0", + "snapper-fmt==0.11.0", "sphinx==9.1.0", "sphinx-copybutton==0.5.2", "sphinx-lint==1.0.2", @@ -129,9 +130,6 @@ dev = [ "zizmor==1.30.0", ] release = [ "check-wheel-contents==0.6.3", "towncrier==26.9.0" ] -snapper = [ - "snapper-fmt==0.11.0", -] [tool.setuptools] packages.find.where = [ diff --git a/uv.lock b/uv.lock index ce97423e8..7c1a05924 100644 --- a/uv.lock +++ b/uv.lock @@ -2873,6 +2873,7 @@ dev = [ { name = "ruff" }, { name = "shellcheck-py" }, { name = "shfmt-py" }, + { name = "snapper-fmt" }, { name = "sphinx" }, { name = "sphinx-copybutton" }, { name = "sphinx-lint" }, @@ -2904,9 +2905,6 @@ release = [ { name = "check-wheel-contents" }, { name = "towncrier" }, ] -snapper = [ - { name = "snapper-fmt" }, -] [package.metadata] requires-dist = [ @@ -2967,6 +2965,7 @@ dev = [ { name = "ruff", specifier = "==0.16.6" }, { name = "shellcheck-py", specifier = "==0.11.0.1" }, { name = "shfmt-py", specifier = "==4.1.0" }, + { name = "snapper-fmt", specifier = "==0.11.0" }, { name = "sphinx", specifier = "==9.1.0" }, { name = "sphinx-copybutton", specifier = "==0.5.2" }, { name = "sphinx-lint", specifier = "==1.0.2" }, @@ -2998,7 +2997,6 @@ release = [ { name = "check-wheel-contents", specifier = "==0.6.3" }, { name = "towncrier", specifier = "==26.9.0" }, ] -snapper = [{ name = "snapper-fmt", specifier = "==0.11.0" }] [[package]] name = "vws-test-fixtures"