diff --git a/.snapperrc.toml b/.snapperrc.toml new file mode 100644 index 000000000..1fe1477d4 --- /dev/null +++ b/.snapperrc.toml @@ -0,0 +1,6 @@ +# 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/.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/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:: 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..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", 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]'] diff --git a/uv.lock b/uv.lock index 7daf19bfa..7c1a05924 100644 --- a/uv.lock +++ b/uv.lock @@ -2129,6 +2129,19 @@ 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 = { 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" version = "1.3.1" @@ -2860,6 +2873,7 @@ dev = [ { name = "ruff" }, { name = "shellcheck-py" }, { name = "shfmt-py" }, + { name = "snapper-fmt" }, { name = "sphinx" }, { name = "sphinx-copybutton" }, { name = "sphinx-lint" }, @@ -2951,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" },