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/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/pyproject.toml b/pyproject.toml index fb918a205..55238906d 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.22.1", - "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.3.0", + "pydocstringformatter==0.7.3", "pydocstyle==6.3", "pygments==2.19.2", "pylint[spelling]==4.0.4", @@ -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. @@ -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,15 @@ enableTypeIgnoreComments = false reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" +[tool.pydocstringformatter] +write = true +split-summary-body = false +# 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] fail-under = 100 omit-covered-files = true 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..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. """ @@ -10,9 +11,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 +23,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 +45,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..b2e3ee67f 100644 --- a/src/vws/exceptions/cloud_reco_exceptions.py +++ b/src/vws/exceptions/cloud_reco_exceptions.py @@ -1,5 +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 @@ -17,31 +18,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..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 @@ -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,20 @@ 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 +48,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..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 @@ -14,16 +16,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 +31,21 @@ 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 +53,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 +76,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 +84,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 +92,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 +100,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 +142,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 +164,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..6c2dc481e 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, @@ -74,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/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..9b3d19b4e 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, @@ -573,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/__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..5576f4d40 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 @@ -51,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: @@ -63,8 +62,8 @@ def test_image_too_large( def test_cloudrecoexception_inheritance() -> None: - """ - CloudRecoService-specific exceptions inherit from CloudRecoException. + """CloudRecoService-specific exceptions inherit from + CloudRecoException. """ subclasses = [ MaxNumResultsOutOfRangeError, @@ -81,7 +80,9 @@ 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 e229cf95d..a79a712c0 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,14 +43,14 @@ 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: """ - 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" @@ -93,9 +85,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 +93,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 +119,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 +153,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 +161,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, @@ -210,7 +192,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( @@ -244,7 +227,9 @@ 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 e16eff555..00936bde8 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: @@ -83,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. """ @@ -98,14 +93,13 @@ 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: """ - 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" @@ -128,18 +122,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 +148,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,17 +171,15 @@ 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 @@ -240,14 +224,12 @@ 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() @@ -287,18 +269,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 +322,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 +338,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 +363,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,8 +413,8 @@ 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() @@ -493,9 +463,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 +499,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 +529,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 +538,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 +595,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..4262b3ea6 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 @@ -42,7 +40,9 @@ 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: @@ -59,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" @@ -71,7 +72,9 @@ 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 @@ -98,8 +101,8 @@ 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( @@ -120,9 +123,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( @@ -141,7 +142,9 @@ 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( @@ -168,7 +171,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) @@ -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,9 @@ 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. """ @@ -306,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( @@ -325,9 +335,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 +362,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")