From 87794eb73cfacd4e49af38c2e95077ba06dfd1e2 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 11:21:39 +0000 Subject: [PATCH 1/2] Replace docformatter with pydocstringformatter - Replace docformatter==1.7.7 with pydocstringformatter==0.7.3 - Replace [tool.docformatter] with [tool.pydocstringformatter] config - Update ruff ignore comments (D200 -> D205/D212) - Don't use linewrap-full-docstring to avoid breaking URLs (https://github.com/DanielNoord/pydocstringformatter/issues/540) --- pyproject.toml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 53ee7714..8165765b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ optional-dependencies.dev = [ "deptry==0.24.0", "doc8==2.0.0", "doccmd==2026.1.23.4", - "docformatter==1.7.7", "freezegun==1.5.5", "furo==2025.12.19", "hadolint-bin==2.14.0; sys_platform!='win32'", @@ -50,6 +49,7 @@ optional-dependencies.dev = [ "mypy[faster-cache]==1.19.1", "mypy-strict-kwargs==2026.1.12", "prek==0.3.0", + "pydocstringformatter==0.7.3", "pylint[spelling]==4.0.4", "pyproject-fmt==2.11.1", "pyrefly==0.49.0", @@ -118,8 +118,8 @@ lint.select = [ lint.ignore = [ # Ruff warns that this conflicts with the formatter. "COM812", - # Allow our chosen docstring line-style - no one-line summary. - "D200", + # Allow our chosen docstring line-style - pydocstringformatter handles formatting + # but doesn't enforce D205 (blank line after summary) or D212 (summary on first line). "D205", "D212", # Allow backslashes in a docstring. @@ -260,9 +260,6 @@ spelling-private-dict-file = 'spelling_private_dict.txt' # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words = 'no' -[tool.docformatter] -make-summary-multi-line = true - [tool.check-manifest] ignore = [ @@ -340,6 +337,12 @@ enableTypeIgnoreComments = false reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" +[tool.pydocstringformatter] +write = true +split-summary-body = false +max-line-length = 75 +linewrap-full-docstring = true + [tool.interrogate] fail-under = 100 omit-covered-files = true From 91e432bc60bb32598dd1be36f2bd0d0ad278dfce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:32:50 +0000 Subject: [PATCH 2/2] [pre-commit.ci lite] apply automatic fixes --- .pre-commit-config.yaml | 8 +-- bin/vuforia-cloud-reco.py | 4 +- bin/vuforia-web-services.py | 4 +- docs/source/__init__.py | 4 +- docs/source/conf.py | 4 +- pyproject.toml | 8 +++ src/vws_cli/__init__.py | 8 +-- src/vws_cli/commands.py | 4 +- src/vws_cli/options/__init__.py | 4 +- src/vws_cli/options/credentials.py | 20 ++---- src/vws_cli/options/targets.py | 24 ++----- src/vws_cli/query.py | 12 +--- tests/__init__.py | 4 +- tests/conftest.py | 19 ++---- tests/test_cli.py | 8 +-- tests/test_help.py | 4 +- tests/test_query.py | 69 ++++++++----------- tests/test_query_errors.py | 18 ++--- tests/test_vws_commands.py | 103 +++++++++++------------------ tests/test_vws_errors.py | 43 ++++++------ uv.lock | 32 +++------ 21 files changed, 149 insertions(+), 255 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d5fc07cd..3fe643b8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,7 +10,7 @@ ci: - check-manifest - deptry - doc8 - - docformatter + - pydocstringformatter - docs - interrogate - interrogate-docs @@ -128,9 +128,9 @@ repos: additional_dependencies: [uv==0.9.5] stages: [pre-commit] - - id: docformatter - name: docformatter - entry: uv run --extra=dev -m docformatter --in-place + - id: pydocstringformatter + name: pydocstringformatter + entry: uv run --extra=dev pydocstringformatter language: python types_or: [python] # We exclude this file to avoid https://github.com/PyCQA/docformatter/issues/291. diff --git a/bin/vuforia-cloud-reco.py b/bin/vuforia-cloud-reco.py index 55438101..22d5bce7 100755 --- a/bin/vuforia-cloud-reco.py +++ b/bin/vuforia-cloud-reco.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 -""" -Run VWS Cloud Reco CLI. -""" +"""Run VWS Cloud Reco CLI.""" from vws_cli.query import vuforia_cloud_reco diff --git a/bin/vuforia-web-services.py b/bin/vuforia-web-services.py index 90d42003..fc86cecc 100755 --- a/bin/vuforia-web-services.py +++ b/bin/vuforia-web-services.py @@ -1,8 +1,6 @@ #!/usr/bin/env python3 -""" -Run VWS CLI. -""" +"""Run VWS CLI.""" from vws_cli import vws_group diff --git a/docs/source/__init__.py b/docs/source/__init__.py index b63eed5f..535ceb2e 100644 --- a/docs/source/__init__.py +++ b/docs/source/__init__.py @@ -1,3 +1 @@ -""" -Documentation. -""" +"""Documentation.""" diff --git a/docs/source/conf.py b/docs/source/conf.py index c1c049f2..6140c8f5 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -""" -Configuration for Sphinx. -""" +"""Configuration for Sphinx.""" # pylint: disable=invalid-name diff --git a/pyproject.toml b/pyproject.toml index 8165765b..b569c40d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,6 +136,14 @@ lint.ignore = [ "S101", ] +lint.per-file-ignores."doccmd_*.py" = [ + # Allow our chosen docstring line-style - pydocstringformatter handles + # formatting but docstrings in docs may not match this style. + "D200", + # Allow asserts in docs. + "S101", +] + lint.per-file-ignores."tests/test_*.py" = [ # Do not require tests to have a one-line summary. "D205", diff --git a/src/vws_cli/__init__.py b/src/vws_cli/__init__.py index b62566c0..7837a425 100644 --- a/src/vws_cli/__init__.py +++ b/src/vws_cli/__init__.py @@ -1,6 +1,4 @@ -""" -A CLI for Vuforia Web Services. -""" +"""A CLI for Vuforia Web Services.""" from importlib.metadata import PackageNotFoundError, version @@ -38,9 +36,7 @@ @click.version_option(version=__version__) @beartype def vws_group() -> None: - """ - Manage a Vuforia Web Services cloud database. - """ + """Manage a Vuforia Web Services cloud database.""" vws_group.add_command(cmd=add_target) diff --git a/src/vws_cli/commands.py b/src/vws_cli/commands.py index 3b8c82a1..03ad3150 100644 --- a/src/vws_cli/commands.py +++ b/src/vws_cli/commands.py @@ -456,7 +456,9 @@ def wait_for_target_processed( base_vws_url: str, timeout_seconds: float, ) -> None: - """Wait for a target to be "processed". This is done by polling the VWS API.""" + """Wait for a target to be "processed". This is done by polling the VWS + API. + """ vws_client = VWS( server_access_key=server_access_key, server_secret_key=server_secret_key, diff --git a/src/vws_cli/options/__init__.py b/src/vws_cli/options/__init__.py index e001e2d2..834d6fb5 100644 --- a/src/vws_cli/options/__init__.py +++ b/src/vws_cli/options/__init__.py @@ -1,3 +1 @@ -""" -Options for the VWS CLI commands. -""" +"""Options for the VWS CLI commands.""" diff --git a/src/vws_cli/options/credentials.py b/src/vws_cli/options/credentials.py index a9d8a60a..353c7c8f 100644 --- a/src/vws_cli/options/credentials.py +++ b/src/vws_cli/options/credentials.py @@ -1,6 +1,4 @@ -""" -``click`` options regarding credentials. -""" +"""``click`` options regarding credentials.""" from collections.abc import Callable from typing import Any @@ -13,9 +11,7 @@ def server_access_key_option( command: Callable[..., Any], ) -> Callable[..., Any]: - """ - An option decorator for the Vuforia server access key. - """ + """An option decorator for the Vuforia server access key.""" return click.option( "--server-access-key", type=str, @@ -33,9 +29,7 @@ def server_access_key_option( def server_secret_key_option( command: Callable[..., Any], ) -> Callable[..., Any]: - """ - An option decorator for the Vuforia server secret key. - """ + """An option decorator for the Vuforia server secret key.""" return click.option( "--server-secret-key", type=str, @@ -53,9 +47,7 @@ def server_secret_key_option( def client_access_key_option( command: Callable[..., Any], ) -> Callable[..., Any]: - """ - An option decorator for the Vuforia client access key. - """ + """An option decorator for the Vuforia client access key.""" return click.option( "--client-access-key", type=str, @@ -73,9 +65,7 @@ def client_access_key_option( def client_secret_key_option( command: Callable[..., Any], ) -> Callable[..., Any]: - """ - An option decorator for the Vuforia client secret key. - """ + """An option decorator for the Vuforia client secret key.""" return click.option( "--client-secret-key", type=str, diff --git a/src/vws_cli/options/targets.py b/src/vws_cli/options/targets.py index e2c80622..aeb9be60 100644 --- a/src/vws_cli/options/targets.py +++ b/src/vws_cli/options/targets.py @@ -1,6 +1,4 @@ -""" -``click`` options regarding targets. -""" +"""``click`` options regarding targets.""" from collections.abc import Callable from enum import Enum, unique @@ -20,9 +18,7 @@ @beartype def target_name_option(*, required: bool) -> Callable[..., Any]: - """ - An option decorator for choosing a target name. - """ + """An option decorator for choosing a target name.""" return click.option( "--name", type=str, @@ -33,9 +29,7 @@ def target_name_option(*, required: bool) -> Callable[..., Any]: @beartype def target_width_option(*, required: bool) -> Callable[..., Any]: - """ - An option decorator for choosing a target width. - """ + """An option decorator for choosing a target width.""" option: Callable[..., Any] = click.option( "--width", type=float, @@ -47,9 +41,7 @@ def target_width_option(*, required: bool) -> Callable[..., Any]: @beartype def target_image_option(*, required: bool) -> Callable[..., Any]: - """ - An option decorator for choosing a target image. - """ + """An option decorator for choosing a target image.""" return click.option( "--image", "image_file_path", @@ -66,9 +58,7 @@ def target_image_option(*, required: bool) -> Callable[..., Any]: @unique class ActiveFlagChoice(Enum): - """ - Choices for active flag. - """ + """Choices for active flag.""" TRUE = "true" FALSE = "false" @@ -78,9 +68,7 @@ def active_flag_option( *, allow_none: bool, ) -> Callable[..., Any]: - """ - An option decorator for setting a target's active flag. - """ + """An option decorator for setting a target's active flag.""" if allow_none: default = None show_default = False diff --git a/src/vws_cli/query.py b/src/vws_cli/query.py index 37607345..409d3f63 100644 --- a/src/vws_cli/query.py +++ b/src/vws_cli/query.py @@ -1,6 +1,4 @@ -""" -A CLI for the Vuforia Cloud Recognition Service API. -""" +"""A CLI for the Vuforia Cloud Recognition Service API.""" import contextlib import dataclasses @@ -34,9 +32,7 @@ @beartype @contextlib.contextmanager def _handle_vwq_exceptions() -> Iterator[None]: - """ - Show error messages and catch exceptions from ``VWS-Python``. - """ + """Show error messages and catch exceptions from ``VWS-Python``.""" try: yield except BadImageError: @@ -136,9 +132,7 @@ def vuforia_cloud_reco( include_target_data: CloudRecoIncludeTargetData, base_vwq_url: str, ) -> None: - """ - Make a request to the Vuforia Cloud Recognition Service API. - """ + """Make a request to the Vuforia Cloud Recognition Service API.""" client = CloudRecoService( client_access_key=client_access_key, client_secret_key=client_secret_key, diff --git a/tests/__init__.py b/tests/__init__.py index 76356810..fb30f6f7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1 @@ -""" -Tests for the VWS CLI. -""" +"""Tests for the VWS CLI.""" diff --git a/tests/conftest.py b/tests/conftest.py index 080c3d12..b11ab73b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,4 @@ -""" -``pytest`` fixtures. -""" +"""``pytest`` fixtures.""" from collections.abc import Iterator @@ -13,9 +11,7 @@ @beartype def pytest_collection_modifyitems(items: list[pytest.Item]) -> None: - """ - Apply the beartype decorator to all collected test functions. - """ + """Apply the beartype decorator to all collected test functions.""" for item in items: assert isinstance(item, pytest.Function) item.obj = beartype(obj=item.obj) @@ -23,9 +19,7 @@ def pytest_collection_modifyitems(items: list[pytest.Item]) -> None: @pytest.fixture(name="mock_database") def fixture_mock_database() -> Iterator[VuforiaDatabase]: - """ - Yield a mock ``VuforiaDatabase``. - """ + """Yield a mock ``VuforiaDatabase``.""" with MockVWS() as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -34,9 +28,7 @@ def fixture_mock_database() -> Iterator[VuforiaDatabase]: @pytest.fixture def vws_client(mock_database: VuforiaDatabase) -> VWS: - """ - Return a VWS client which connects to a mock database. - """ + """Return a VWS client which connects to a mock database.""" return VWS( server_access_key=mock_database.server_access_key, server_secret_key=mock_database.server_secret_key, @@ -48,7 +40,8 @@ def cloud_reco_client( mock_database: VuforiaDatabase, ) -> CloudRecoService: """ - Return a ``CloudRecoService`` client which connects to a mock database. + Return a ``CloudRecoService`` client which connects to a mock + database. """ return CloudRecoService( client_access_key=mock_database.client_access_key, diff --git a/tests/test_cli.py b/tests/test_cli.py index f830dd46..a8d726d6 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,6 +1,4 @@ -""" -Tests for the VWS CLI. -""" +"""Tests for the VWS CLI.""" from click.testing import CliRunner @@ -8,9 +6,7 @@ def test_version() -> None: - """ - The CLI version is shown with ``vws --version``. - """ + """The CLI version is shown with ``vws --version``.""" runner = CliRunner() result = runner.invoke( cli=vws_group, diff --git a/tests/test_help.py b/tests/test_help.py index 9d782a01..0ec1fb07 100644 --- a/tests/test_help.py +++ b/tests/test_help.py @@ -1,6 +1,4 @@ -""" -Tests for the VWS CLI help. -""" +"""Tests for the VWS CLI help.""" import pytest from click.testing import CliRunner diff --git a/tests/test_query.py b/tests/test_query.py index 9b09e559..0ebd57ef 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -1,6 +1,4 @@ -""" -Test for the Cloud Reco Service commands. -""" +"""Test for the Cloud Reco Service commands.""" import io import uuid @@ -17,9 +15,7 @@ class TestQuery: - """ - Tests for making image queries. - """ + """Tests for making image queries.""" @staticmethod def test_no_matches( @@ -27,9 +23,7 @@ def test_no_matches( tmp_path: Path, high_quality_image: io.BytesIO, ) -> None: - """ - An empty list is returned if there are no matches. - """ + """An empty list is returned if there are no matches.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex image_data = high_quality_image.getvalue() @@ -58,9 +52,7 @@ def test_matches( vws_client: VWS, mock_database: VuforiaDatabase, ) -> None: - """ - Details of matching targets are shown. - """ + """Details of matching targets are shown.""" name = uuid.uuid4().hex target_id = vws_client.add_target( name=name, @@ -108,7 +100,8 @@ def test_image_file_is_dir( mock_database: VuforiaDatabase, ) -> None: """ - An appropriate error is given if the given image file path points to a + An appropriate error is given if the given image file path + points to a directory. """ runner = CliRunner() @@ -144,9 +137,7 @@ def test_relative_path( mock_database: VuforiaDatabase, high_quality_image: io.BytesIO, ) -> None: - """ - Image file paths are resolved. - """ + """Image file paths are resolved.""" runner = CliRunner() new_filename = uuid.uuid4().hex original_image_file = tmp_path / "foo" @@ -179,7 +170,8 @@ def test_image_file_does_not_exist( tmp_path: Path, ) -> None: """ - An appropriate error is given if the given image file does not exist. + An appropriate error is given if the given image file does not + exist. """ runner = CliRunner() does_not_exist_file = tmp_path / uuid.uuid4().hex @@ -211,9 +203,7 @@ def test_image_file_does_not_exist( def test_version() -> None: - """ - ``vuforia-cloud-reco --version`` shows the version. - """ + """``vuforia-cloud-reco --version`` shows the version.""" runner = CliRunner() commands = ["--version"] result = runner.invoke( @@ -227,9 +217,7 @@ def test_version() -> None: class TestMaxNumResults: - """ - Tests for the ``--max-num-results`` option. - """ + """Tests for the ``--max-num-results`` option.""" @staticmethod def test_default( @@ -238,9 +226,7 @@ def test_default( tmp_path: Path, mock_database: VuforiaDatabase, ) -> None: - """ - By default the maximum number of results is 1. - """ + """By default the maximum number of results is 1.""" runner = CliRunner() target_id = vws_client.add_target( name=uuid.uuid4().hex, @@ -286,9 +272,7 @@ def test_custom( tmp_path: Path, mock_database: VuforiaDatabase, ) -> None: - """ - It is possible to set a custom ``--max-num-results``. - """ + """It is possible to set a custom ``--max-num-results``.""" runner = CliRunner() target_id = vws_client.add_target( name=uuid.uuid4().hex, @@ -374,9 +358,7 @@ def test_out_of_range( class TestIncludeTargetData: - """ - Tests for the ``--include-target-data`` option. - """ + """Tests for the ``--include-target-data`` option.""" @staticmethod def test_default( @@ -385,9 +367,7 @@ def test_default( tmp_path: Path, mock_database: VuforiaDatabase, ) -> None: - """ - By default, target data is only returned in the top match. - """ + """By default, target data is only returned in the top match.""" runner = CliRunner() target_id = vws_client.add_target( name=uuid.uuid4().hex, @@ -437,7 +417,8 @@ def test_top( mock_database: VuforiaDatabase, ) -> None: """ - When 'top' is given, target data is only returned in the top match. + When 'top' is given, target data is only returned in the top + match. """ runner = CliRunner() target_id = vws_client.add_target( @@ -490,7 +471,8 @@ def test_none( mock_database: VuforiaDatabase, ) -> None: """ - When 'none' is given, target data is not returned in any match. + When 'none' is given, target data is not returned in any + match. """ runner = CliRunner() target_id = vws_client.add_target( @@ -542,9 +524,7 @@ def test_all( tmp_path: Path, mock_database: VuforiaDatabase, ) -> None: - """ - When 'all' is given, target data is returned in all matches. - """ + """When 'all' is given, target data is returned in all matches.""" runner = CliRunner() target_id = vws_client.add_target( name=uuid.uuid4().hex, @@ -596,7 +576,8 @@ def test_other( mock_database: VuforiaDatabase, ) -> None: """ - When a string other than 'top', 'all', or 'none' is given, an error is + When a string other than 'top', 'all', or 'none' is given, an + error is shown. """ runner = CliRunner() @@ -631,7 +612,8 @@ def test_other( def test_base_vwq_url(high_quality_image: io.BytesIO, tmp_path: Path) -> None: """ - It is possible to use query a target to a database under a custom VWQ URL. + It is possible to use query a target to a database under a custom + VWQ URL. """ runner = CliRunner() base_vwq_url = "http://example.com" @@ -683,7 +665,8 @@ def test_env_var_credentials( mock_database: VuforiaDatabase, ) -> None: """ - It is possible to use environment variables to set the credentials. + It is possible to use environment variables to set the + credentials. """ runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex diff --git a/tests/test_query_errors.py b/tests/test_query_errors.py index 1f9b7dde..6067bc70 100644 --- a/tests/test_query_errors.py +++ b/tests/test_query_errors.py @@ -1,6 +1,4 @@ -""" -Tests for how errors from the Cloud Reco Service are handled by the CLI. -""" +"""Tests for how errors from the Cloud Reco Service are handled by the CLI.""" import io import uuid @@ -20,9 +18,7 @@ def test_authentication_failure( tmp_path: Path, high_quality_image: io.BytesIO, ) -> None: - """ - An error is given when the secret key is incorrect. - """ + """An error is given when the secret key is incorrect.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex image_data = high_quality_image.getvalue() @@ -50,9 +46,7 @@ def test_image_too_large( tmp_path: Path, png_too_large: io.BytesIO, ) -> None: - """ - An error is given when the image is too large. - """ + """An error is given when the image is too large.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex image_data = png_too_large.getvalue() @@ -112,7 +106,8 @@ def test_inactive_project( tmp_path: Path, ) -> None: """ - An error is given if the project is inactive and the desired action cannot + An error is given if the project is inactive and the desired action + cannot be taken because of this. """ new_file = tmp_path / uuid.uuid4().hex @@ -150,7 +145,8 @@ def test_request_time_too_skewed( tmp_path: Path, ) -> None: """ - An error is given when the request time is more than 65 minutes different + An error is given when the request time is more than 65 minutes + different from the server time. """ runner = CliRunner() diff --git a/tests/test_vws_commands.py b/tests/test_vws_commands.py index 9996fd14..4be064a6 100644 --- a/tests/test_vws_commands.py +++ b/tests/test_vws_commands.py @@ -1,7 +1,5 @@ # pylint:disable=too-many-lines -""" -Tests for VWS CLI commands. -""" +"""Tests for VWS CLI commands.""" import base64 import io @@ -27,9 +25,7 @@ def test_get_database_summary_report( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to get a database summary report. - """ + """It is possible to get a database summary report.""" runner = CliRunner() for name in ("a", "b"): vws_client.add_target( @@ -77,9 +73,7 @@ def test_list_targets( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to get a list of targets in the database. - """ + """It is possible to get a list of targets in the database.""" runner = CliRunner() target_id_1 = vws_client.add_target( name="x1", @@ -120,9 +114,7 @@ def test_get_target_record( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to get a target record. - """ + """It is possible to get a target record.""" runner = CliRunner() target_id = vws_client.add_target( name="x", @@ -164,9 +156,7 @@ def test_get_target_summary_report( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to get a target summary report. - """ + """It is possible to get a target summary report.""" runner = CliRunner() upload_date = "2015-04-29" with freeze_time(time_to_freeze=upload_date): @@ -214,9 +204,7 @@ def test_delete_target( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to delete a target. - """ + """It is possible to delete a target.""" runner = CliRunner() target_id = vws_client.add_target( name="x", @@ -252,9 +240,7 @@ def test_get_duplicate_targets( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to get a list of duplicate targets. - """ + """It is possible to get a list of duplicate targets.""" runner = CliRunner() target_id = vws_client.add_target( name="x", @@ -296,9 +282,7 @@ def test_get_duplicate_targets( class TestAddTarget: - """ - Tests for ``vws add-target``. - """ + """Tests for ``vws add-target``.""" @staticmethod def test_add_target( @@ -308,9 +292,7 @@ def test_add_target( tmp_path: Path, cloud_reco_client: CloudRecoService, ) -> None: - """ - It is possible to add a target. - """ + """It is possible to add a target.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex name = uuid.uuid4().hex @@ -358,7 +340,8 @@ def test_image_file_does_not_exist( tmp_path: Path, ) -> None: """ - An appropriate error is given if the given image file does not exist. + An appropriate error is given if the given image file does not + exist. """ runner = CliRunner() does_not_exist_file = tmp_path / uuid.uuid4().hex @@ -400,7 +383,8 @@ def test_image_file_is_dir( tmp_path: Path, ) -> None: """ - An appropriate error is given if the given image file path points to a + An appropriate error is given if the given image file path + points to a directory. """ runner = CliRunner() @@ -443,9 +427,7 @@ def test_relative_path( high_quality_image: io.BytesIO, tmp_path: Path, ) -> None: - """ - Image file paths are resolved. - """ + """Image file paths are resolved.""" runner = CliRunner() new_filename = uuid.uuid4().hex original_image_file = tmp_path / "foo" @@ -487,9 +469,7 @@ def test_custom_metadata( tmp_path: Path, high_quality_image: io.BytesIO, ) -> None: - """ - Custom metadata can be given. - """ + """Custom metadata can be given.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex name = uuid.uuid4().hex @@ -548,9 +528,7 @@ def test_custom_active_flag( *, active_flag_expected: bool, ) -> None: - """ - The Active Flag of the new target can be chosen. - """ + """The Active Flag of the new target can be chosen.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex image_data = high_quality_image.getvalue() @@ -585,9 +563,7 @@ def test_custom_active_flag( class TestWaitForTargetProcessed: - """ - Tests for ``vws wait-for-target-processed``. - """ + """Tests for ``vws wait-for-target-processed``.""" @staticmethod def test_wait_for_target_processed( @@ -596,7 +572,8 @@ def test_wait_for_target_processed( high_quality_image: io.BytesIO, ) -> None: """ - It is possible to use a command to wait for a target to be processed. + It is possible to use a command to wait for a target to be + processed. """ runner = CliRunner() target_id = vws_client.add_target( @@ -632,9 +609,7 @@ def test_wait_for_target_processed( def test_default_seconds_between_requests( high_quality_image: io.BytesIO, ) -> None: - """ - By default, 0.2 seconds are waited between polling requests. - """ + """By default, 0.2 seconds are waited between polling requests.""" runner = CliRunner() with MockVWS(processing_time_seconds=0.5) as mock: mock_database = VuforiaDatabase() @@ -702,7 +677,8 @@ def test_custom_seconds_between_requests( high_quality_image: io.BytesIO, ) -> None: """ - It is possible to customize the time waited between polling requests. + It is possible to customize the time waited between polling + requests. """ runner = CliRunner() with MockVWS(processing_time_seconds=0.5) as mock: @@ -768,7 +744,8 @@ def test_custom_seconds_between_requests( @staticmethod def test_custom_seconds_too_small(mock_database: VuforiaDatabase) -> None: """ - The minimum valid value for ``--seconds-between-requests`` is 0.05 + The minimum valid value for ``--seconds-between-requests`` is + 0.05 seconds. """ runner = CliRunner() @@ -796,9 +773,7 @@ def test_custom_seconds_too_small(mock_database: VuforiaDatabase) -> None: @staticmethod def test_custom_timeout(high_quality_image: io.BytesIO) -> None: - """ - It is possible to set a maximum timeout. - """ + """It is possible to set a maximum timeout.""" runner = CliRunner() with MockVWS(processing_time_seconds=0.5) as mock: mock_database = VuforiaDatabase() @@ -863,7 +838,8 @@ def test_custom_timeout(high_quality_image: io.BytesIO) -> None: @staticmethod def test_custom_timeout_too_small(mock_database: VuforiaDatabase) -> None: """ - The minimum valid value for ``--timeout-seconds`` is 0.05 seconds. + The minimum valid value for ``--timeout-seconds`` is 0.05 + seconds. """ runner = CliRunner() commands = [ @@ -889,9 +865,7 @@ def test_custom_timeout_too_small(mock_database: VuforiaDatabase) -> None: class TestUpdateTarget: - """ - Tests for ``vws update-target``. - """ + """Tests for ``vws update-target``.""" @staticmethod def test_update_target( @@ -903,9 +877,7 @@ def test_update_target( cloud_reco_client: CloudRecoService, different_high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to update a target. - """ + """It is possible to update a target.""" runner = CliRunner() old_name = uuid.uuid4().hex old_width = secrets.choice(seq=range(1, 5000)) / 100 @@ -996,9 +968,7 @@ def test_no_fields_given( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to give no update fields. - """ + """It is possible to give no update fields.""" runner = CliRunner() old_name = uuid.uuid4().hex old_width = secrets.choice(seq=range(1, 5000)) / 100 @@ -1037,7 +1007,8 @@ def test_image_file_does_not_exist( tmp_path: Path, ) -> None: """ - An appropriate error is given if the given image file does not exist. + An appropriate error is given if the given image file does not + exist. """ target_id = vws_client.add_target( name="x", @@ -1087,7 +1058,8 @@ def test_image_file_is_dir( tmp_path: Path, ) -> None: """ - An appropriate error is given if the given image file path points to a + An appropriate error is given if the given image file path + points to a directory. """ target_id = vws_client.add_target( @@ -1136,9 +1108,7 @@ def test_relative_path( high_quality_image: io.BytesIO, tmp_path: Path, ) -> None: - """ - Image file paths are resolved. - """ + """Image file paths are resolved.""" runner = CliRunner() target_id = vws_client.add_target( name="x", @@ -1179,7 +1149,8 @@ def test_relative_path( def test_custom_base_url() -> None: """ - It is possible to use the API to connect to a database under a custom VWS + It is possible to use the API to connect to a database under a + custom VWS URL. """ runner = CliRunner() diff --git a/tests/test_vws_errors.py b/tests/test_vws_errors.py index 3c4e7515..321f4c75 100644 --- a/tests/test_vws_errors.py +++ b/tests/test_vws_errors.py @@ -1,6 +1,4 @@ -""" -Tests for how errors from VWS are handled by the CLI. -""" +"""Tests for how errors from VWS are handled by the CLI.""" import io import uuid @@ -18,7 +16,8 @@ def test_target_id_does_not_exist(mock_database: VuforiaDatabase) -> None: """ - Commands which take a target ID show an error if that does not map to a + Commands which take a target ID show an error if that does not map + to a target in the database. """ runner = CliRunner() @@ -80,8 +79,10 @@ def test_fail_bad_request( high_quality_image: io.BytesIO, tmp_path: Path, ) -> None: - """An error is given when Vuforia returns a ``Fail`` error with a ``400`` - error code. For example, when the given server access key does not exist. + """An error is given when Vuforia returns a ``Fail`` error with a + ``400`` + error code. For example, when the given server access key does not + exist. With ``vws_python`` we cannot get a (guaranteed) 500 error or 422 response with a ``Fail`` error. @@ -118,9 +119,7 @@ def test_metadata_too_large( high_quality_image: io.BytesIO, tmp_path: Path, ) -> None: - """ - An error is given when the given metadata is too large. - """ + """An error is given when the given metadata is too large.""" new_file = tmp_path / uuid.uuid4().hex new_file.write_bytes(data=high_quality_image.getvalue()) runner = CliRunner() @@ -151,9 +150,7 @@ def test_image_too_large( png_too_large: io.BytesIO, tmp_path: Path, ) -> None: - """ - An error is given when the given image is too large. - """ + """An error is given when the given image is too large.""" runner = CliRunner() new_file = tmp_path / uuid.uuid4().hex image_data = png_too_large.getvalue() @@ -190,7 +187,8 @@ def test_target_name_exist( tmp_path: Path, ) -> None: """ - An error is given when there is already a target with the given name. + An error is given when there is already a target with the given + name. """ name = "foobar" vws_client.add_target( @@ -235,7 +233,8 @@ def test_project_inactive( tmp_path: Path, ) -> None: """ - An error is given if the project is inactive and the desired action cannot + An error is given if the project is inactive and the desired action + cannot be taken because of this. """ new_file = tmp_path / uuid.uuid4().hex @@ -279,7 +278,8 @@ def test_unknown_vws_error( tmp_path: Path, ) -> None: """ - When an unknown VWS error is given, e.g. what is given when some bad names + When an unknown VWS error is given, e.g. what is given when some bad + names are given, an error is given. """ runner = CliRunner() @@ -323,7 +323,8 @@ def test_target_status_processing( mock_database: VuforiaDatabase, ) -> None: """ - An error is given when trying to delete a target which is processing. + An error is given when trying to delete a target which is + processing. """ runner = CliRunner() @@ -366,7 +367,8 @@ def test_target_status_not_success( mock_database: VuforiaDatabase, ) -> None: """ - An error is given when updating a target which has a status which is not + An error is given when updating a target which has a status which is + not "Success". """ runner = CliRunner() @@ -404,9 +406,7 @@ def test_target_status_not_success( def test_authentication_failure(mock_database: VuforiaDatabase) -> None: - """ - An error is given when the secret key is incorrect. - """ + """An error is given when the secret key is incorrect.""" runner = CliRunner() commands = [ "list-targets", @@ -430,7 +430,8 @@ def test_authentication_failure(mock_database: VuforiaDatabase) -> None: def test_request_time_too_skewed(mock_database: VuforiaDatabase) -> None: """ - An error is given when the request time is more than 5 minutes different + An error is given when the request time is more than 5 minutes + different from the server time. """ runner = CliRunner() diff --git a/uv.lock b/uv.lock index 524e9284..76b5d6f9 100644 --- a/uv.lock +++ b/uv.lock @@ -392,19 +392,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/fa/fb5ceaad739d7126df95ff7f55183ce822e1695a46fc4c287781d74d6255/doccmd-2026.1.23.4-py2.py3-none-any.whl", hash = "sha256:3a17bb8deaa3b7bbee726fbe69e21036b5816e5298dac1f179e928f9c60ab3b5", size = 18398, upload-time = "2026-01-23T13:40:39.492Z" }, ] -[[package]] -name = "docformatter" -version = "1.7.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "charset-normalizer" }, - { name = "untokenize" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/7b/ee08cb5fe2627ed0b6f0cc4a1c6be6c9c71de5a3e9785de8174273fc3128/docformatter-1.7.7.tar.gz", hash = "sha256:ea0e1e8867e5af468dfc3f9e947b92230a55be9ec17cd1609556387bffac7978", size = 26587, upload-time = "2025-05-11T04:54:04.356Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl", hash = "sha256:7af49f8a46346a77858f6651f431b882c503c2f4442c8b4524b920c863277834", size = 33525, upload-time = "2025-05-11T04:54:03.353Z" }, -] - [[package]] name = "docutils" version = "0.21.2" @@ -1335,6 +1322,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] +[[package]] +name = "pydocstringformatter" +version = "0.7.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/51/5c21963eb7bdba245ec808fdb0ef8abc0cd87ef674f2b6ba1fd76f3a0ffa/pydocstringformatter-0.7.3.tar.gz", hash = "sha256:dfcc07bec1706803d563275e282ef9e629b02dc19983ec6778d07a9f500bb62b", size = 24024, upload-time = "2023-01-02T15:09:30.152Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/38/b3a99e9cc66941e044ad3d40e90a72b1191925b8af13e3e4d8edc5c0eb87/pydocstringformatter-0.7.3-py3-none-any.whl", hash = "sha256:3654f52c49fc729b49712d1e7c49384dfd253bdffeda4939e79dab31491c563f", size = 31287, upload-time = "2023-01-02T15:09:28.904Z" }, +] + [[package]] name = "pyenchant" version = "3.3.0" @@ -2322,12 +2318,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] -[[package]] -name = "untokenize" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2", size = 3099, upload-time = "2014-02-08T16:30:40.631Z" } - [[package]] name = "urllib3" version = "2.6.3" @@ -2372,7 +2362,6 @@ dev = [ { name = "deptry" }, { name = "doc8" }, { name = "doccmd" }, - { name = "docformatter" }, { name = "freezegun" }, { name = "furo" }, { name = "hadolint-bin", marker = "sys_platform != 'win32'" }, @@ -2380,6 +2369,7 @@ dev = [ { name = "mypy", extra = ["faster-cache"] }, { name = "mypy-strict-kwargs" }, { name = "prek" }, + { name = "pydocstringformatter" }, { name = "pylint", extra = ["spelling"] }, { name = "pyproject-fmt" }, { name = "pyrefly" }, @@ -2423,7 +2413,6 @@ requires-dist = [ { name = "deptry", marker = "extra == 'dev'", specifier = "==0.24.0" }, { name = "doc8", marker = "extra == 'dev'", specifier = "==2.0.0" }, { name = "doccmd", marker = "extra == 'dev'", specifier = "==2026.1.23.4" }, - { name = "docformatter", marker = "extra == 'dev'", specifier = "==1.7.7" }, { name = "freezegun", marker = "extra == 'dev'", specifier = "==1.5.5" }, { name = "furo", marker = "extra == 'dev'", specifier = "==2025.12.19" }, { name = "hadolint-bin", marker = "sys_platform != 'win32' and extra == 'dev'", specifier = "==2.14.0" }, @@ -2432,6 +2421,7 @@ requires-dist = [ { name = "mypy", extras = ["faster-cache"], marker = "extra == 'dev'", specifier = "==1.19.1" }, { name = "mypy-strict-kwargs", marker = "extra == 'dev'", specifier = "==2026.1.12" }, { name = "prek", marker = "extra == 'dev'", specifier = "==0.3.0" }, + { name = "pydocstringformatter", marker = "extra == 'dev'", specifier = "==0.7.3" }, { name = "pylint", extras = ["spelling"], marker = "extra == 'dev'", specifier = "==4.0.4" }, { name = "pyproject-fmt", marker = "extra == 'dev'", specifier = "==2.11.1" }, { name = "pyrefly", marker = "extra == 'dev'", specifier = "==0.49.0" },