From c5f4eadbcd741164f39152960d3fba50ec2b3c13 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 12 Jan 2026 14:17:13 +0000 Subject: [PATCH 01/13] Switch from docformatter to pydocstringformatter --- .pre-commit-config.yaml | 8 ++++---- pyproject.toml | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1ed243a7a..6b48bc64c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ ci: - check-manifest - deptry - doc8 - - docformatter + - pydocstringformatter - docs - interrogate - interrogate-docs @@ -104,9 +104,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] additional_dependencies: [uv==0.9.5] diff --git a/pyproject.toml b/pyproject.toml index 3f7f5df0a..d4a6cbd29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,13 +42,13 @@ optional-dependencies.dev = [ "deptry==0.24.0", "doc8==2.0.0", "doccmd==2026.1.3.2", - "docformatter==1.7.7", "freezegun==1.5.5", "furo==2025.12.19", "interrogate==1.7.0", "mypy[faster-cache]==1.19.1", "mypy-strict-kwargs==2026.1.12", "prek==0.2.27", + "pydocstringformatter==0.7.3", "pydocstyle==6.3", "pygments==2.19.2", "pylint[spelling]==4.0.4", @@ -274,9 +274,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 = [ @@ -346,6 +343,10 @@ enableTypeIgnoreComments = false reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" +[tool.pydocstringformatter] +write = true +split-summary-body = false + [tool.interrogate] fail-under = 100 omit-covered-files = true From e4126ee5441f4afdae41339aad26f77c04bc4638 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, 12 Jan 2026 14:18:45 +0000 Subject: [PATCH 02/13] [pre-commit.ci lite] apply automatic fixes --- conftest.py | 8 +- docs/source/__init__.py | 4 +- docs/source/conf.py | 4 +- src/vws/__init__.py | 4 +- src/vws/exceptions/__init__.py | 4 +- src/vws/exceptions/base_exceptions.py | 12 +-- src/vws/exceptions/cloud_reco_exceptions.py | 16 +--- src/vws/exceptions/custom_exceptions.py | 20 +--- src/vws/exceptions/vws_exceptions.py | 68 ++++--------- src/vws/include_target_data.py | 4 +- src/vws/query.py | 12 +-- src/vws/reports.py | 8 +- src/vws/response.py | 8 +- src/vws/vws.py | 12 +-- tests/__init__.py | 4 +- tests/conftest.py | 24 ++--- tests/test_cloud_reco_exceptions.py | 8 +- tests/test_query.py | 40 ++------ tests/test_vws.py | 100 +++++--------------- tests/test_vws_exceptions.py | 20 +--- 20 files changed, 100 insertions(+), 280 deletions(-) diff --git a/conftest.py b/conftest.py index 1d776f8db..0e579a4db 100644 --- a/conftest.py +++ b/conftest.py @@ -1,6 +1,4 @@ -""" -Setup for Sybil. -""" +"""Setup for Sybil.""" import io import uuid @@ -21,9 +19,7 @@ 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: if isinstance(item, pytest.Function): item.obj = beartype(obj=item.obj) diff --git a/docs/source/__init__.py b/docs/source/__init__.py index b63eed5fb..535ceb2ec 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 914bcb886..920ba1a4b 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.""" import importlib.metadata from pathlib import Path diff --git a/src/vws/__init__.py b/src/vws/__init__.py index 42788b92d..bfd96d6c2 100644 --- a/src/vws/__init__.py +++ b/src/vws/__init__.py @@ -1,6 +1,4 @@ -""" -A library for Vuforia Web Services. -""" +"""A library for Vuforia Web Services.""" from .query import CloudRecoService from .vws import VWS diff --git a/src/vws/exceptions/__init__.py b/src/vws/exceptions/__init__.py index a1e3cd91c..7260ffdbb 100644 --- a/src/vws/exceptions/__init__.py +++ b/src/vws/exceptions/__init__.py @@ -1,3 +1 @@ -""" -Custom exceptions raised by this package. -""" +"""Custom exceptions raised by this package.""" diff --git a/src/vws/exceptions/base_exceptions.py b/src/vws/exceptions/base_exceptions.py index 943323bfd..c86080593 100644 --- a/src/vws/exceptions/base_exceptions.py +++ b/src/vws/exceptions/base_exceptions.py @@ -10,9 +10,7 @@ @beartype class CloudRecoError(Exception): - """ - Base class for Vuforia Cloud Recognition Web API exceptions. - """ + """Base class for Vuforia Cloud Recognition Web API exceptions.""" def __init__(self, response: Response) -> None: """ @@ -24,9 +22,7 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response @@ -48,7 +44,5 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response diff --git a/src/vws/exceptions/cloud_reco_exceptions.py b/src/vws/exceptions/cloud_reco_exceptions.py index ff5dde209..2b20a7220 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,6 +1,4 @@ -""" -Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs. -""" +"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs.""" from beartype import beartype @@ -17,31 +15,27 @@ class MaxNumResultsOutOfRangeError(CloudRecoError): @beartype class InactiveProjectError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'InactiveProject'. """ @beartype class BadImageError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @beartype class RequestTimeTooSkewedError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index 694e98c30..466dfd1cd 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -11,9 +11,7 @@ @beartype class RequestEntityTooLargeError(Exception): - """ - Exception raised when the given image is too large. - """ + """Exception raised when the given image is too large.""" def __init__(self, response: Response) -> None: """ @@ -25,24 +23,18 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response @beartype class TargetProcessingTimeoutError(Exception): - """ - Exception raised when waiting for a target to be processed times out. - """ + """Exception raised when waiting for a target to be processed times out.""" @beartype class ServerError(Exception): # pragma: no cover - """ - Exception raised when VWS returns a server error. - """ + """Exception raised when VWS returns a server error.""" def __init__(self, response: Response) -> None: """ @@ -54,7 +46,5 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index 482223766..a25c2261b 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -14,16 +14,13 @@ @beartype class UnknownTargetError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'UnknownTarget'. """ @property def target_id(self) -> str: - """ - The unknown target ID. - """ + """The unknown target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -32,23 +29,19 @@ def target_id(self) -> str: @beartype class FailError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code 'Fail'. - """ + """Exception raised when Vuforia returns a response with a result code 'Fail'.""" @beartype class BadImageError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @@ -56,24 +49,20 @@ class AuthenticationFailureError(VWSError): # See https://github.com/VWS-Python/vws-python/issues/822. @beartype class RequestQuotaReachedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestQuotaReached'. """ @beartype class TargetStatusProcessingError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetStatusProcessing'. """ @property def target_id(self) -> str: - """ - The processing target ID. - """ + """The processing target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -83,8 +72,7 @@ def target_id(self) -> str: # This is not simulated by the mock. @beartype class DateRangeError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'DateRangeError'. """ @@ -92,8 +80,7 @@ class DateRangeError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class TargetQuotaReachedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetQuotaReached'. """ @@ -101,8 +88,7 @@ class TargetQuotaReachedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectSuspendedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectSuspended'. """ @@ -110,48 +96,41 @@ class ProjectSuspendedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectHasNoAPIAccessError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectHasNoAPIAccess'. """ @beartype class ProjectInactiveError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectInactive'. """ @beartype class MetadataTooLargeError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'MetadataTooLarge'. """ @beartype class RequestTimeTooSkewedError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ @beartype class TargetNameExistError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetNameExist'. """ @property def target_name(self) -> str: - """ - The target name which already exists. - """ + """The target name which already exists.""" response_body = self.response.request_body or b"" request_json = json.loads(s=response_body) return str(object=request_json["name"]) @@ -159,24 +138,20 @@ def target_name(self) -> str: @beartype class ImageTooLargeError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ImageTooLarge'. """ @beartype class TargetStatusNotSuccessError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetStatusNotSuccess'. """ @property def target_id(self) -> str: - """ - The unknown target ID. - """ + """The unknown target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -185,7 +160,6 @@ def target_id(self) -> str: @beartype class TooManyRequestsError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TooManyRequests'. """ diff --git a/src/vws/include_target_data.py b/src/vws/include_target_data.py index 37682e08a..0692a1e40 100644 --- a/src/vws/include_target_data.py +++ b/src/vws/include_target_data.py @@ -1,6 +1,4 @@ -""" -Tools for managing ``CloudRecoService.query``'s ``include_target_data``. -""" +"""Tools for managing ``CloudRecoService.query``'s ``include_target_data``.""" from enum import StrEnum, auto, unique diff --git a/src/vws/query.py b/src/vws/query.py index 96122aa14..ab449c614 100644 --- a/src/vws/query.py +++ b/src/vws/query.py @@ -1,6 +1,4 @@ -""" -Tools for interacting with the Vuforia Cloud Recognition Web APIs. -""" +"""Tools for interacting with the Vuforia Cloud Recognition Web APIs.""" import datetime import io @@ -34,9 +32,7 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """ - Get the data of an image file. - """ + """Get the data of an image file.""" original_tell = image.tell() image.seek(0) image_data = image.read() @@ -46,9 +42,7 @@ def _get_image_data(image: _ImageType) -> bytes: @beartype class CloudRecoService: - """ - An interface to the Vuforia Cloud Recognition Web APIs. - """ + """An interface to the Vuforia Cloud Recognition Web APIs.""" def __init__( self, diff --git a/src/vws/reports.py b/src/vws/reports.py index f6a77133c..e59408aad 100644 --- a/src/vws/reports.py +++ b/src/vws/reports.py @@ -1,6 +1,4 @@ -""" -Classes for representing Vuforia reports. -""" +"""Classes for representing Vuforia reports.""" import datetime from dataclasses import dataclass @@ -86,9 +84,7 @@ class TargetRecord: @beartype @dataclass(frozen=True) class TargetData: - """ - The target data optionally included with a query match. - """ + """The target data optionally included with a query match.""" name: str application_metadata: str | None diff --git a/src/vws/response.py b/src/vws/response.py index 269f2e23f..e2060cb9e 100644 --- a/src/vws/response.py +++ b/src/vws/response.py @@ -1,6 +1,4 @@ -""" -Responses for requests to VWS and VWQ. -""" +"""Responses for requests to VWS and VWQ.""" from dataclasses import dataclass @@ -10,9 +8,7 @@ @dataclass(frozen=True) @beartype class Response: - """ - A response from a request. - """ + """A response from a request.""" text: str url: str diff --git a/src/vws/vws.py b/src/vws/vws.py index 8def19ed7..1191ee7df 100644 --- a/src/vws/vws.py +++ b/src/vws/vws.py @@ -1,6 +1,4 @@ -""" -Tools for interacting with Vuforia APIs. -""" +"""Tools for interacting with Vuforia APIs.""" import base64 import io @@ -52,9 +50,7 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """ - Get the data of an image file. - """ + """Get the data of an image file.""" original_tell = image.tell() image.seek(0) image_data = image.read() @@ -131,9 +127,7 @@ def _target_api_request( @beartype(conf=BeartypeConf(is_pep484_tower=True)) class VWS: - """ - An interface to Vuforia Web Services APIs. - """ + """An interface to Vuforia Web Services APIs.""" def __init__( self, diff --git a/tests/__init__.py b/tests/__init__.py index c7e38a862..3502d86d5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1 @@ -""" -Tests for ``vws``. -""" +"""Tests for ``vws``.""" diff --git a/tests/conftest.py b/tests/conftest.py index 74c6fc56d..7c0647786 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,4 @@ -""" -Configuration, plugins and fixtures for `pytest`. -""" +"""Configuration, plugins and fixtures for `pytest`.""" import io from collections.abc import Generator @@ -16,9 +14,7 @@ @pytest.fixture(name="_mock_database") def fixture_mock_database() -> Generator[VuforiaDatabase]: - """ - Yield a mock ``VuforiaDatabase``. - """ + """Yield a mock ``VuforiaDatabase``.""" # We use a low processing time so that tests run quickly. with MockVWS(processing_time_seconds=0.2) as mock: database = VuforiaDatabase() @@ -28,9 +24,7 @@ def fixture_mock_database() -> Generator[VuforiaDatabase]: @pytest.fixture def vws_client(_mock_database: VuforiaDatabase) -> VWS: - """ - A VWS client which connects to a mock database. - """ + """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, @@ -39,9 +33,7 @@ def vws_client(_mock_database: VuforiaDatabase) -> VWS: @pytest.fixture def cloud_reco_client(_mock_database: VuforiaDatabase) -> CloudRecoService: - """ - A ``CloudRecoService`` client which connects to a mock database. - """ + """A ``CloudRecoService`` client which connects to a mock database.""" return CloudRecoService( client_access_key=_mock_database.client_access_key, client_secret_key=_mock_database.client_secret_key, @@ -54,9 +46,7 @@ def fixture_image_file( tmp_path: Path, request: pytest.FixtureRequest, ) -> Generator[BinaryIO]: - """ - An image file object. - """ + """An image file object.""" file = tmp_path / "image.jpg" buffer = high_quality_image.getvalue() file.write_bytes(data=buffer) @@ -71,9 +61,7 @@ def image( high_quality_image: io.BytesIO, image_file: BinaryIO, ) -> io.BytesIO | BinaryIO: - """ - An image in any of the types that the API accepts. - """ + """An image in any of the types that the API accepts.""" if request.param == "high_quality_image": return high_quality_image return image_file diff --git a/tests/test_cloud_reco_exceptions.py b/tests/test_cloud_reco_exceptions.py index 3515b0d22..d4c8cb0f7 100644 --- a/tests/test_cloud_reco_exceptions.py +++ b/tests/test_cloud_reco_exceptions.py @@ -1,6 +1,4 @@ -""" -Tests for exceptions raised when using the CloudRecoService. -""" +"""Tests for exceptions raised when using the CloudRecoService.""" import io import uuid @@ -63,9 +61,7 @@ def test_image_too_large( def test_cloudrecoexception_inheritance() -> None: - """ - CloudRecoService-specific exceptions inherit from CloudRecoException. - """ + """CloudRecoService-specific exceptions inherit from CloudRecoException.""" subclasses = [ MaxNumResultsOutOfRangeError, InactiveProjectError, diff --git a/tests/test_query.py b/tests/test_query.py index e229cf95d..11b803eb5 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -1,6 +1,4 @@ -""" -Tests for the ``CloudRecoService`` querying functionality. -""" +"""Tests for the ``CloudRecoService`` querying functionality.""" import io import uuid @@ -14,18 +12,14 @@ class TestQuery: - """ - Tests for making image queries. - """ + """Tests for making image queries.""" @staticmethod def test_no_matches( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - An empty list is returned if there are no matches. - """ + """An empty list is returned if there are no matches.""" result = cloud_reco_client.query(image=image) assert result == [] @@ -35,9 +29,7 @@ def test_match( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of matching targets are returned. - """ + """Details of matching targets are returned.""" target_id = vws_client.add_target( name="x", width=1, @@ -51,9 +43,7 @@ def test_match( class TestCustomBaseVWQURL: - """ - Tests for using a custom base VWQ URL. - """ + """Tests for using a custom base VWQ URL.""" @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -93,9 +83,7 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestMaxNumResults: - """ - Tests for the ``max_num_results`` parameter of ``query``. - """ + """Tests for the ``max_num_results`` parameter of ``query``.""" @staticmethod def test_default( @@ -103,9 +91,7 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - By default the maximum number of results is 1. - """ + """By default the maximum number of results is 1.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -131,9 +117,7 @@ def test_custom( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to set a custom ``max_num_results``. - """ + """It is possible to set a custom ``max_num_results``.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -167,9 +151,7 @@ def test_custom( class TestIncludeTargetData: - """ - Tests for the ``include_target_data`` parameter of ``query``. - """ + """Tests for the ``include_target_data`` parameter of ``query``.""" @staticmethod def test_default( @@ -177,9 +159,7 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - By default, target data is only returned in the top match. - """ + """By default, target data is only returned in the top match.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, diff --git a/tests/test_vws.py b/tests/test_vws.py index e16eff555..d427e1c9b 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -1,6 +1,4 @@ -""" -Tests for helper functions for managing a Vuforia database. -""" +"""Tests for helper functions for managing a Vuforia database.""" import base64 import datetime @@ -25,9 +23,7 @@ class TestAddTarget: - """ - Tests for adding a target. - """ + """Tests for adding a target.""" @staticmethod @pytest.mark.parametrize( @@ -43,9 +39,7 @@ def test_add_target( *, active_flag: bool, ) -> None: - """ - No exception is raised when adding one target. - """ + """No exception is raised when adding one target.""" name = "x" width = 1 if application_metadata is None: @@ -98,9 +92,7 @@ def test_add_two_targets( class TestCustomBaseVWSURL: - """ - Tests for using a custom base VWS URL. - """ + """Tests for using a custom base VWS URL.""" @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -128,18 +120,14 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestListTargets: - """ - Tests for listing targets. - """ + """Tests for listing targets.""" @staticmethod def test_list_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to get a list of target IDs. - """ + """It is possible to get a list of target IDs.""" id_1 = vws_client.add_target( name="x", width=1, @@ -158,18 +146,14 @@ def test_list_targets( class TestDelete: - """ - Test for deleting a target. - """ + """Test for deleting a target.""" @staticmethod def test_delete_target( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to delete a target. - """ + """It is possible to delete a target.""" target_id = vws_client.add_target( name="x", width=1, @@ -185,18 +169,14 @@ def test_delete_target( class TestGetTargetSummaryReport: - """ - Tests for getting a summary report for a target. - """ + """Tests for getting a summary report for a target.""" @staticmethod def test_get_target_summary_report( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of a target are returned by ``get_target_summary_report``. - """ + """Details of a target are returned by ``get_target_summary_report``.""" date = "2018-04-25" target_name = uuid.uuid4().hex with freeze_time(time_to_freeze=date): @@ -240,15 +220,11 @@ def test_get_target_summary_report( class TestGetDatabaseSummaryReport: - """ - Tests for getting a summary report for a database. - """ + """Tests for getting a summary report for a database.""" @staticmethod def test_get_target(vws_client: VWS) -> None: - """ - Details of a database are returned by ``get_database_summary_report``. - """ + """Details of a database are returned by ``get_database_summary_report``.""" report = vws_client.get_database_summary_report() expected_report = DatabaseSummaryReport( @@ -287,18 +263,14 @@ def test_get_target(vws_client: VWS) -> None: class TestGetTargetRecord: - """ - Tests for getting a record of a target. - """ + """Tests for getting a record of a target.""" @staticmethod def test_get_target_record( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of a target are returned by ``get_target_record``. - """ + """Details of a target are returned by ``get_target_record``.""" target_id = vws_client.add_target( name="x", width=1, @@ -344,9 +316,7 @@ def test_get_failed( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - Check that the report works with a failed target. - """ + """Check that the report works with a failed target.""" target_id = vws_client.add_target( name="x", width=1, @@ -362,18 +332,14 @@ def test_get_failed( class TestWaitForTargetProcessed: - """ - Tests for waiting for a target to be processed. - """ + """Tests for waiting for a target to be processed.""" @staticmethod def test_wait_for_target_processed( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to wait until a target is processed. - """ + """It is possible to wait until a target is processed.""" target_id = vws_client.add_target( name="x", width=1, @@ -391,9 +357,7 @@ def test_wait_for_target_processed( def test_default_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """ - By default, 0.2 seconds are waited between polling requests. - """ + """By default, 0.2 seconds are waited between polling requests.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -443,9 +407,7 @@ def test_default_seconds_between_requests( def test_custom_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to customize the time waited between polling requests. - """ + """It is possible to customize the time waited between polling requests.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -493,9 +455,7 @@ def test_custom_seconds_between_requests( @staticmethod def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: - """ - It is possible to set a maximum timeout. - """ + """It is possible to set a maximum timeout.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -531,18 +491,14 @@ def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: class TestGetDuplicateTargets: - """ - Tests for getting duplicate targets. - """ + """Tests for getting duplicate targets.""" @staticmethod def test_get_duplicate_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to get the IDs of similar targets. - """ + """It is possible to get the IDs of similar targets.""" target_id = vws_client.add_target( name="x", width=1, @@ -565,9 +521,7 @@ def test_get_duplicate_targets( class TestUpdateTarget: - """ - Tests for updating a target. - """ + """Tests for updating a target.""" @staticmethod def test_update_target( @@ -576,9 +530,7 @@ def test_update_target( different_high_quality_image: io.BytesIO, cloud_reco_client: CloudRecoService, ) -> None: - """ - It is possible to update a target. - """ + """It is possible to update a target.""" old_name = uuid.uuid4().hex old_width = secrets.choice(seq=range(1, 5000)) / 100 target_id = vws_client.add_target( @@ -635,9 +587,7 @@ def test_no_fields_given( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to give no update fields. - """ + """It is possible to give no update fields.""" target_id = vws_client.add_target( name="x", width=1, diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index 86da66040..eb5b12a6f 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -1,6 +1,4 @@ -""" -Tests for VWS exceptions. -""" +"""Tests for VWS exceptions.""" import io import uuid @@ -98,9 +96,7 @@ def test_request_quota_reached() -> None: def test_fail(high_quality_image: io.BytesIO) -> None: - """ - A ``Fail`` exception is raised when the server access key does not exist. - """ + """A ``Fail`` exception is raised when the server access key does not exist.""" with MockVWS(): vws_client = VWS( server_access_key=uuid.uuid4().hex, @@ -120,9 +116,7 @@ def test_fail(high_quality_image: io.BytesIO) -> None: def test_bad_image(vws_client: VWS) -> None: - """ - A ``BadImage`` exception is raised when a non-image is given. - """ + """A ``BadImage`` exception is raised when a non-image is given.""" not_an_image = io.BytesIO(initial_bytes=b"Not an image") with pytest.raises(expected_exception=BadImageError) as exc: vws_client.add_target( @@ -325,9 +319,7 @@ def test_target_status_not_success( def test_vwsexception_inheritance() -> None: - """ - VWS-related exceptions should inherit from VWSException. - """ + """VWS-related exceptions should inherit from VWSException.""" subclasses = [ AuthenticationFailureError, BadImageError, @@ -354,9 +346,7 @@ def test_base_exception( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - ``VWSException``s has a response property. - """ + """``VWSException``s has a response property.""" with pytest.raises(expected_exception=VWSError) as exc: vws_client.get_target_record(target_id="a") From b57ba660dc68b9c917b91fe720d5bd223280745d Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 12 Jan 2026 14:23:57 +0000 Subject: [PATCH 03/13] Configure pydocstringformatter to make minimal changes --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d4a6cbd29..f83bea5bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -346,6 +346,8 @@ typeCheckingMode = "strict" [tool.pydocstringformatter] write = true split-summary-body = false +beginning-quotes = false +closing-quotes = false [tool.interrogate] fail-under = 100 From 6c82f4a9543f22170b369090744d872742ae8630 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 12 Jan 2026 14:24:43 +0000 Subject: [PATCH 04/13] Switch from pydocstringformatter --- conftest.py | 8 +- docs/source/__init__.py | 4 +- docs/source/conf.py | 4 +- pyproject.toml | 2 - src/vws/__init__.py | 4 +- src/vws/exceptions/__init__.py | 4 +- src/vws/exceptions/base_exceptions.py | 12 ++- src/vws/exceptions/cloud_reco_exceptions.py | 16 +++- src/vws/exceptions/custom_exceptions.py | 20 +++- src/vws/exceptions/vws_exceptions.py | 68 +++++++++---- src/vws/include_target_data.py | 4 +- src/vws/query.py | 12 ++- src/vws/reports.py | 8 +- src/vws/response.py | 8 +- src/vws/vws.py | 12 ++- tests/__init__.py | 4 +- tests/conftest.py | 24 +++-- tests/test_cloud_reco_exceptions.py | 8 +- tests/test_query.py | 40 ++++++-- tests/test_vws.py | 100 +++++++++++++++----- tests/test_vws_exceptions.py | 20 +++- 21 files changed, 280 insertions(+), 102 deletions(-) diff --git a/conftest.py b/conftest.py index 0e579a4db..1d776f8db 100644 --- a/conftest.py +++ b/conftest.py @@ -1,4 +1,6 @@ -"""Setup for Sybil.""" +""" +Setup for Sybil. +""" import io import uuid @@ -19,7 +21,9 @@ 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: if isinstance(item, pytest.Function): item.obj = beartype(obj=item.obj) diff --git a/docs/source/__init__.py b/docs/source/__init__.py index 535ceb2ec..b63eed5fb 100644 --- a/docs/source/__init__.py +++ b/docs/source/__init__.py @@ -1 +1,3 @@ -"""Documentation.""" +""" +Documentation. +""" diff --git a/docs/source/conf.py b/docs/source/conf.py index 920ba1a4b..914bcb886 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 -"""Configuration for Sphinx.""" +""" +Configuration for Sphinx. +""" import importlib.metadata from pathlib import Path diff --git a/pyproject.toml b/pyproject.toml index f83bea5bb..d4a6cbd29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -346,8 +346,6 @@ typeCheckingMode = "strict" [tool.pydocstringformatter] write = true split-summary-body = false -beginning-quotes = false -closing-quotes = false [tool.interrogate] fail-under = 100 diff --git a/src/vws/__init__.py b/src/vws/__init__.py index bfd96d6c2..42788b92d 100644 --- a/src/vws/__init__.py +++ b/src/vws/__init__.py @@ -1,4 +1,6 @@ -"""A library for Vuforia Web Services.""" +""" +A library for Vuforia Web Services. +""" from .query import CloudRecoService from .vws import VWS diff --git a/src/vws/exceptions/__init__.py b/src/vws/exceptions/__init__.py index 7260ffdbb..a1e3cd91c 100644 --- a/src/vws/exceptions/__init__.py +++ b/src/vws/exceptions/__init__.py @@ -1 +1,3 @@ -"""Custom exceptions raised by this package.""" +""" +Custom exceptions raised by this package. +""" diff --git a/src/vws/exceptions/base_exceptions.py b/src/vws/exceptions/base_exceptions.py index c86080593..943323bfd 100644 --- a/src/vws/exceptions/base_exceptions.py +++ b/src/vws/exceptions/base_exceptions.py @@ -10,7 +10,9 @@ @beartype class CloudRecoError(Exception): - """Base class for Vuforia Cloud Recognition Web API exceptions.""" + """ + Base class for Vuforia Cloud Recognition Web API exceptions. + """ def __init__(self, response: Response) -> None: """ @@ -22,7 +24,9 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """The response returned by Vuforia which included this error.""" + """ + The response returned by Vuforia which included this error. + """ return self._response @@ -44,5 +48,7 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """The response returned by Vuforia which included this error.""" + """ + The response returned by Vuforia which included this error. + """ return self._response diff --git a/src/vws/exceptions/cloud_reco_exceptions.py b/src/vws/exceptions/cloud_reco_exceptions.py index 2b20a7220..ff5dde209 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,4 +1,6 @@ -"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs.""" +""" +Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs. +""" from beartype import beartype @@ -15,27 +17,31 @@ class MaxNumResultsOutOfRangeError(CloudRecoError): @beartype class InactiveProjectError(CloudRecoError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'InactiveProject'. """ @beartype class BadImageError(CloudRecoError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(CloudRecoError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @beartype class RequestTimeTooSkewedError(CloudRecoError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index 466dfd1cd..694e98c30 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -11,7 +11,9 @@ @beartype class RequestEntityTooLargeError(Exception): - """Exception raised when the given image is too large.""" + """ + Exception raised when the given image is too large. + """ def __init__(self, response: Response) -> None: """ @@ -23,18 +25,24 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """The response returned by Vuforia which included this error.""" + """ + The response returned by Vuforia which included this error. + """ return self._response @beartype class TargetProcessingTimeoutError(Exception): - """Exception raised when waiting for a target to be processed times out.""" + """ + Exception raised when waiting for a target to be processed times out. + """ @beartype class ServerError(Exception): # pragma: no cover - """Exception raised when VWS returns a server error.""" + """ + Exception raised when VWS returns a server error. + """ def __init__(self, response: Response) -> None: """ @@ -46,5 +54,7 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """The response returned by Vuforia which included this error.""" + """ + The response returned by Vuforia which included this error. + """ return self._response diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index a25c2261b..482223766 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -14,13 +14,16 @@ @beartype class UnknownTargetError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'UnknownTarget'. """ @property def target_id(self) -> str: - """The unknown target ID.""" + """ + The unknown target ID. + """ path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -29,19 +32,23 @@ def target_id(self) -> str: @beartype class FailError(VWSError): - """Exception raised when Vuforia returns a response with a result code 'Fail'.""" + """ + Exception raised when Vuforia returns a response with a result code 'Fail'. + """ @beartype class BadImageError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @@ -49,20 +56,24 @@ class AuthenticationFailureError(VWSError): # See https://github.com/VWS-Python/vws-python/issues/822. @beartype class RequestQuotaReachedError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'RequestQuotaReached'. """ @beartype class TargetStatusProcessingError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'TargetStatusProcessing'. """ @property def target_id(self) -> str: - """The processing target ID.""" + """ + The processing target ID. + """ path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -72,7 +83,8 @@ def target_id(self) -> str: # This is not simulated by the mock. @beartype class DateRangeError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'DateRangeError'. """ @@ -80,7 +92,8 @@ class DateRangeError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class TargetQuotaReachedError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'TargetQuotaReached'. """ @@ -88,7 +101,8 @@ class TargetQuotaReachedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectSuspendedError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'ProjectSuspended'. """ @@ -96,41 +110,48 @@ class ProjectSuspendedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectHasNoAPIAccessError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'ProjectHasNoAPIAccess'. """ @beartype class ProjectInactiveError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'ProjectInactive'. """ @beartype class MetadataTooLargeError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'MetadataTooLarge'. """ @beartype class RequestTimeTooSkewedError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ @beartype class TargetNameExistError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'TargetNameExist'. """ @property def target_name(self) -> str: - """The target name which already exists.""" + """ + The target name which already exists. + """ response_body = self.response.request_body or b"" request_json = json.loads(s=response_body) return str(object=request_json["name"]) @@ -138,20 +159,24 @@ def target_name(self) -> str: @beartype class ImageTooLargeError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'ImageTooLarge'. """ @beartype class TargetStatusNotSuccessError(VWSError): - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'TargetStatusNotSuccess'. """ @property def target_id(self) -> str: - """The unknown target ID.""" + """ + The unknown target ID. + """ path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -160,6 +185,7 @@ def target_id(self) -> str: @beartype class TooManyRequestsError(VWSError): # pragma: no cover - """Exception raised when Vuforia returns a response with a result code + """ + Exception raised when Vuforia returns a response with a result code 'TooManyRequests'. """ diff --git a/src/vws/include_target_data.py b/src/vws/include_target_data.py index 0692a1e40..37682e08a 100644 --- a/src/vws/include_target_data.py +++ b/src/vws/include_target_data.py @@ -1,4 +1,6 @@ -"""Tools for managing ``CloudRecoService.query``'s ``include_target_data``.""" +""" +Tools for managing ``CloudRecoService.query``'s ``include_target_data``. +""" from enum import StrEnum, auto, unique diff --git a/src/vws/query.py b/src/vws/query.py index ab449c614..96122aa14 100644 --- a/src/vws/query.py +++ b/src/vws/query.py @@ -1,4 +1,6 @@ -"""Tools for interacting with the Vuforia Cloud Recognition Web APIs.""" +""" +Tools for interacting with the Vuforia Cloud Recognition Web APIs. +""" import datetime import io @@ -32,7 +34,9 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """Get the data of an image file.""" + """ + Get the data of an image file. + """ original_tell = image.tell() image.seek(0) image_data = image.read() @@ -42,7 +46,9 @@ def _get_image_data(image: _ImageType) -> bytes: @beartype class CloudRecoService: - """An interface to the Vuforia Cloud Recognition Web APIs.""" + """ + An interface to the Vuforia Cloud Recognition Web APIs. + """ def __init__( self, diff --git a/src/vws/reports.py b/src/vws/reports.py index e59408aad..f6a77133c 100644 --- a/src/vws/reports.py +++ b/src/vws/reports.py @@ -1,4 +1,6 @@ -"""Classes for representing Vuforia reports.""" +""" +Classes for representing Vuforia reports. +""" import datetime from dataclasses import dataclass @@ -84,7 +86,9 @@ class TargetRecord: @beartype @dataclass(frozen=True) class TargetData: - """The target data optionally included with a query match.""" + """ + The target data optionally included with a query match. + """ name: str application_metadata: str | None diff --git a/src/vws/response.py b/src/vws/response.py index e2060cb9e..269f2e23f 100644 --- a/src/vws/response.py +++ b/src/vws/response.py @@ -1,4 +1,6 @@ -"""Responses for requests to VWS and VWQ.""" +""" +Responses for requests to VWS and VWQ. +""" from dataclasses import dataclass @@ -8,7 +10,9 @@ @dataclass(frozen=True) @beartype class Response: - """A response from a request.""" + """ + A response from a request. + """ text: str url: str diff --git a/src/vws/vws.py b/src/vws/vws.py index 1191ee7df..8def19ed7 100644 --- a/src/vws/vws.py +++ b/src/vws/vws.py @@ -1,4 +1,6 @@ -"""Tools for interacting with Vuforia APIs.""" +""" +Tools for interacting with Vuforia APIs. +""" import base64 import io @@ -50,7 +52,9 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """Get the data of an image file.""" + """ + Get the data of an image file. + """ original_tell = image.tell() image.seek(0) image_data = image.read() @@ -127,7 +131,9 @@ def _target_api_request( @beartype(conf=BeartypeConf(is_pep484_tower=True)) class VWS: - """An interface to Vuforia Web Services APIs.""" + """ + An interface to Vuforia Web Services APIs. + """ def __init__( self, diff --git a/tests/__init__.py b/tests/__init__.py index 3502d86d5..c7e38a862 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1,3 @@ -"""Tests for ``vws``.""" +""" +Tests for ``vws``. +""" diff --git a/tests/conftest.py b/tests/conftest.py index 7c0647786..74c6fc56d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,6 @@ -"""Configuration, plugins and fixtures for `pytest`.""" +""" +Configuration, plugins and fixtures for `pytest`. +""" import io from collections.abc import Generator @@ -14,7 +16,9 @@ @pytest.fixture(name="_mock_database") def fixture_mock_database() -> Generator[VuforiaDatabase]: - """Yield a mock ``VuforiaDatabase``.""" + """ + Yield a mock ``VuforiaDatabase``. + """ # We use a low processing time so that tests run quickly. with MockVWS(processing_time_seconds=0.2) as mock: database = VuforiaDatabase() @@ -24,7 +28,9 @@ def fixture_mock_database() -> Generator[VuforiaDatabase]: @pytest.fixture def vws_client(_mock_database: VuforiaDatabase) -> VWS: - """A VWS client which connects to a mock database.""" + """ + 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, @@ -33,7 +39,9 @@ def vws_client(_mock_database: VuforiaDatabase) -> VWS: @pytest.fixture def cloud_reco_client(_mock_database: VuforiaDatabase) -> CloudRecoService: - """A ``CloudRecoService`` client which connects to a mock database.""" + """ + A ``CloudRecoService`` client which connects to a mock database. + """ return CloudRecoService( client_access_key=_mock_database.client_access_key, client_secret_key=_mock_database.client_secret_key, @@ -46,7 +54,9 @@ def fixture_image_file( tmp_path: Path, request: pytest.FixtureRequest, ) -> Generator[BinaryIO]: - """An image file object.""" + """ + An image file object. + """ file = tmp_path / "image.jpg" buffer = high_quality_image.getvalue() file.write_bytes(data=buffer) @@ -61,7 +71,9 @@ def image( high_quality_image: io.BytesIO, image_file: BinaryIO, ) -> io.BytesIO | BinaryIO: - """An image in any of the types that the API accepts.""" + """ + An image in any of the types that the API accepts. + """ if request.param == "high_quality_image": return high_quality_image return image_file diff --git a/tests/test_cloud_reco_exceptions.py b/tests/test_cloud_reco_exceptions.py index d4c8cb0f7..3515b0d22 100644 --- a/tests/test_cloud_reco_exceptions.py +++ b/tests/test_cloud_reco_exceptions.py @@ -1,4 +1,6 @@ -"""Tests for exceptions raised when using the CloudRecoService.""" +""" +Tests for exceptions raised when using the CloudRecoService. +""" import io import uuid @@ -61,7 +63,9 @@ def test_image_too_large( def test_cloudrecoexception_inheritance() -> None: - """CloudRecoService-specific exceptions inherit from CloudRecoException.""" + """ + CloudRecoService-specific exceptions inherit from CloudRecoException. + """ subclasses = [ MaxNumResultsOutOfRangeError, InactiveProjectError, diff --git a/tests/test_query.py b/tests/test_query.py index 11b803eb5..e229cf95d 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -1,4 +1,6 @@ -"""Tests for the ``CloudRecoService`` querying functionality.""" +""" +Tests for the ``CloudRecoService`` querying functionality. +""" import io import uuid @@ -12,14 +14,18 @@ class TestQuery: - """Tests for making image queries.""" + """ + Tests for making image queries. + """ @staticmethod def test_no_matches( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """An empty list is returned if there are no matches.""" + """ + An empty list is returned if there are no matches. + """ result = cloud_reco_client.query(image=image) assert result == [] @@ -29,7 +35,9 @@ def test_match( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """Details of matching targets are returned.""" + """ + Details of matching targets are returned. + """ target_id = vws_client.add_target( name="x", width=1, @@ -43,7 +51,9 @@ def test_match( class TestCustomBaseVWQURL: - """Tests for using a custom base VWQ URL.""" + """ + Tests for using a custom base VWQ URL. + """ @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -83,7 +93,9 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestMaxNumResults: - """Tests for the ``max_num_results`` parameter of ``query``.""" + """ + Tests for the ``max_num_results`` parameter of ``query``. + """ @staticmethod def test_default( @@ -91,7 +103,9 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """By default the maximum number of results is 1.""" + """ + By default the maximum number of results is 1. + """ target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -117,7 +131,9 @@ def test_custom( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to set a custom ``max_num_results``.""" + """ + It is possible to set a custom ``max_num_results``. + """ target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -151,7 +167,9 @@ def test_custom( class TestIncludeTargetData: - """Tests for the ``include_target_data`` parameter of ``query``.""" + """ + Tests for the ``include_target_data`` parameter of ``query``. + """ @staticmethod def test_default( @@ -159,7 +177,9 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """By default, target data is only returned in the top match.""" + """ + By default, target data is only returned in the top match. + """ target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, diff --git a/tests/test_vws.py b/tests/test_vws.py index d427e1c9b..e16eff555 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -1,4 +1,6 @@ -"""Tests for helper functions for managing a Vuforia database.""" +""" +Tests for helper functions for managing a Vuforia database. +""" import base64 import datetime @@ -23,7 +25,9 @@ class TestAddTarget: - """Tests for adding a target.""" + """ + Tests for adding a target. + """ @staticmethod @pytest.mark.parametrize( @@ -39,7 +43,9 @@ def test_add_target( *, active_flag: bool, ) -> None: - """No exception is raised when adding one target.""" + """ + No exception is raised when adding one target. + """ name = "x" width = 1 if application_metadata is None: @@ -92,7 +98,9 @@ def test_add_two_targets( class TestCustomBaseVWSURL: - """Tests for using a custom base VWS URL.""" + """ + Tests for using a custom base VWS URL. + """ @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -120,14 +128,18 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestListTargets: - """Tests for listing targets.""" + """ + Tests for listing targets. + """ @staticmethod def test_list_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to get a list of target IDs.""" + """ + It is possible to get a list of target IDs. + """ id_1 = vws_client.add_target( name="x", width=1, @@ -146,14 +158,18 @@ def test_list_targets( class TestDelete: - """Test for deleting a target.""" + """ + Test for deleting a target. + """ @staticmethod def test_delete_target( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to delete a target.""" + """ + It is possible to delete a target. + """ target_id = vws_client.add_target( name="x", width=1, @@ -169,14 +185,18 @@ def test_delete_target( class TestGetTargetSummaryReport: - """Tests for getting a summary report for a target.""" + """ + Tests for getting a summary report for a target. + """ @staticmethod def test_get_target_summary_report( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """Details of a target are returned by ``get_target_summary_report``.""" + """ + Details of a target are returned by ``get_target_summary_report``. + """ date = "2018-04-25" target_name = uuid.uuid4().hex with freeze_time(time_to_freeze=date): @@ -220,11 +240,15 @@ def test_get_target_summary_report( class TestGetDatabaseSummaryReport: - """Tests for getting a summary report for a database.""" + """ + Tests for getting a summary report for a database. + """ @staticmethod def test_get_target(vws_client: VWS) -> None: - """Details of a database are returned by ``get_database_summary_report``.""" + """ + Details of a database are returned by ``get_database_summary_report``. + """ report = vws_client.get_database_summary_report() expected_report = DatabaseSummaryReport( @@ -263,14 +287,18 @@ def test_get_target(vws_client: VWS) -> None: class TestGetTargetRecord: - """Tests for getting a record of a target.""" + """ + Tests for getting a record of a target. + """ @staticmethod def test_get_target_record( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """Details of a target are returned by ``get_target_record``.""" + """ + Details of a target are returned by ``get_target_record``. + """ target_id = vws_client.add_target( name="x", width=1, @@ -316,7 +344,9 @@ def test_get_failed( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """Check that the report works with a failed target.""" + """ + Check that the report works with a failed target. + """ target_id = vws_client.add_target( name="x", width=1, @@ -332,14 +362,18 @@ def test_get_failed( class TestWaitForTargetProcessed: - """Tests for waiting for a target to be processed.""" + """ + Tests for waiting for a target to be processed. + """ @staticmethod def test_wait_for_target_processed( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to wait until a target is processed.""" + """ + It is possible to wait until a target is processed. + """ target_id = vws_client.add_target( name="x", width=1, @@ -357,7 +391,9 @@ def test_wait_for_target_processed( def test_default_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """By default, 0.2 seconds are waited between polling requests.""" + """ + By default, 0.2 seconds are waited between polling requests. + """ with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -407,7 +443,9 @@ def test_default_seconds_between_requests( def test_custom_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to customize the time waited between polling requests.""" + """ + It is possible to customize the time waited between polling requests. + """ with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -455,7 +493,9 @@ def test_custom_seconds_between_requests( @staticmethod def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: - """It is possible to set a maximum timeout.""" + """ + It is possible to set a maximum timeout. + """ with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -491,14 +531,18 @@ def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: class TestGetDuplicateTargets: - """Tests for getting duplicate targets.""" + """ + Tests for getting duplicate targets. + """ @staticmethod def test_get_duplicate_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to get the IDs of similar targets.""" + """ + It is possible to get the IDs of similar targets. + """ target_id = vws_client.add_target( name="x", width=1, @@ -521,7 +565,9 @@ def test_get_duplicate_targets( class TestUpdateTarget: - """Tests for updating a target.""" + """ + Tests for updating a target. + """ @staticmethod def test_update_target( @@ -530,7 +576,9 @@ def test_update_target( different_high_quality_image: io.BytesIO, cloud_reco_client: CloudRecoService, ) -> None: - """It is possible to update a target.""" + """ + It is possible to update a target. + """ old_name = uuid.uuid4().hex old_width = secrets.choice(seq=range(1, 5000)) / 100 target_id = vws_client.add_target( @@ -587,7 +635,9 @@ def test_no_fields_given( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to give no update fields.""" + """ + It is possible to give no update fields. + """ target_id = vws_client.add_target( name="x", width=1, diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index eb5b12a6f..86da66040 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -1,4 +1,6 @@ -"""Tests for VWS exceptions.""" +""" +Tests for VWS exceptions. +""" import io import uuid @@ -96,7 +98,9 @@ def test_request_quota_reached() -> None: def test_fail(high_quality_image: io.BytesIO) -> None: - """A ``Fail`` exception is raised when the server access key does not exist.""" + """ + A ``Fail`` exception is raised when the server access key does not exist. + """ with MockVWS(): vws_client = VWS( server_access_key=uuid.uuid4().hex, @@ -116,7 +120,9 @@ def test_fail(high_quality_image: io.BytesIO) -> None: def test_bad_image(vws_client: VWS) -> None: - """A ``BadImage`` exception is raised when a non-image is given.""" + """ + A ``BadImage`` exception is raised when a non-image is given. + """ not_an_image = io.BytesIO(initial_bytes=b"Not an image") with pytest.raises(expected_exception=BadImageError) as exc: vws_client.add_target( @@ -319,7 +325,9 @@ def test_target_status_not_success( def test_vwsexception_inheritance() -> None: - """VWS-related exceptions should inherit from VWSException.""" + """ + VWS-related exceptions should inherit from VWSException. + """ subclasses = [ AuthenticationFailureError, BadImageError, @@ -346,7 +354,9 @@ def test_base_exception( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """``VWSException``s has a response property.""" + """ + ``VWSException``s has a response property. + """ with pytest.raises(expected_exception=VWSError) as exc: vws_client.get_target_record(target_id="a") From 848686798b4cd9b7617d973b77ef25fbdc69c10a 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, 12 Jan 2026 14:27:40 +0000 Subject: [PATCH 05/13] [pre-commit.ci lite] apply automatic fixes --- conftest.py | 8 +- docs/source/__init__.py | 4 +- docs/source/conf.py | 4 +- src/vws/__init__.py | 4 +- src/vws/exceptions/__init__.py | 4 +- src/vws/exceptions/base_exceptions.py | 12 +-- src/vws/exceptions/cloud_reco_exceptions.py | 16 +--- src/vws/exceptions/custom_exceptions.py | 20 +--- src/vws/exceptions/vws_exceptions.py | 68 ++++--------- src/vws/include_target_data.py | 4 +- src/vws/query.py | 12 +-- src/vws/reports.py | 8 +- src/vws/response.py | 8 +- src/vws/vws.py | 12 +-- tests/__init__.py | 4 +- tests/conftest.py | 24 ++--- tests/test_cloud_reco_exceptions.py | 8 +- tests/test_query.py | 40 ++------ tests/test_vws.py | 100 +++++--------------- tests/test_vws_exceptions.py | 20 +--- 20 files changed, 100 insertions(+), 280 deletions(-) diff --git a/conftest.py b/conftest.py index 1d776f8db..0e579a4db 100644 --- a/conftest.py +++ b/conftest.py @@ -1,6 +1,4 @@ -""" -Setup for Sybil. -""" +"""Setup for Sybil.""" import io import uuid @@ -21,9 +19,7 @@ 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: if isinstance(item, pytest.Function): item.obj = beartype(obj=item.obj) diff --git a/docs/source/__init__.py b/docs/source/__init__.py index b63eed5fb..535ceb2ec 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 914bcb886..920ba1a4b 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.""" import importlib.metadata from pathlib import Path diff --git a/src/vws/__init__.py b/src/vws/__init__.py index 42788b92d..bfd96d6c2 100644 --- a/src/vws/__init__.py +++ b/src/vws/__init__.py @@ -1,6 +1,4 @@ -""" -A library for Vuforia Web Services. -""" +"""A library for Vuforia Web Services.""" from .query import CloudRecoService from .vws import VWS diff --git a/src/vws/exceptions/__init__.py b/src/vws/exceptions/__init__.py index a1e3cd91c..7260ffdbb 100644 --- a/src/vws/exceptions/__init__.py +++ b/src/vws/exceptions/__init__.py @@ -1,3 +1 @@ -""" -Custom exceptions raised by this package. -""" +"""Custom exceptions raised by this package.""" diff --git a/src/vws/exceptions/base_exceptions.py b/src/vws/exceptions/base_exceptions.py index 943323bfd..c86080593 100644 --- a/src/vws/exceptions/base_exceptions.py +++ b/src/vws/exceptions/base_exceptions.py @@ -10,9 +10,7 @@ @beartype class CloudRecoError(Exception): - """ - Base class for Vuforia Cloud Recognition Web API exceptions. - """ + """Base class for Vuforia Cloud Recognition Web API exceptions.""" def __init__(self, response: Response) -> None: """ @@ -24,9 +22,7 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response @@ -48,7 +44,5 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response diff --git a/src/vws/exceptions/cloud_reco_exceptions.py b/src/vws/exceptions/cloud_reco_exceptions.py index ff5dde209..2b20a7220 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,6 +1,4 @@ -""" -Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs. -""" +"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs.""" from beartype import beartype @@ -17,31 +15,27 @@ class MaxNumResultsOutOfRangeError(CloudRecoError): @beartype class InactiveProjectError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'InactiveProject'. """ @beartype class BadImageError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @beartype class RequestTimeTooSkewedError(CloudRecoError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index 694e98c30..466dfd1cd 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -11,9 +11,7 @@ @beartype class RequestEntityTooLargeError(Exception): - """ - Exception raised when the given image is too large. - """ + """Exception raised when the given image is too large.""" def __init__(self, response: Response) -> None: """ @@ -25,24 +23,18 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response @beartype class TargetProcessingTimeoutError(Exception): - """ - Exception raised when waiting for a target to be processed times out. - """ + """Exception raised when waiting for a target to be processed times out.""" @beartype class ServerError(Exception): # pragma: no cover - """ - Exception raised when VWS returns a server error. - """ + """Exception raised when VWS returns a server error.""" def __init__(self, response: Response) -> None: """ @@ -54,7 +46,5 @@ def __init__(self, response: Response) -> None: @property def response(self) -> Response: - """ - The response returned by Vuforia which included this error. - """ + """The response returned by Vuforia which included this error.""" return self._response diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index 482223766..a25c2261b 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -14,16 +14,13 @@ @beartype class UnknownTargetError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'UnknownTarget'. """ @property def target_id(self) -> str: - """ - The unknown target ID. - """ + """The unknown target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -32,23 +29,19 @@ def target_id(self) -> str: @beartype class FailError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code 'Fail'. - """ + """Exception raised when Vuforia returns a response with a result code 'Fail'.""" @beartype class BadImageError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @beartype class AuthenticationFailureError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @@ -56,24 +49,20 @@ class AuthenticationFailureError(VWSError): # See https://github.com/VWS-Python/vws-python/issues/822. @beartype class RequestQuotaReachedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestQuotaReached'. """ @beartype class TargetStatusProcessingError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetStatusProcessing'. """ @property def target_id(self) -> str: - """ - The processing target ID. - """ + """The processing target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -83,8 +72,7 @@ def target_id(self) -> str: # This is not simulated by the mock. @beartype class DateRangeError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'DateRangeError'. """ @@ -92,8 +80,7 @@ class DateRangeError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class TargetQuotaReachedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetQuotaReached'. """ @@ -101,8 +88,7 @@ class TargetQuotaReachedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectSuspendedError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectSuspended'. """ @@ -110,48 +96,41 @@ class ProjectSuspendedError(VWSError): # pragma: no cover # This is not simulated by the mock. @beartype class ProjectHasNoAPIAccessError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectHasNoAPIAccess'. """ @beartype class ProjectInactiveError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectInactive'. """ @beartype class MetadataTooLargeError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'MetadataTooLarge'. """ @beartype class RequestTimeTooSkewedError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ @beartype class TargetNameExistError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetNameExist'. """ @property def target_name(self) -> str: - """ - The target name which already exists. - """ + """The target name which already exists.""" response_body = self.response.request_body or b"" request_json = json.loads(s=response_body) return str(object=request_json["name"]) @@ -159,24 +138,20 @@ def target_name(self) -> str: @beartype class ImageTooLargeError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ImageTooLarge'. """ @beartype class TargetStatusNotSuccessError(VWSError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetStatusNotSuccess'. """ @property def target_id(self) -> str: - """ - The unknown target ID. - """ + """The unknown target ID.""" path = urlparse(url=self.response.url).path # Every HTTP path which can raise this error is in the format # `/something/{target_id}`. @@ -185,7 +160,6 @@ def target_id(self) -> str: @beartype class TooManyRequestsError(VWSError): # pragma: no cover - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TooManyRequests'. """ diff --git a/src/vws/include_target_data.py b/src/vws/include_target_data.py index 37682e08a..0692a1e40 100644 --- a/src/vws/include_target_data.py +++ b/src/vws/include_target_data.py @@ -1,6 +1,4 @@ -""" -Tools for managing ``CloudRecoService.query``'s ``include_target_data``. -""" +"""Tools for managing ``CloudRecoService.query``'s ``include_target_data``.""" from enum import StrEnum, auto, unique diff --git a/src/vws/query.py b/src/vws/query.py index 96122aa14..ab449c614 100644 --- a/src/vws/query.py +++ b/src/vws/query.py @@ -1,6 +1,4 @@ -""" -Tools for interacting with the Vuforia Cloud Recognition Web APIs. -""" +"""Tools for interacting with the Vuforia Cloud Recognition Web APIs.""" import datetime import io @@ -34,9 +32,7 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """ - Get the data of an image file. - """ + """Get the data of an image file.""" original_tell = image.tell() image.seek(0) image_data = image.read() @@ -46,9 +42,7 @@ def _get_image_data(image: _ImageType) -> bytes: @beartype class CloudRecoService: - """ - An interface to the Vuforia Cloud Recognition Web APIs. - """ + """An interface to the Vuforia Cloud Recognition Web APIs.""" def __init__( self, diff --git a/src/vws/reports.py b/src/vws/reports.py index f6a77133c..e59408aad 100644 --- a/src/vws/reports.py +++ b/src/vws/reports.py @@ -1,6 +1,4 @@ -""" -Classes for representing Vuforia reports. -""" +"""Classes for representing Vuforia reports.""" import datetime from dataclasses import dataclass @@ -86,9 +84,7 @@ class TargetRecord: @beartype @dataclass(frozen=True) class TargetData: - """ - The target data optionally included with a query match. - """ + """The target data optionally included with a query match.""" name: str application_metadata: str | None diff --git a/src/vws/response.py b/src/vws/response.py index 269f2e23f..e2060cb9e 100644 --- a/src/vws/response.py +++ b/src/vws/response.py @@ -1,6 +1,4 @@ -""" -Responses for requests to VWS and VWQ. -""" +"""Responses for requests to VWS and VWQ.""" from dataclasses import dataclass @@ -10,9 +8,7 @@ @dataclass(frozen=True) @beartype class Response: - """ - A response from a request. - """ + """A response from a request.""" text: str url: str diff --git a/src/vws/vws.py b/src/vws/vws.py index 8def19ed7..1191ee7df 100644 --- a/src/vws/vws.py +++ b/src/vws/vws.py @@ -1,6 +1,4 @@ -""" -Tools for interacting with Vuforia APIs. -""" +"""Tools for interacting with Vuforia APIs.""" import base64 import io @@ -52,9 +50,7 @@ @beartype def _get_image_data(image: _ImageType) -> bytes: - """ - Get the data of an image file. - """ + """Get the data of an image file.""" original_tell = image.tell() image.seek(0) image_data = image.read() @@ -131,9 +127,7 @@ def _target_api_request( @beartype(conf=BeartypeConf(is_pep484_tower=True)) class VWS: - """ - An interface to Vuforia Web Services APIs. - """ + """An interface to Vuforia Web Services APIs.""" def __init__( self, diff --git a/tests/__init__.py b/tests/__init__.py index c7e38a862..3502d86d5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1 @@ -""" -Tests for ``vws``. -""" +"""Tests for ``vws``.""" diff --git a/tests/conftest.py b/tests/conftest.py index 74c6fc56d..7c0647786 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,4 @@ -""" -Configuration, plugins and fixtures for `pytest`. -""" +"""Configuration, plugins and fixtures for `pytest`.""" import io from collections.abc import Generator @@ -16,9 +14,7 @@ @pytest.fixture(name="_mock_database") def fixture_mock_database() -> Generator[VuforiaDatabase]: - """ - Yield a mock ``VuforiaDatabase``. - """ + """Yield a mock ``VuforiaDatabase``.""" # We use a low processing time so that tests run quickly. with MockVWS(processing_time_seconds=0.2) as mock: database = VuforiaDatabase() @@ -28,9 +24,7 @@ def fixture_mock_database() -> Generator[VuforiaDatabase]: @pytest.fixture def vws_client(_mock_database: VuforiaDatabase) -> VWS: - """ - A VWS client which connects to a mock database. - """ + """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, @@ -39,9 +33,7 @@ def vws_client(_mock_database: VuforiaDatabase) -> VWS: @pytest.fixture def cloud_reco_client(_mock_database: VuforiaDatabase) -> CloudRecoService: - """ - A ``CloudRecoService`` client which connects to a mock database. - """ + """A ``CloudRecoService`` client which connects to a mock database.""" return CloudRecoService( client_access_key=_mock_database.client_access_key, client_secret_key=_mock_database.client_secret_key, @@ -54,9 +46,7 @@ def fixture_image_file( tmp_path: Path, request: pytest.FixtureRequest, ) -> Generator[BinaryIO]: - """ - An image file object. - """ + """An image file object.""" file = tmp_path / "image.jpg" buffer = high_quality_image.getvalue() file.write_bytes(data=buffer) @@ -71,9 +61,7 @@ def image( high_quality_image: io.BytesIO, image_file: BinaryIO, ) -> io.BytesIO | BinaryIO: - """ - An image in any of the types that the API accepts. - """ + """An image in any of the types that the API accepts.""" if request.param == "high_quality_image": return high_quality_image return image_file diff --git a/tests/test_cloud_reco_exceptions.py b/tests/test_cloud_reco_exceptions.py index 3515b0d22..d4c8cb0f7 100644 --- a/tests/test_cloud_reco_exceptions.py +++ b/tests/test_cloud_reco_exceptions.py @@ -1,6 +1,4 @@ -""" -Tests for exceptions raised when using the CloudRecoService. -""" +"""Tests for exceptions raised when using the CloudRecoService.""" import io import uuid @@ -63,9 +61,7 @@ def test_image_too_large( def test_cloudrecoexception_inheritance() -> None: - """ - CloudRecoService-specific exceptions inherit from CloudRecoException. - """ + """CloudRecoService-specific exceptions inherit from CloudRecoException.""" subclasses = [ MaxNumResultsOutOfRangeError, InactiveProjectError, diff --git a/tests/test_query.py b/tests/test_query.py index e229cf95d..11b803eb5 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -1,6 +1,4 @@ -""" -Tests for the ``CloudRecoService`` querying functionality. -""" +"""Tests for the ``CloudRecoService`` querying functionality.""" import io import uuid @@ -14,18 +12,14 @@ class TestQuery: - """ - Tests for making image queries. - """ + """Tests for making image queries.""" @staticmethod def test_no_matches( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - An empty list is returned if there are no matches. - """ + """An empty list is returned if there are no matches.""" result = cloud_reco_client.query(image=image) assert result == [] @@ -35,9 +29,7 @@ def test_match( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of matching targets are returned. - """ + """Details of matching targets are returned.""" target_id = vws_client.add_target( name="x", width=1, @@ -51,9 +43,7 @@ def test_match( class TestCustomBaseVWQURL: - """ - Tests for using a custom base VWQ URL. - """ + """Tests for using a custom base VWQ URL.""" @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -93,9 +83,7 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestMaxNumResults: - """ - Tests for the ``max_num_results`` parameter of ``query``. - """ + """Tests for the ``max_num_results`` parameter of ``query``.""" @staticmethod def test_default( @@ -103,9 +91,7 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - By default the maximum number of results is 1. - """ + """By default the maximum number of results is 1.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -131,9 +117,7 @@ def test_custom( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to set a custom ``max_num_results``. - """ + """It is possible to set a custom ``max_num_results``.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -167,9 +151,7 @@ def test_custom( class TestIncludeTargetData: - """ - Tests for the ``include_target_data`` parameter of ``query``. - """ + """Tests for the ``include_target_data`` parameter of ``query``.""" @staticmethod def test_default( @@ -177,9 +159,7 @@ def test_default( cloud_reco_client: CloudRecoService, image: io.BytesIO | BinaryIO, ) -> None: - """ - By default, target data is only returned in the top match. - """ + """By default, target data is only returned in the top match.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, diff --git a/tests/test_vws.py b/tests/test_vws.py index e16eff555..d427e1c9b 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -1,6 +1,4 @@ -""" -Tests for helper functions for managing a Vuforia database. -""" +"""Tests for helper functions for managing a Vuforia database.""" import base64 import datetime @@ -25,9 +23,7 @@ class TestAddTarget: - """ - Tests for adding a target. - """ + """Tests for adding a target.""" @staticmethod @pytest.mark.parametrize( @@ -43,9 +39,7 @@ def test_add_target( *, active_flag: bool, ) -> None: - """ - No exception is raised when adding one target. - """ + """No exception is raised when adding one target.""" name = "x" width = 1 if application_metadata is None: @@ -98,9 +92,7 @@ def test_add_two_targets( class TestCustomBaseVWSURL: - """ - Tests for using a custom base VWS URL. - """ + """Tests for using a custom base VWS URL.""" @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: @@ -128,18 +120,14 @@ def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: class TestListTargets: - """ - Tests for listing targets. - """ + """Tests for listing targets.""" @staticmethod def test_list_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to get a list of target IDs. - """ + """It is possible to get a list of target IDs.""" id_1 = vws_client.add_target( name="x", width=1, @@ -158,18 +146,14 @@ def test_list_targets( class TestDelete: - """ - Test for deleting a target. - """ + """Test for deleting a target.""" @staticmethod def test_delete_target( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to delete a target. - """ + """It is possible to delete a target.""" target_id = vws_client.add_target( name="x", width=1, @@ -185,18 +169,14 @@ def test_delete_target( class TestGetTargetSummaryReport: - """ - Tests for getting a summary report for a target. - """ + """Tests for getting a summary report for a target.""" @staticmethod def test_get_target_summary_report( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of a target are returned by ``get_target_summary_report``. - """ + """Details of a target are returned by ``get_target_summary_report``.""" date = "2018-04-25" target_name = uuid.uuid4().hex with freeze_time(time_to_freeze=date): @@ -240,15 +220,11 @@ def test_get_target_summary_report( class TestGetDatabaseSummaryReport: - """ - Tests for getting a summary report for a database. - """ + """Tests for getting a summary report for a database.""" @staticmethod def test_get_target(vws_client: VWS) -> None: - """ - Details of a database are returned by ``get_database_summary_report``. - """ + """Details of a database are returned by ``get_database_summary_report``.""" report = vws_client.get_database_summary_report() expected_report = DatabaseSummaryReport( @@ -287,18 +263,14 @@ def test_get_target(vws_client: VWS) -> None: class TestGetTargetRecord: - """ - Tests for getting a record of a target. - """ + """Tests for getting a record of a target.""" @staticmethod def test_get_target_record( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - Details of a target are returned by ``get_target_record``. - """ + """Details of a target are returned by ``get_target_record``.""" target_id = vws_client.add_target( name="x", width=1, @@ -344,9 +316,7 @@ def test_get_failed( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - Check that the report works with a failed target. - """ + """Check that the report works with a failed target.""" target_id = vws_client.add_target( name="x", width=1, @@ -362,18 +332,14 @@ def test_get_failed( class TestWaitForTargetProcessed: - """ - Tests for waiting for a target to be processed. - """ + """Tests for waiting for a target to be processed.""" @staticmethod def test_wait_for_target_processed( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to wait until a target is processed. - """ + """It is possible to wait until a target is processed.""" target_id = vws_client.add_target( name="x", width=1, @@ -391,9 +357,7 @@ def test_wait_for_target_processed( def test_default_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """ - By default, 0.2 seconds are waited between polling requests. - """ + """By default, 0.2 seconds are waited between polling requests.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -443,9 +407,7 @@ def test_default_seconds_between_requests( def test_custom_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to customize the time waited between polling requests. - """ + """It is possible to customize the time waited between polling requests.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -493,9 +455,7 @@ def test_custom_seconds_between_requests( @staticmethod def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: - """ - It is possible to set a maximum timeout. - """ + """It is possible to set a maximum timeout.""" with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) @@ -531,18 +491,14 @@ def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None: class TestGetDuplicateTargets: - """ - Tests for getting duplicate targets. - """ + """Tests for getting duplicate targets.""" @staticmethod def test_get_duplicate_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to get the IDs of similar targets. - """ + """It is possible to get the IDs of similar targets.""" target_id = vws_client.add_target( name="x", width=1, @@ -565,9 +521,7 @@ def test_get_duplicate_targets( class TestUpdateTarget: - """ - Tests for updating a target. - """ + """Tests for updating a target.""" @staticmethod def test_update_target( @@ -576,9 +530,7 @@ def test_update_target( different_high_quality_image: io.BytesIO, cloud_reco_client: CloudRecoService, ) -> None: - """ - It is possible to update a target. - """ + """It is possible to update a target.""" old_name = uuid.uuid4().hex old_width = secrets.choice(seq=range(1, 5000)) / 100 target_id = vws_client.add_target( @@ -635,9 +587,7 @@ def test_no_fields_given( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """ - It is possible to give no update fields. - """ + """It is possible to give no update fields.""" target_id = vws_client.add_target( name="x", width=1, diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index 86da66040..eb5b12a6f 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -1,6 +1,4 @@ -""" -Tests for VWS exceptions. -""" +"""Tests for VWS exceptions.""" import io import uuid @@ -98,9 +96,7 @@ def test_request_quota_reached() -> None: def test_fail(high_quality_image: io.BytesIO) -> None: - """ - A ``Fail`` exception is raised when the server access key does not exist. - """ + """A ``Fail`` exception is raised when the server access key does not exist.""" with MockVWS(): vws_client = VWS( server_access_key=uuid.uuid4().hex, @@ -120,9 +116,7 @@ def test_fail(high_quality_image: io.BytesIO) -> None: def test_bad_image(vws_client: VWS) -> None: - """ - A ``BadImage`` exception is raised when a non-image is given. - """ + """A ``BadImage`` exception is raised when a non-image is given.""" not_an_image = io.BytesIO(initial_bytes=b"Not an image") with pytest.raises(expected_exception=BadImageError) as exc: vws_client.add_target( @@ -325,9 +319,7 @@ def test_target_status_not_success( def test_vwsexception_inheritance() -> None: - """ - VWS-related exceptions should inherit from VWSException. - """ + """VWS-related exceptions should inherit from VWSException.""" subclasses = [ AuthenticationFailureError, BadImageError, @@ -354,9 +346,7 @@ def test_base_exception( vws_client: VWS, high_quality_image: io.BytesIO, ) -> None: - """ - ``VWSException``s has a response property. - """ + """``VWSException``s has a response property.""" with pytest.raises(expected_exception=VWSError) as exc: vws_client.get_target_record(target_id="a") From 0ed9be617a157ece3114f783b3d9a5bbfbb9380b Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 09:26:34 +0000 Subject: [PATCH 06/13] Linewrap with pydocstringformatter --- pyproject.toml | 2 ++ src/vws/exceptions/cloud_reco_exceptions.py | 4 +++- src/vws/exceptions/custom_exceptions.py | 7 +++++-- src/vws/exceptions/vws_exceptions.py | 7 +++++-- tests/test_cloud_reco_exceptions.py | 7 +++++-- tests/test_query.py | 9 ++++++--- tests/test_vws.py | 12 +++++++++--- tests/test_vws_exceptions.py | 19 +++++++++++++------ 8 files changed, 48 insertions(+), 19 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index d4a6cbd29..3998bc1a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -346,6 +346,8 @@ typeCheckingMode = "strict" [tool.pydocstringformatter] write = true split-summary-body = false +max-line-length = 79 +linewrap-full-docstring = true [tool.interrogate] fail-under = 100 diff --git a/src/vws/exceptions/cloud_reco_exceptions.py b/src/vws/exceptions/cloud_reco_exceptions.py index 2b20a7220..a59335f14 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,4 +1,6 @@ -"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web APIs.""" +"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web +APIs. +""" from beartype import beartype diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index 466dfd1cd..e06c20a19 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -1,6 +1,7 @@ """ Exceptions which do not map to errors at -https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes +https://developer.vuforia.com/library/web-api/cloud-targets-web-services- +api#result-codes or simple errors given by the cloud recognition service. """ @@ -29,7 +30,9 @@ def response(self) -> Response: @beartype class TargetProcessingTimeoutError(Exception): - """Exception raised when waiting for a target to be processed times out.""" + """Exception raised when waiting for a target to be processed times + out. + """ @beartype diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index a25c2261b..892f6e12f 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -1,7 +1,8 @@ """ Exception raised when Vuforia returns a response with a result code matching one of those documented at -https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes. +https://developer.vuforia.com/library/web-api/cloud-targets-web-services- +api#result-codes. """ import json @@ -29,7 +30,9 @@ def target_id(self) -> str: @beartype class FailError(VWSError): - """Exception raised when Vuforia returns a response with a result code 'Fail'.""" + """Exception raised when Vuforia returns a response with a result code + 'Fail'. + """ @beartype diff --git a/tests/test_cloud_reco_exceptions.py b/tests/test_cloud_reco_exceptions.py index d4c8cb0f7..a9e25338f 100644 --- a/tests/test_cloud_reco_exceptions.py +++ b/tests/test_cloud_reco_exceptions.py @@ -61,7 +61,9 @@ def test_image_too_large( def test_cloudrecoexception_inheritance() -> None: - """CloudRecoService-specific exceptions inherit from CloudRecoException.""" + """CloudRecoService-specific exceptions inherit from + CloudRecoException. + """ subclasses = [ MaxNumResultsOutOfRangeError, InactiveProjectError, @@ -77,7 +79,8 @@ def test_authentication_failure( high_quality_image: io.BytesIO, ) -> None: """ - An ``AuthenticationFailure`` exception is raised when the client access key + An ``AuthenticationFailure`` exception is raised when the client access + key exists but the client secret key is incorrect. """ database = VuforiaDatabase() diff --git a/tests/test_query.py b/tests/test_query.py index 11b803eb5..10fff3a8c 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -48,7 +48,8 @@ class TestCustomBaseVWQURL: @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: """ - It is possible to use query a target to a database under a custom VWQ + It is possible to use query a target to a database under a custom + VWQ URL. """ base_vwq_url = "http://example.com" @@ -190,7 +191,8 @@ def test_top( image: io.BytesIO | BinaryIO, ) -> None: """ - When ``CloudRecoIncludeTargetData.TOP`` is given, target data is only + When ``CloudRecoIncludeTargetData.TOP`` is given, target data is + only returned in the top match. """ target_id = vws_client.add_target( @@ -224,7 +226,8 @@ def test_none( image: io.BytesIO | BinaryIO, ) -> None: """ - When ``CloudRecoIncludeTargetData.NONE`` is given, target data is not + When ``CloudRecoIncludeTargetData.NONE`` is given, target data is + not returned in any match. """ target_id = vws_client.add_target( diff --git a/tests/test_vws.py b/tests/test_vws.py index d427e1c9b..73d8e1fdf 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -176,7 +176,9 @@ def test_get_target_summary_report( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """Details of a target are returned by ``get_target_summary_report``.""" + """Details of a target are returned by + ``get_target_summary_report``. + """ date = "2018-04-25" target_name = uuid.uuid4().hex with freeze_time(time_to_freeze=date): @@ -224,7 +226,9 @@ class TestGetDatabaseSummaryReport: @staticmethod def test_get_target(vws_client: VWS) -> None: - """Details of a database are returned by ``get_database_summary_report``.""" + """Details of a database are returned by + ``get_database_summary_report``. + """ report = vws_client.get_database_summary_report() expected_report = DatabaseSummaryReport( @@ -407,7 +411,9 @@ def test_default_seconds_between_requests( def test_custom_seconds_between_requests( image: io.BytesIO | BinaryIO, ) -> None: - """It is possible to customize the time waited between polling requests.""" + """It is possible to customize the time waited between polling + requests. + """ with MockVWS(processing_time_seconds=0.5) as mock: database = VuforiaDatabase() mock.add_database(database=database) diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index eb5b12a6f..496243274 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -40,7 +40,8 @@ def test_image_too_large( png_too_large: io.BytesIO | io.BufferedRandom, ) -> None: """ - When giving an image which is too large, an ``ImageTooLarge`` exception is + When giving an image which is too large, an ``ImageTooLarge`` exception + is raised. """ with pytest.raises(expected_exception=ImageTooLargeError) as exc: @@ -69,7 +70,8 @@ def test_invalid_given_id(vws_client: VWS) -> None: def test_add_bad_name(vws_client: VWS, high_quality_image: io.BytesIO) -> None: """ - When a name with a bad character is given, a ``ServerError`` exception is + When a name with a bad character is given, a ``ServerError`` exception + is raised. """ max_char_value = 65535 @@ -96,7 +98,9 @@ def test_request_quota_reached() -> None: def test_fail(high_quality_image: io.BytesIO) -> None: - """A ``Fail`` exception is raised when the server access key does not exist.""" + """A ``Fail`` exception is raised when the server access key does not + exist. + """ with MockVWS(): vws_client = VWS( server_access_key=uuid.uuid4().hex, @@ -135,7 +139,8 @@ def test_target_name_exist( high_quality_image: io.BytesIO, ) -> None: """ - A ``TargetNameExist`` exception is raised after adding two targets with the + A ``TargetNameExist`` exception is raised after adding two targets with + the same name. """ vws_client.add_target( @@ -162,7 +167,8 @@ def test_project_inactive( high_quality_image: io.BytesIO, ) -> None: """ - A ``ProjectInactive`` exception is raised if adding a target to an inactive + A ``ProjectInactive`` exception is raised if adding a target to an + inactive database. """ database = VuforiaDatabase(state=States.PROJECT_INACTIVE) @@ -267,7 +273,8 @@ def test_authentication_failure( high_quality_image: io.BytesIO, ) -> None: """ - An ``AuthenticationFailure`` exception is raised when the server access key + An ``AuthenticationFailure`` exception is raised when the server access + key exists but the server secret key is incorrect, or when a client key is incorrect. """ From e446e04b4352f3d4d1ed82994bec513d0d5cf64d Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 09:50:09 +0000 Subject: [PATCH 07/13] Un-break URLs --- pyproject.toml | 2 +- src/vws/exceptions/custom_exceptions.py | 3 +-- src/vws/exceptions/vws_exceptions.py | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3998bc1a9..a37ece588 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -344,7 +344,7 @@ reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" [tool.pydocstringformatter] -write = true +write = false split-summary-body = false max-line-length = 79 linewrap-full-docstring = true diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index e06c20a19..ff20c1b6d 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -1,7 +1,6 @@ """ Exceptions which do not map to errors at -https://developer.vuforia.com/library/web-api/cloud-targets-web-services- -api#result-codes +https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes or simple errors given by the cloud recognition service. """ diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index 892f6e12f..c68107d00 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -1,8 +1,7 @@ """ Exception raised when Vuforia returns a response with a result code matching one of those documented at -https://developer.vuforia.com/library/web-api/cloud-targets-web-services- -api#result-codes. +https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes. """ import json From 06de28f492912c6c6cea349964fadc130429f89e Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 10:46:10 +0000 Subject: [PATCH 08/13] Work around pydocstringformatter issue --- src/vws/exceptions/custom_exceptions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vws/exceptions/custom_exceptions.py b/src/vws/exceptions/custom_exceptions.py index ff20c1b6d..cf3902264 100644 --- a/src/vws/exceptions/custom_exceptions.py +++ b/src/vws/exceptions/custom_exceptions.py @@ -1,7 +1,7 @@ -""" -Exceptions which do not map to errors at +"""Exceptions which do not map to errors at the following URL, or simple +errors given by the cloud recognition service. + https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes -or simple errors given by the cloud recognition service. """ from beartype import beartype From a820dbdcfabf5fc81a4580e8421dc47f4ea73b98 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 10:50:31 +0000 Subject: [PATCH 09/13] Fix ruff ignore comment --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index a37ece588..77640c0ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,8 +119,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", # Ruff warns that this conflicts with the formatter. From d4fe42e32a2351b9025f0ce53ec04a04dbd712ef Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 10:52:41 +0000 Subject: [PATCH 10/13] Write fixes --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 77640c0ba..32edef2a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -344,7 +344,7 @@ reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" [tool.pydocstringformatter] -write = false +write = true split-summary-body = false max-line-length = 79 linewrap-full-docstring = true From 31dfe8c1839343f38272d5b4f08fa67c3525bc45 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 11:03:05 +0000 Subject: [PATCH 11/13] Re-add D200 to ruff ignores - conflicts with pydocstringformatter at line-length boundary --- pyproject.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 15fb0e3cf..9843058be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,7 +120,9 @@ lint.ignore = [ # Ruff warns that this conflicts with the formatter. "COM812", # Allow our chosen docstring line-style - pydocstringformatter handles formatting - # but doesn't enforce D205 (blank line after summary) or D212 (summary on first line). + # but may conflict with D200 at the line-length boundary, and doesn't enforce + # D205 (blank line after summary) or D212 (summary on first line). + "D200", "D205", "D212", # Ruff warns that this conflicts with the formatter. From 114e0835579deb7d0727a12bb158cefdaa3b235a Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 11:03:51 +0000 Subject: [PATCH 12/13] Remove D200 ignore by lowering pydocstringformatter line length to 75 --- bun.lock | 14 +++++++++++ example.txt | 0 issue.txt | 28 +++++++++++++++++++++ package.json | 6 +++++ pyproject.toml | 9 ++++--- src/vws/exceptions/base_exceptions.py | 3 ++- src/vws/exceptions/cloud_reco_exceptions.py | 3 ++- src/vws/exceptions/vws_exceptions.py | 6 +++-- src/vws/query.py | 3 ++- src/vws/vws.py | 3 ++- tests/test_cloud_reco_exceptions.py | 6 +++-- tests/test_query.py | 6 +++-- tests/test_vws.py | 6 +++-- tests/test_vws_exceptions.py | 27 +++++++++++++------- 14 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 bun.lock create mode 100644 example.txt create mode 100644 issue.txt create mode 100644 package.json diff --git a/bun.lock b/bun.lock new file mode 100644 index 000000000..45f73b81b --- /dev/null +++ b/bun.lock @@ -0,0 +1,14 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "devDependencies": { + "prettier": "3.7.4", + }, + }, + }, + "packages": { + "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], + } +} diff --git a/example.txt b/example.txt new file mode 100644 index 000000000..e69de29bb diff --git a/issue.txt b/issue.txt new file mode 100644 index 000000000..abe88bb9b --- /dev/null +++ b/issue.txt @@ -0,0 +1,28 @@ +URLs are broken when reflowing paragraphs + +## Version + +0.7.3 + +## Example + +Input file: + +```python +"""For more information see https://example.com/documentation/api/v2/reference/getting-started#authentication or contact support.""" +``` + +Output after running `pydocstringformatter --linewrap-full-docstring`: + +```diff +--- issue.py ++++ issue.py +@@ -1,2 +1,5 @@ +-"""For more information see https://example.com/documentation/api/v2/reference/getting-started#authentication or contact support.""" ++"""For more information see https://example.com/documentation/api/v2/reference/getting-. ++ ++started#authentication or contact support. ++""" +``` + +The URL is broken across two lines, making it impossible to click. diff --git a/package.json b/package.json new file mode 100644 index 000000000..71b8ee1ef --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": {}, + "devDependencies": { + "prettier": "3.7.4" + } +} diff --git a/pyproject.toml b/pyproject.toml index 9843058be..55238906d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -120,9 +120,7 @@ lint.ignore = [ # Ruff warns that this conflicts with the formatter. "COM812", # Allow our chosen docstring line-style - pydocstringformatter handles formatting - # but may conflict with D200 at the line-length boundary, and doesn't enforce - # D205 (blank line after summary) or D212 (summary on first line). - "D200", + # but doesn't enforce D205 (blank line after summary) or D212 (summary on first line). "D205", "D212", # Ruff warns that this conflicts with the formatter. @@ -348,7 +346,10 @@ typeCheckingMode = "strict" [tool.pydocstringformatter] write = true split-summary-body = false -max-line-length = 79 +# Use a lower line length than ruff (79) to avoid conflicts with D200 - +# pydocstringformatter would otherwise split docstrings at exactly 79 chars +# which ruff considers should stay on one line. +max-line-length = 75 linewrap-full-docstring = true [tool.interrogate] diff --git a/src/vws/exceptions/base_exceptions.py b/src/vws/exceptions/base_exceptions.py index c86080593..fa031838a 100644 --- a/src/vws/exceptions/base_exceptions.py +++ b/src/vws/exceptions/base_exceptions.py @@ -1,5 +1,6 @@ """ -Base exceptions for errors returned by Vuforia Web Services or the Vuforia +Base exceptions for errors returned by Vuforia Web Services or the +Vuforia Cloud Recognition Web API. """ diff --git a/src/vws/exceptions/cloud_reco_exceptions.py b/src/vws/exceptions/cloud_reco_exceptions.py index a59335f14..b2e3ee67f 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,4 +1,5 @@ -"""Exceptions which match errors raised by the Vuforia Cloud Recognition Web +"""Exceptions which match errors raised by the Vuforia Cloud Recognition +Web APIs. """ diff --git a/src/vws/exceptions/vws_exceptions.py b/src/vws/exceptions/vws_exceptions.py index c68107d00..6b1447577 100644 --- a/src/vws/exceptions/vws_exceptions.py +++ b/src/vws/exceptions/vws_exceptions.py @@ -1,7 +1,9 @@ """ -Exception raised when Vuforia returns a response with a result code matching +Exception raised when Vuforia returns a response with a result code +matching one of those documented at -https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#result-codes. +https://developer.vuforia.com/library/web-api/cloud-targets-web-services- +api#result-codes. """ import json diff --git a/src/vws/query.py b/src/vws/query.py index ab449c614..6c2dc481e 100644 --- a/src/vws/query.py +++ b/src/vws/query.py @@ -68,7 +68,8 @@ def query( CloudRecoIncludeTargetData.TOP ), ) -> list[QueryResult]: - """Use the Vuforia Web Query API to make an Image Recognition Query. + """Use the Vuforia Web Query API to make an Image Recognition + Query. See https://developer.vuforia.com/library/web-api/vuforia-query-web-api diff --git a/src/vws/vws.py b/src/vws/vws.py index 1191ee7df..9b3d19b4e 100644 --- a/src/vws/vws.py +++ b/src/vws/vws.py @@ -567,7 +567,8 @@ def delete_target(self, target_id: str) -> None: ) def get_duplicate_targets(self, target_id: str) -> list[str]: - """Get targets which may be considered duplicates of a given target. + """Get targets which may be considered duplicates of a given + target. See https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#check. diff --git a/tests/test_cloud_reco_exceptions.py b/tests/test_cloud_reco_exceptions.py index a9e25338f..5576f4d40 100644 --- a/tests/test_cloud_reco_exceptions.py +++ b/tests/test_cloud_reco_exceptions.py @@ -49,7 +49,8 @@ def test_image_too_large( png_too_large: io.BytesIO | io.BufferedRandom, ) -> None: """ - A ``RequestEntityTooLarge`` exception is raised if an image which is too + A ``RequestEntityTooLarge`` exception is raised if an image which is + too large is given. """ with pytest.raises(expected_exception=RequestEntityTooLargeError) as exc: @@ -79,7 +80,8 @@ def test_authentication_failure( high_quality_image: io.BytesIO, ) -> None: """ - An ``AuthenticationFailure`` exception is raised when the client access + An ``AuthenticationFailure`` exception is raised when the client + access key exists but the client secret key is incorrect. """ diff --git a/tests/test_query.py b/tests/test_query.py index 10fff3a8c..a79a712c0 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -48,7 +48,8 @@ class TestCustomBaseVWQURL: @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: """ - It is possible to use query a target to a database under a custom + It is possible to use query a target to a database under a + custom VWQ URL. """ @@ -226,7 +227,8 @@ def test_none( image: io.BytesIO | BinaryIO, ) -> None: """ - When ``CloudRecoIncludeTargetData.NONE`` is given, target data is + When ``CloudRecoIncludeTargetData.NONE`` is given, target data + is not returned in any match. """ diff --git a/tests/test_vws.py b/tests/test_vws.py index 73d8e1fdf..00936bde8 100644 --- a/tests/test_vws.py +++ b/tests/test_vws.py @@ -77,7 +77,8 @@ def test_add_two_targets( vws_client: VWS, image: io.BytesIO | BinaryIO, ) -> None: - """No exception is raised when adding two targets with different names. + """No exception is raised when adding two targets with different + names. This demonstrates that the image seek position is not changed. """ @@ -97,7 +98,8 @@ class TestCustomBaseVWSURL: @staticmethod def test_custom_base_url(image: io.BytesIO | BinaryIO) -> None: """ - It is possible to use add a target to a database under a custom VWS + It is possible to use add a target to a database under a custom + VWS URL. """ base_vws_url = "http://example.com" diff --git a/tests/test_vws_exceptions.py b/tests/test_vws_exceptions.py index 496243274..4262b3ea6 100644 --- a/tests/test_vws_exceptions.py +++ b/tests/test_vws_exceptions.py @@ -40,7 +40,8 @@ def test_image_too_large( png_too_large: io.BytesIO | io.BufferedRandom, ) -> None: """ - When giving an image which is too large, an ``ImageTooLarge`` exception + When giving an image which is too large, an ``ImageTooLarge`` + exception is raised. """ @@ -58,7 +59,8 @@ def test_image_too_large( def test_invalid_given_id(vws_client: VWS) -> None: """ - Giving an invalid ID to a helper which requires a target ID to be given + Giving an invalid ID to a helper which requires a target ID to be + given causes an ``UnknownTarget`` exception to be raised. """ target_id = "12345abc" @@ -70,7 +72,8 @@ def test_invalid_given_id(vws_client: VWS) -> None: def test_add_bad_name(vws_client: VWS, high_quality_image: io.BytesIO) -> None: """ - When a name with a bad character is given, a ``ServerError`` exception + When a name with a bad character is given, a ``ServerError`` + exception is raised. """ @@ -139,7 +142,8 @@ def test_target_name_exist( high_quality_image: io.BytesIO, ) -> None: """ - A ``TargetNameExist`` exception is raised after adding two targets with + A ``TargetNameExist`` exception is raised after adding two targets + with the same name. """ @@ -196,7 +200,8 @@ def test_target_status_processing( high_quality_image: io.BytesIO, ) -> None: """ - A ``TargetStatusProcessing`` exception is raised if trying to delete a + A ``TargetStatusProcessing`` exception is raised if trying to delete + a target which is processing. """ target_id = vws_client.add_target( @@ -219,7 +224,8 @@ def test_metadata_too_large( high_quality_image: io.BytesIO, ) -> None: """ - A ``MetadataTooLarge`` exception is raised if the metadata given is too + A ``MetadataTooLarge`` exception is raised if the metadata given is + too large. """ with pytest.raises(expected_exception=MetadataTooLargeError) as exc: @@ -239,7 +245,8 @@ def test_request_time_too_skewed( high_quality_image: io.BytesIO, ) -> None: """ - A ``RequestTimeTooSkewed`` exception is raised when the request time is + A ``RequestTimeTooSkewed`` exception is raised when the request time + is more than five minutes different from the server time. """ target_id = vws_client.add_target( @@ -273,7 +280,8 @@ def test_authentication_failure( high_quality_image: io.BytesIO, ) -> None: """ - An ``AuthenticationFailure`` exception is raised when the server access + An ``AuthenticationFailure`` exception is raised when the server + access key exists but the server secret key is incorrect, or when a client key is incorrect. @@ -307,7 +315,8 @@ def test_target_status_not_success( high_quality_image: io.BytesIO, ) -> None: """ - A ``TargetStatusNotSuccess`` exception is raised when updating a target + A ``TargetStatusNotSuccess`` exception is raised when updating a + target which has a status which is not "Success". """ target_id = vws_client.add_target( From 7f330219e793b08895ff78a54052b950d3fc3254 Mon Sep 17 00:00:00 2001 From: Adam Dangoor Date: Mon, 26 Jan 2026 11:04:20 +0000 Subject: [PATCH 13/13] Remove unrelated test files --- bun.lock | 14 -------------- example.txt | 0 issue.txt | 28 ---------------------------- package.json | 6 ------ 4 files changed, 48 deletions(-) delete mode 100644 bun.lock delete mode 100644 example.txt delete mode 100644 issue.txt delete mode 100644 package.json diff --git a/bun.lock b/bun.lock deleted file mode 100644 index 45f73b81b..000000000 --- a/bun.lock +++ /dev/null @@ -1,14 +0,0 @@ -{ - "lockfileVersion": 1, - "configVersion": 1, - "workspaces": { - "": { - "devDependencies": { - "prettier": "3.7.4", - }, - }, - }, - "packages": { - "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="], - } -} diff --git a/example.txt b/example.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/issue.txt b/issue.txt deleted file mode 100644 index abe88bb9b..000000000 --- a/issue.txt +++ /dev/null @@ -1,28 +0,0 @@ -URLs are broken when reflowing paragraphs - -## Version - -0.7.3 - -## Example - -Input file: - -```python -"""For more information see https://example.com/documentation/api/v2/reference/getting-started#authentication or contact support.""" -``` - -Output after running `pydocstringformatter --linewrap-full-docstring`: - -```diff ---- issue.py -+++ issue.py -@@ -1,2 +1,5 @@ --"""For more information see https://example.com/documentation/api/v2/reference/getting-started#authentication or contact support.""" -+"""For more information see https://example.com/documentation/api/v2/reference/getting-. -+ -+started#authentication or contact support. -+""" -``` - -The URL is broken across two lines, making it impossible to click. diff --git a/package.json b/package.json deleted file mode 100644 index 71b8ee1ef..000000000 --- a/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "dependencies": {}, - "devDependencies": { - "prettier": "3.7.4" - } -}