diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 568751b20..083d2a28d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ ci: - ruff-check-fix-docs - ruff-format-fix - ruff-format-fix-docs - - docformatter + - pydocstringformatter - shellcheck - shellcheck-docs - shfmt @@ -119,9 +119,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/admin/__init__.py b/admin/__init__.py index 6a8f8f73b..1a76e35be 100644 --- a/admin/__init__.py +++ b/admin/__init__.py @@ -1,3 +1 @@ -""" -Admin tools. -""" +"""Admin tools.""" diff --git a/admin/create_secrets_files.py b/admin/create_secrets_files.py index a41a5ad8b..4f1b7183c 100644 --- a/admin/create_secrets_files.py +++ b/admin/create_secrets_files.py @@ -20,9 +20,7 @@ def main() -> None: - """ - Create secrets files. - """ + """Create secrets files.""" email_address = os.environ["VWS_EMAIL_ADDRESS"] password = os.environ["VWS_PASSWORD"] new_secrets_dir = Path(os.environ["NEW_SECRETS_DIR"]).expanduser() diff --git a/ci/__init__.py b/ci/__init__.py index fdd0b5af8..4b867b2bd 100644 --- a/ci/__init__.py +++ b/ci/__init__.py @@ -1,3 +1 @@ -""" -CI helpers. -""" +"""CI helpers.""" diff --git a/ci/test_custom_linters.py b/ci/test_custom_linters.py index f740f39a0..c25260b46 100644 --- a/ci/test_custom_linters.py +++ b/ci/test_custom_linters.py @@ -1,6 +1,4 @@ -""" -Custom lint tests. -""" +"""Custom lint tests.""" from pathlib import Path from typing import TYPE_CHECKING @@ -15,9 +13,7 @@ @beartype def _ci_patterns(*, repository_root: Path) -> set[str]: - """ - Return the CI patterns given in the CI configuration file. - """ + """Return the CI patterns given in the CI configuration file.""" ci_file = repository_root / ".github" / "workflows" / "test.yml" github_workflow_config = yaml.safe_load(stream=ci_file.read_text()) matrix = github_workflow_config["jobs"]["ci-tests"]["strategy"]["matrix"] @@ -33,9 +29,7 @@ def _tests_from_pattern( ci_pattern: str, capsys: pytest.CaptureFixture[str], ) -> set[str]: - """ - From a CI pattern, get all tests ``pytest`` would collect. - """ + """From a CI pattern, get all tests ``pytest`` would collect.""" # Clear the captured output. capsys.readouterr() tests: Iterable[str] = set() @@ -59,7 +53,8 @@ def _tests_from_pattern( def test_ci_patterns_valid(request: pytest.FixtureRequest) -> None: """ - All of the CI patterns in the CI configuration match at least one test in + All of the CI patterns in the CI configuration match at least one + test in the test suite. """ ci_patterns = _ci_patterns(repository_root=request.config.rootpath) diff --git a/conftest.py b/conftest.py index ed36d6500..93484cd3e 100644 --- a/conftest.py +++ b/conftest.py @@ -1,6 +1,4 @@ -""" -Setup for Sybil. -""" +"""Setup for Sybil.""" from doctest import ELLIPSIS @@ -17,9 +15,7 @@ @beartype def pytest_collection_modifyitems(items: list[pytest.Item]) -> None: - """ - Apply the beartype decorator to all collected test functions. - """ + """Apply the beartype decorator to all collected test functions.""" for item in items: 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 c24499f79..72d9d43da 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 eb860f1c1..3b2feaf22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,6 @@ optional-dependencies.dev = [ "dirty-equals==0.11", "doc8==1.1.1", "doccmd==2026.1.25", - "docformatter==1.7.7", "docker==7.1.0", "enum-tools[sphinx]==0.13.0", "freezegun==1.5.5", @@ -66,6 +65,7 @@ optional-dependencies.dev = [ "mypy[faster-cache]==1.19.1", "mypy-strict-kwargs==2026.1.12", "prek==0.3.0", + "pydocstringformatter==0.7.3", "pydocstyle==6.3", "pylint[spelling]==4.0.4", "pylint-per-file-ignores==3.2.0", @@ -152,8 +152,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", "D415", @@ -169,6 +169,14 @@ lint.per-file-ignores."ci/test_custom_linters.py" = [ "S101", ] +lint.per-file-ignores."doccmd_*.py" = [ + # Allow our chosen docstring line-style - pydocstringformatter handles + # formatting but docstrings in docs may not match this style. + "D200", + # Allow asserts in docs. + "S101", +] + lint.per-file-ignores."tests/**" = [ # Allow asserts in tests. "S101", @@ -298,9 +306,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 = [ @@ -403,6 +408,12 @@ enableTypeIgnoreComments = false reportUnnecessaryTypeIgnoreComment = true typeCheckingMode = "strict" +[tool.pydocstringformatter] +write = true +split-summary-body = false +max-line-length = 75 +linewrap-full-docstring = true + [tool.interrogate] fail-under = 100 omit-covered-files = true diff --git a/src/mock_vws/__init__.py b/src/mock_vws/__init__.py index 357f764b7..d6d5e053a 100644 --- a/src/mock_vws/__init__.py +++ b/src/mock_vws/__init__.py @@ -1,6 +1,4 @@ -""" -Tools for using a fake implementation of Vuforia. -""" +"""Tools for using a fake implementation of Vuforia.""" from mock_vws._requests_mock_server.decorators import ( MissingSchemeError, diff --git a/src/mock_vws/_base64_decoding.py b/src/mock_vws/_base64_decoding.py index 0d9ae1159..d6ed379b1 100644 --- a/src/mock_vws/_base64_decoding.py +++ b/src/mock_vws/_base64_decoding.py @@ -1,6 +1,4 @@ -""" -Helpers for handling Base64 like Vuforia does. -""" +"""Helpers for handling Base64 like Vuforia does.""" import base64 import binascii diff --git a/src/mock_vws/_constants.py b/src/mock_vws/_constants.py index 61443bbc7..1f832af1f 100644 --- a/src/mock_vws/_constants.py +++ b/src/mock_vws/_constants.py @@ -1,6 +1,4 @@ -""" -Constants used to make the VWS mock. -""" +"""Constants used to make the VWS mock.""" from enum import Enum, unique diff --git a/src/mock_vws/_database_matchers.py b/src/mock_vws/_database_matchers.py index 211e4c70f..899cf71b2 100644 --- a/src/mock_vws/_database_matchers.py +++ b/src/mock_vws/_database_matchers.py @@ -1,6 +1,4 @@ -""" -Helpers for getting databases which match keys given in requests. -""" +"""Helpers for getting databases which match keys given in requests.""" from collections.abc import Iterable, Mapping @@ -19,7 +17,8 @@ def get_database_matching_client_keys( request_path: str, databases: Iterable[VuforiaDatabase], ) -> VuforiaDatabase: - """Return the first of the given databases which is being accessed by the + """Return the first of the given databases which is being accessed by + the given client request. Args: @@ -67,7 +66,8 @@ def get_database_matching_server_keys( request_path: str, databases: Iterable[VuforiaDatabase], ) -> VuforiaDatabase: - """Return the first of the given databases which is being accessed by the + """Return the first of the given databases which is being accessed by + the given server request. Args: diff --git a/src/mock_vws/_flask_server/__init__.py b/src/mock_vws/_flask_server/__init__.py index 50e18f288..81533727f 100644 --- a/src/mock_vws/_flask_server/__init__.py +++ b/src/mock_vws/_flask_server/__init__.py @@ -1,3 +1 @@ -""" -Flask server for the mock Vuforia web service. -""" +"""Flask server for the mock Vuforia web service.""" diff --git a/src/mock_vws/_flask_server/healthcheck.py b/src/mock_vws/_flask_server/healthcheck.py index 39c37a5e2..dbc5dee4b 100644 --- a/src/mock_vws/_flask_server/healthcheck.py +++ b/src/mock_vws/_flask_server/healthcheck.py @@ -1,6 +1,4 @@ -""" -Health check for the Flask server. -""" +"""Health check for the Flask server.""" import http.client import socket @@ -12,9 +10,7 @@ @beartype def flask_app_healthy(port: int) -> bool: - """ - Check if the Flask app is healthy. - """ + """Check if the Flask app is healthy.""" conn = http.client.HTTPConnection(host="localhost", port=port) try: conn.request(method="GET", url="/some-random-endpoint") diff --git a/src/mock_vws/_flask_server/target_manager.py b/src/mock_vws/_flask_server/target_manager.py index 7b112d364..90f3341eb 100644 --- a/src/mock_vws/_flask_server/target_manager.py +++ b/src/mock_vws/_flask_server/target_manager.py @@ -1,6 +1,4 @@ -""" -Storage layer for the mock Vuforia Flask application. -""" +"""Storage layer for the mock Vuforia Flask application.""" import base64 import copy @@ -32,18 +30,14 @@ @beartype class _TargetRaterChoice(StrEnum): - """ - Target rater choices. - """ + """Target rater choices.""" BRISQUE = auto() PERFECT = auto() RANDOM = auto() def to_target_rater(self) -> TargetTrackingRater: - """ - Get the target rater. - """ + """Get the target rater.""" match self: case self.BRISQUE: return BrisqueTargetTrackingRater() @@ -57,9 +51,7 @@ def to_target_rater(self) -> TargetTrackingRater: @beartype class TargetManagerSettings(BaseSettings): - """ - Settings for the Target Manager Flask app. - """ + """Settings for the Target Manager Flask app.""" target_manager_host: str = "" target_rater: _TargetRaterChoice = _TargetRaterChoice.BRISQUE @@ -91,9 +83,7 @@ def delete_database(database_name: str) -> Response: @TARGET_MANAGER_FLASK_APP.route(rule="/databases", methods=[HTTPMethod.GET]) @beartype def get_databases() -> Response: - """ - Return a list of all databases. - """ + """Return a list of all databases.""" databases = [database.to_dict() for database in TARGET_MANAGER.databases] return Response( response=json.dumps(obj=databases), @@ -200,9 +190,7 @@ def create_database() -> Response: ) @beartype def create_target(database_name: str) -> Response: - """ - Create a new target in a given database. - """ + """Create a new target in a given database.""" (database,) = ( database for database in TARGET_MANAGER.databases @@ -238,9 +226,7 @@ def create_target(database_name: str) -> Response: ) @beartype def delete_target(database_name: str, target_id: str) -> Response: - """ - Delete a target. - """ + """Delete a target.""" (database,) = ( database for database in TARGET_MANAGER.databases @@ -266,9 +252,7 @@ def delete_target(database_name: str, target_id: str) -> Response: methods=[HTTPMethod.PUT], ) def update_target(database_name: str, target_id: str) -> Response: - """ - Update a target. - """ + """Update a target.""" (database,) = ( database for database in TARGET_MANAGER.databases diff --git a/src/mock_vws/_flask_server/vwq.py b/src/mock_vws/_flask_server/vwq.py index dee12db42..910d71124 100644 --- a/src/mock_vws/_flask_server/vwq.py +++ b/src/mock_vws/_flask_server/vwq.py @@ -33,17 +33,13 @@ @beartype class _ImageMatcherChoice(StrEnum): - """ - Image matcher choices. - """ + """Image matcher choices.""" EXACT = auto() STRUCTURAL_SIMILARITY = auto() def to_image_matcher(self) -> ImageMatcher: - """ - Get the image matcher. - """ + """Get the image matcher.""" match self: case self.EXACT: return ExactMatcher() @@ -55,9 +51,7 @@ def to_image_matcher(self) -> ImageMatcher: @beartype class VWQSettings(BaseSettings): - """ - Settings for the VWQ Flask app. - """ + """Settings for the VWQ Flask app.""" vwq_host: str = "" target_manager_base_url: str @@ -68,9 +62,7 @@ class VWQSettings(BaseSettings): @beartype def get_all_databases() -> set[VuforiaDatabase]: - """ - Get all database objects from the target manager back-end. - """ + """Get all database objects from the target manager back-end.""" settings = VWQSettings.model_validate(obj={}) response = requests.get( url=f"{settings.target_manager_base_url}/databases", @@ -111,9 +103,7 @@ def set_terminate_wsgi_input() -> None: @CLOUDRECO_FLASK_APP.errorhandler(code_or_exception=ValidatorError) def handle_exceptions(exc: ValidatorError) -> Response: - """ - Return the error response associated with the given exception. - """ + """Return the error response associated with the given exception.""" response = Response( status=exc.status_code.value, response=exc.response_text, @@ -127,9 +117,7 @@ def handle_exceptions(exc: ValidatorError) -> Response: @CLOUDRECO_FLASK_APP.route(rule="/v1/query", methods=[HTTPMethod.POST]) def query() -> Response: - """ - Perform an image recognition query. - """ + """Perform an image recognition query.""" settings = VWQSettings.model_validate(obj={}) query_match_checker = settings.query_image_matcher.to_image_matcher() diff --git a/src/mock_vws/_flask_server/vws.py b/src/mock_vws/_flask_server/vws.py index 2d2f9ac9f..6463b928f 100644 --- a/src/mock_vws/_flask_server/vws.py +++ b/src/mock_vws/_flask_server/vws.py @@ -47,17 +47,13 @@ @beartype class _ImageMatcherChoice(StrEnum): - """ - Image matcher choices. - """ + """Image matcher choices.""" EXACT = auto() STRUCTURAL_SIMILARITY = auto() def to_image_matcher(self) -> ImageMatcher: - """ - Get the image matcher. - """ + """Get the image matcher.""" match self: case self.EXACT: return ExactMatcher() @@ -69,9 +65,7 @@ def to_image_matcher(self) -> ImageMatcher: @beartype class VWSSettings(BaseSettings): - """ - Settings for the VWS Flask app. - """ + """Settings for the VWS Flask app.""" target_manager_base_url: str processing_time_seconds: float = 2.0 @@ -83,9 +77,7 @@ class VWSSettings(BaseSettings): @beartype def get_all_databases() -> set[VuforiaDatabase]: - """ - Get all database objects from the task manager back-end. - """ + """Get all database objects from the task manager back-end.""" settings = VWSSettings.model_validate(obj={}) timeout_seconds = 30 response = requests.get( @@ -127,9 +119,7 @@ def set_terminate_wsgi_input() -> None: @VWS_FLASK_APP.before_request @beartype def validate_request() -> None: - """ - Run validators on the request. - """ + """Run validators on the request.""" databases = get_all_databases() run_services_validators( request_headers=dict(request.headers), @@ -142,9 +132,7 @@ def validate_request() -> None: @VWS_FLASK_APP.errorhandler(code_or_exception=ValidatorError) def handle_exceptions(exc: ValidatorError) -> Response: - """ - Return the error response associated with the given exception. - """ + """Return the error response associated with the given exception.""" response = Response( status=exc.status_code.value, response=exc.response_text, diff --git a/src/mock_vws/_mock_common.py b/src/mock_vws/_mock_common.py index 7ef5d7502..0ebbd379b 100644 --- a/src/mock_vws/_mock_common.py +++ b/src/mock_vws/_mock_common.py @@ -1,6 +1,4 @@ -""" -Common utilities for creating mock routes. -""" +"""Common utilities for creating mock routes.""" import json from collections.abc import Iterable diff --git a/src/mock_vws/_query_tools.py b/src/mock_vws/_query_tools.py index 520afd9ab..b73f6c616 100644 --- a/src/mock_vws/_query_tools.py +++ b/src/mock_vws/_query_tools.py @@ -1,6 +1,4 @@ -""" -Tools for making Vuforia queries. -""" +"""Tools for making Vuforia queries.""" import base64 import io diff --git a/src/mock_vws/_query_validators/__init__.py b/src/mock_vws/_query_validators/__init__.py index 9fc608c78..54e458e80 100644 --- a/src/mock_vws/_query_validators/__init__.py +++ b/src/mock_vws/_query_validators/__init__.py @@ -1,6 +1,4 @@ -""" -Input validators to use in the mock query API. -""" +"""Input validators to use in the mock query API.""" from collections.abc import Iterable, Mapping diff --git a/src/mock_vws/_query_validators/accept_header_validators.py b/src/mock_vws/_query_validators/accept_header_validators.py index baeb735fe..fe3e966f6 100644 --- a/src/mock_vws/_query_validators/accept_header_validators.py +++ b/src/mock_vws/_query_validators/accept_header_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the ``Accept`` header. -""" +"""Validators for the ``Accept`` header.""" import logging from collections.abc import Mapping diff --git a/src/mock_vws/_query_validators/auth_validators.py b/src/mock_vws/_query_validators/auth_validators.py index a8a139691..a90273909 100644 --- a/src/mock_vws/_query_validators/auth_validators.py +++ b/src/mock_vws/_query_validators/auth_validators.py @@ -1,6 +1,4 @@ -""" -Authorization validators to use in the mock query API. -""" +"""Authorization validators to use in the mock query API.""" import logging from collections.abc import Iterable, Mapping @@ -41,7 +39,8 @@ def validate_auth_header_number_of_parts( *, request_headers: Mapping[str, str], ) -> None: - """Validate the authorization header includes text either side of a space. + """Validate the authorization header includes text either side of a + space. Args: request_headers: The headers sent with the request. @@ -66,7 +65,8 @@ def validate_client_key_exists( request_headers: Mapping[str, str], databases: Iterable[VuforiaDatabase], ) -> None: - """Validate the authorization header includes a client key for a database. + """Validate the authorization header includes a client key for a + database. Args: request_headers: The headers sent with the request. diff --git a/src/mock_vws/_query_validators/content_length_validators.py b/src/mock_vws/_query_validators/content_length_validators.py index f7cbac25b..4cb799fb5 100644 --- a/src/mock_vws/_query_validators/content_length_validators.py +++ b/src/mock_vws/_query_validators/content_length_validators.py @@ -1,6 +1,4 @@ -""" -Content-Length header validators to use in the mock. -""" +"""Content-Length header validators to use in the mock.""" import logging from collections.abc import Mapping diff --git a/src/mock_vws/_query_validators/content_type_validators.py b/src/mock_vws/_query_validators/content_type_validators.py index bd474c6ab..3e7dc4792 100644 --- a/src/mock_vws/_query_validators/content_type_validators.py +++ b/src/mock_vws/_query_validators/content_type_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the ``Content-Type`` header. -""" +"""Validators for the ``Content-Type`` header.""" import logging from collections.abc import Mapping diff --git a/src/mock_vws/_query_validators/date_validators.py b/src/mock_vws/_query_validators/date_validators.py index 4048238c9..4151b0d31 100644 --- a/src/mock_vws/_query_validators/date_validators.py +++ b/src/mock_vws/_query_validators/date_validators.py @@ -1,6 +1,4 @@ -""" -Validators of the date header to use in the mock query API. -""" +"""Validators of the date header to use in the mock query API.""" import contextlib import datetime diff --git a/src/mock_vws/_query_validators/exceptions.py b/src/mock_vws/_query_validators/exceptions.py index 3d225297c..6417595f4 100644 --- a/src/mock_vws/_query_validators/exceptions.py +++ b/src/mock_vws/_query_validators/exceptions.py @@ -1,6 +1,4 @@ -""" -Exceptions to raise from validators. -""" +"""Exceptions to raise from validators.""" import email.utils import textwrap @@ -17,7 +15,8 @@ @beartype class ValidatorError(Exception): """ - A base class for exceptions thrown from mock Vuforia cloud recognition + A base class for exceptions thrown from mock Vuforia cloud + recognition client endpoints. """ @@ -28,16 +27,15 @@ class ValidatorError(Exception): @beartype class DateHeaderNotGivenError(ValidatorError): - """ - Exception raised when a date header is not given. - """ + """Exception raised when a date header is not given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -59,16 +57,15 @@ def __init__(self) -> None: @beartype class DateFormatNotValidError(ValidatorError): - """ - Exception raised when the date format is not valid. - """ + """Exception raised when the date format is not valid.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -91,8 +88,7 @@ def __init__(self) -> None: @beartype class RequestTimeTooSkewedError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ @@ -101,7 +97,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -127,8 +124,7 @@ def __init__(self) -> None: @beartype class BadImageError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @@ -137,7 +133,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -170,8 +167,7 @@ def __init__(self) -> None: @beartype class AuthenticationFailureError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @@ -180,7 +176,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -213,8 +210,7 @@ def __init__(self) -> None: @beartype class AuthenticationFailureGoodFormattingError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure' with a standard JSON formatting. """ @@ -223,7 +219,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -251,16 +248,15 @@ def __init__(self) -> None: @beartype class ImageNotGivenError(ValidatorError): - """ - Exception raised when an image is not given. - """ + """Exception raised when an image is not given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -283,16 +279,15 @@ def __init__(self) -> None: @beartype class AuthHeaderMissingError(ValidatorError): - """ - Exception raised when an auth header is not given. - """ + """Exception raised when an auth header is not given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -316,16 +311,15 @@ def __init__(self) -> None: @beartype class MalformedAuthHeaderError(ValidatorError): - """ - Exception raised when an auth header is not given. - """ + """Exception raised when an auth header is not given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. www_authenticate: The WWW-Authenticate header value. """ @@ -350,16 +344,15 @@ def __init__(self) -> None: @beartype class UnknownParametersError(ValidatorError): - """ - Exception raised when unknown parameters are given. - """ + """Exception raised when unknown parameters are given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -382,8 +375,7 @@ def __init__(self) -> None: @beartype class InactiveProjectError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'InactiveProject'. """ @@ -392,7 +384,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -424,8 +417,8 @@ def __init__(self) -> None: @beartype class InvalidMaxNumResultsError(ValidatorError): - """ - Exception raised when an invalid value is given as the "max_num_results" + """Exception raised when an invalid value is given as the + "max_num_results" field. """ @@ -434,7 +427,8 @@ def __init__(self, given_value: str) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -461,8 +455,8 @@ def __init__(self, given_value: str) -> None: @beartype class MaxNumResultsOutOfRangeError(ValidatorError): - """ - Exception raised when an integer value is given as the "max_num_results" + """Exception raised when an integer value is given as the + "max_num_results" field which is out of range. """ @@ -471,7 +465,8 @@ def __init__(self, given_value: str) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -498,8 +493,7 @@ def __init__(self, given_value: str) -> None: @beartype class InvalidIncludeTargetDataError(ValidatorError): - """ - Exception raised when an invalid value is given as the + """Exception raised when an invalid value is given as the "include_target_data" field. """ @@ -508,7 +502,8 @@ def __init__(self, given_value: str) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -537,16 +532,15 @@ def __init__(self, given_value: str) -> None: @beartype class UnsupportedMediaTypeError(ValidatorError): - """ - Exception raised when no boundary is found for multipart data. - """ + """Exception raised when no boundary is found for multipart data.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -568,16 +562,15 @@ def __init__(self) -> None: @beartype class InvalidAcceptHeaderError(ValidatorError): - """ - Exception raised when there is an invalid accept header given. - """ + """Exception raised when there is an invalid accept header given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -599,16 +592,15 @@ def __init__(self) -> None: @beartype class NoBoundaryFoundError(ValidatorError): - """ - Exception raised when an invalid media type is given. - """ + """Exception raised when an invalid media type is given.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -634,7 +626,8 @@ def __init__(self) -> None: @beartype class ContentLengthHeaderTooLargeError(ValidatorError): """ - Exception raised when the given content length header is too large. + Exception raised when the given content length header is too + large. """ # We skip coverage here as running a test to cover this is very slow. @@ -643,7 +636,8 @@ def __init__(self) -> None: # pragma: no cover Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -658,7 +652,8 @@ def __init__(self) -> None: # pragma: no cover @beartype class ContentLengthHeaderNotIntError(ValidatorError): """ - Exception raised when the given content length header is not an integer. + Exception raised when the given content length header is not an + integer. """ def __init__(self) -> None: @@ -666,7 +661,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -680,9 +676,7 @@ def __init__(self) -> None: @beartype class RequestEntityTooLargeError(ValidatorError): - """ - Exception raised when the given image file size is too large. - """ + """Exception raised when the given image file size is too large.""" # Ignore coverage on this as there is a bug in urllib3 which means that we # do not trigger this exception. @@ -692,7 +686,8 @@ def __init__(self) -> None: # pragma: no cover Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -725,7 +720,8 @@ def __init__(self) -> None: # pragma: no cover @beartype class NoContentTypeError(ValidatorError): """ - Exception raised when a content type is either not given or is empty. + Exception raised when a content type is either not given or is + empty. """ def __init__(self) -> None: @@ -733,7 +729,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() diff --git a/src/mock_vws/_query_validators/fields_validators.py b/src/mock_vws/_query_validators/fields_validators.py index 3b91fb9fb..b9e78fecd 100644 --- a/src/mock_vws/_query_validators/fields_validators.py +++ b/src/mock_vws/_query_validators/fields_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the fields given. -""" +"""Validators for the fields given.""" import io import logging diff --git a/src/mock_vws/_query_validators/image_validators.py b/src/mock_vws/_query_validators/image_validators.py index 203c606de..827c636d2 100644 --- a/src/mock_vws/_query_validators/image_validators.py +++ b/src/mock_vws/_query_validators/image_validators.py @@ -1,6 +1,4 @@ -""" -Input validators for the image field use in the mock query API. -""" +"""Input validators for the image field use in the mock query API.""" import io import logging diff --git a/src/mock_vws/_query_validators/include_target_data_validators.py b/src/mock_vws/_query_validators/include_target_data_validators.py index 5f8277ade..b3719aad8 100644 --- a/src/mock_vws/_query_validators/include_target_data_validators.py +++ b/src/mock_vws/_query_validators/include_target_data_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the ``include_target_data`` field. -""" +"""Validators for the ``include_target_data`` field.""" import io import logging @@ -20,7 +18,8 @@ def validate_include_target_data( request_headers: Mapping[str, str], request_body: bytes, ) -> None: - """Validate the ``include_target_data`` field is either an accepted value + """Validate the ``include_target_data`` field is either an accepted + value or not given. Args: diff --git a/src/mock_vws/_query_validators/num_results_validators.py b/src/mock_vws/_query_validators/num_results_validators.py index ff4b99ae1..31ead620b 100644 --- a/src/mock_vws/_query_validators/num_results_validators.py +++ b/src/mock_vws/_query_validators/num_results_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the ``max_num_results`` fields. -""" +"""Validators for the ``max_num_results`` fields.""" import io import logging @@ -24,7 +22,8 @@ def validate_max_num_results( request_headers: Mapping[str, str], request_body: bytes, ) -> None: - """Validate the ``max_num_results`` field is either an integer within range + """Validate the ``max_num_results`` field is either an integer within + range or not given. Args: diff --git a/src/mock_vws/_query_validators/project_state_validators.py b/src/mock_vws/_query_validators/project_state_validators.py index bd44f4fd8..5a3517bde 100644 --- a/src/mock_vws/_query_validators/project_state_validators.py +++ b/src/mock_vws/_query_validators/project_state_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the project state. -""" +"""Validators for the project state.""" import logging from collections.abc import Iterable, Mapping diff --git a/src/mock_vws/_requests_mock_server/__init__.py b/src/mock_vws/_requests_mock_server/__init__.py index 81677dca3..79758e3ce 100644 --- a/src/mock_vws/_requests_mock_server/__init__.py +++ b/src/mock_vws/_requests_mock_server/__init__.py @@ -1,3 +1 @@ -""" -An interface to the mock Vuforia which uses ``responses``. -""" +"""An interface to the mock Vuforia which uses ``responses``.""" diff --git a/src/mock_vws/_requests_mock_server/decorators.py b/src/mock_vws/_requests_mock_server/decorators.py index 6acdd899d..6572d593d 100644 --- a/src/mock_vws/_requests_mock_server/decorators.py +++ b/src/mock_vws/_requests_mock_server/decorators.py @@ -1,6 +1,4 @@ -""" -Decorators for using the mock. -""" +"""Decorators for using the mock.""" import re from contextlib import ContextDecorator @@ -32,9 +30,7 @@ class MissingSchemeError(Exception): - """ - Raised when a URL is missing a schema. - """ + """Raised when a URL is missing a schema.""" def __init__(self, url: str) -> None: """ @@ -46,7 +42,8 @@ def __init__(self, url: str) -> None: def __str__(self) -> str: """ - Give a string representation of this error with a suggestion. + Give a string representation of this error with a + suggestion. """ return ( f'Invalid URL "{self.url}": No scheme supplied. ' @@ -56,9 +53,7 @@ def __str__(self) -> str: @beartype(conf=BeartypeConf(is_pep484_tower=True)) class MockVWS(ContextDecorator): - """ - Route requests to Vuforia's Web Service APIs to fakes of those APIs. - """ + """Route requests to Vuforia's Web Service APIs to fakes of those APIs.""" def __init__( self, @@ -71,7 +66,8 @@ def __init__( target_tracking_rater: TargetTrackingRater = _BRISQUE_TRACKING_RATER, real_http: bool = False, ) -> None: - """Route requests to Vuforia's Web Service APIs to fakes of those APIs. + """Route requests to Vuforia's Web Service APIs to fakes of those + APIs. Args: real_http: Whether or not to forward requests to the real diff --git a/src/mock_vws/_requests_mock_server/mock_web_query_api.py b/src/mock_vws/_requests_mock_server/mock_web_query_api.py index 545ecfe03..8206a6d10 100644 --- a/src/mock_vws/_requests_mock_server/mock_web_query_api.py +++ b/src/mock_vws/_requests_mock_server/mock_web_query_api.py @@ -31,16 +31,12 @@ @runtime_checkable class _RouteMethod(Protocol[_P]): - """ - Callable used for routing which also exposes ``__name__``. - """ + """Callable used for routing which also exposes ``__name__``.""" __name__: str def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _ResponseType: - """ - Return a mock response. - """ + """Return a mock response.""" ... # pylint: disable=unnecessary-ellipsis @@ -63,7 +59,8 @@ def route( def decorator( method: _RouteMethod[_P], ) -> _RouteMethod[_P]: - """Register a decorated method so that it can be recognized as a route. + """Register a decorated method so that it can be recognized as a + route. Returns: The given `method` with multiple changes, including added @@ -83,9 +80,7 @@ def decorator( @beartype def _body_bytes(request: PreparedRequest) -> bytes: - """ - Return the body of a request as bytes. - """ + """Return the body of a request as bytes.""" if request.body is None or isinstance(request.body, str): return b"" @@ -107,7 +102,8 @@ def __init__( """ Args: target_manager: The target manager which holds all databases. - query_match_checker: A callable which takes two image values and + query_match_checker: A callable which takes two image values + and returns whether they match. Attributes: @@ -119,9 +115,7 @@ def __init__( @route(path_pattern="/v1/query", http_methods={HTTPMethod.POST}) def query(self, request: PreparedRequest) -> _ResponseType: - """ - Perform an image recognition query. - """ + """Perform an image recognition query.""" try: run_query_validators( request_path=request.path_url, diff --git a/src/mock_vws/_requests_mock_server/mock_web_services_api.py b/src/mock_vws/_requests_mock_server/mock_web_services_api.py index a4c2065dc..ddee6ef03 100644 --- a/src/mock_vws/_requests_mock_server/mock_web_services_api.py +++ b/src/mock_vws/_requests_mock_server/mock_web_services_api.py @@ -44,16 +44,12 @@ @runtime_checkable class _RouteMethod(Protocol[_P]): - """ - Callable used for routing which also exposes ``__name__``. - """ + """Callable used for routing which also exposes ``__name__``.""" __name__: str def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _ResponseType: - """ - Return a mock response. - """ + """Return a mock response.""" ... # pylint: disable=unnecessary-ellipsis @@ -77,7 +73,8 @@ def route( def decorator( method: _RouteMethod[_P], ) -> _RouteMethod[_P]: - """Register a decorated method so that it can be recognized as a route. + """Register a decorated method so that it can be recognized as a + route. Returns: The given `method` with multiple changes, including added @@ -97,9 +94,7 @@ def decorator( @beartype def _body_bytes(request: PreparedRequest) -> bytes: - """ - Return the body of a request as bytes. - """ + """Return the body of a request as bytes.""" if request.body is None: return b"" @@ -130,9 +125,11 @@ def __init__( processing_time_seconds: The number of seconds to process each image for. In the real Vuforia Web Services, this is not deterministic. - duplicate_match_checker: A callable which takes two image values + duplicate_match_checker: A callable which takes two image + values and returns whether they are duplicates. - target_tracking_rater: A callable for rating targets for tracking. + target_tracking_rater: A callable for rating targets for + tracking. Attributes: routes: The `Route`s to be used in the mock. @@ -475,7 +472,8 @@ def get_target(self, request: PreparedRequest) -> _ResponseType: http_methods={HTTPMethod.GET}, ) def get_duplicates(self, request: PreparedRequest) -> _ResponseType: - """Get targets which may be considered duplicates of a given target. + """Get targets which may be considered duplicates of a given + target. Fake implementation of https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#check diff --git a/src/mock_vws/_services_validators/__init__.py b/src/mock_vws/_services_validators/__init__.py index d8bbf0c78..44487b365 100644 --- a/src/mock_vws/_services_validators/__init__.py +++ b/src/mock_vws/_services_validators/__init__.py @@ -1,6 +1,4 @@ -""" -Input validators to use in the mock. -""" +"""Input validators to use in the mock.""" from collections.abc import Iterable, Mapping diff --git a/src/mock_vws/_services_validators/active_flag_validators.py b/src/mock_vws/_services_validators/active_flag_validators.py index f4864bcc7..66a446945 100644 --- a/src/mock_vws/_services_validators/active_flag_validators.py +++ b/src/mock_vws/_services_validators/active_flag_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the active flag. -""" +"""Validators for the active flag.""" import json import logging diff --git a/src/mock_vws/_services_validators/auth_validators.py b/src/mock_vws/_services_validators/auth_validators.py index 0fd8d6757..f47164085 100644 --- a/src/mock_vws/_services_validators/auth_validators.py +++ b/src/mock_vws/_services_validators/auth_validators.py @@ -1,6 +1,4 @@ -""" -Authorization header validators to use in the mock. -""" +"""Authorization header validators to use in the mock.""" import logging from collections.abc import Iterable, Mapping @@ -20,7 +18,8 @@ @beartype def validate_auth_header_exists(*, request_headers: Mapping[str, str]) -> None: - """Validate that there is an authorization header given to a VWS endpoint. + """Validate that there is an authorization header given to a VWS + endpoint. Args: request_headers: The headers sent with the request. @@ -39,7 +38,8 @@ def validate_access_key_exists( request_headers: Mapping[str, str], databases: Iterable[VuforiaDatabase], ) -> None: - """Validate the authorization header includes an access key for a database. + """Validate the authorization header includes an access key for a + database. Args: request_headers: The headers sent with the request. diff --git a/src/mock_vws/_services_validators/content_length_validators.py b/src/mock_vws/_services_validators/content_length_validators.py index 9e2cc966b..eaa41b2af 100644 --- a/src/mock_vws/_services_validators/content_length_validators.py +++ b/src/mock_vws/_services_validators/content_length_validators.py @@ -1,6 +1,4 @@ -""" -Content-Length header validators to use in the mock. -""" +"""Content-Length header validators to use in the mock.""" import logging from collections.abc import Mapping diff --git a/src/mock_vws/_services_validators/content_type_validators.py b/src/mock_vws/_services_validators/content_type_validators.py index 4c97c4cdf..12913fa6f 100644 --- a/src/mock_vws/_services_validators/content_type_validators.py +++ b/src/mock_vws/_services_validators/content_type_validators.py @@ -1,6 +1,4 @@ -""" -Content-Type header validators to use in the mock. -""" +"""Content-Type header validators to use in the mock.""" import logging from collections.abc import Mapping diff --git a/src/mock_vws/_services_validators/date_validators.py b/src/mock_vws/_services_validators/date_validators.py index 4f6bda3ed..f5f773d97 100644 --- a/src/mock_vws/_services_validators/date_validators.py +++ b/src/mock_vws/_services_validators/date_validators.py @@ -1,6 +1,4 @@ -""" -Validators of the date header to use in the mock services API. -""" +"""Validators of the date header to use in the mock services API.""" import datetime import logging diff --git a/src/mock_vws/_services_validators/exceptions.py b/src/mock_vws/_services_validators/exceptions.py index 6a582a9fc..4bbc5dab8 100644 --- a/src/mock_vws/_services_validators/exceptions.py +++ b/src/mock_vws/_services_validators/exceptions.py @@ -1,6 +1,4 @@ -""" -Exceptions to raise from validators. -""" +"""Exceptions to raise from validators.""" import email.utils import textwrap @@ -17,7 +15,8 @@ @beartype class ValidatorError(Exception): """ - A base class for exceptions thrown from mock Vuforia services endpoints. + A base class for exceptions thrown from mock Vuforia services + endpoints. """ status_code: HTTPStatus @@ -27,8 +26,7 @@ class ValidatorError(Exception): @beartype class UnknownTargetError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'UnknownTarget'. """ @@ -37,7 +35,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -67,8 +66,7 @@ def __init__(self) -> None: @beartype class ProjectInactiveError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ProjectInactive'. """ @@ -77,7 +75,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -107,8 +106,7 @@ def __init__(self) -> None: @beartype class AuthenticationFailureError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'AuthenticationFailure'. """ @@ -117,7 +115,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -147,8 +146,8 @@ def __init__(self) -> None: @beartype class FailError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code 'Fail'. + """Exception raised when Vuforia returns a response with a result code + 'Fail'. """ def __init__(self, *, status_code: HTTPStatus) -> None: @@ -156,7 +155,8 @@ def __init__(self, *, status_code: HTTPStatus) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -186,8 +186,7 @@ def __init__(self, *, status_code: HTTPStatus) -> None: @beartype class MetadataTooLargeError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'MetadataTooLarge'. """ @@ -196,7 +195,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -226,8 +226,7 @@ def __init__(self) -> None: @beartype class TargetNameExistError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'TargetNameExist'. """ @@ -236,7 +235,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -266,8 +266,7 @@ def __init__(self) -> None: @beartype class BadImageError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'BadImage'. """ @@ -276,7 +275,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -306,8 +306,7 @@ def __init__(self) -> None: @beartype class ImageTooLargeError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'ImageTooLarge'. """ @@ -316,7 +315,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -346,8 +346,7 @@ def __init__(self) -> None: @beartype class RequestTimeTooSkewedError(ValidatorError): - """ - Exception raised when Vuforia returns a response with a result code + """Exception raised when Vuforia returns a response with a result code 'RequestTimeTooSkewed'. """ @@ -356,7 +355,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -387,7 +387,8 @@ def __init__(self) -> None: @beartype class ContentLengthHeaderTooLargeError(ValidatorError): """ - Exception raised when the given content length header is too large. + Exception raised when the given content length header is too + large. """ # We skip coverage here as running a test to cover this is very slow. @@ -396,7 +397,8 @@ def __init__(self) -> None: # pragma: no cover Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -419,7 +421,8 @@ def __init__(self) -> None: # pragma: no cover @beartype class ContentLengthHeaderNotIntError(ValidatorError): """ - Exception raised when the given content length header is not an integer. + Exception raised when the given content length header is not an + integer. """ def __init__(self) -> None: @@ -427,7 +430,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -458,16 +462,15 @@ def __init__(self) -> None: @beartype class UnnecessaryRequestBodyError(ValidatorError): - """ - Exception raised when a request body is given but not necessary. - """ + """Exception raised when a request body is given but not necessary.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -498,7 +501,8 @@ def __init__(self) -> None: Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() @@ -528,16 +532,15 @@ def __init__(self) -> None: @beartype class TargetStatusProcessingError(ValidatorError): - """ - Exception raised when trying to delete a target which is processing. - """ + """Exception raised when trying to delete a target which is processing.""" def __init__(self) -> None: """ Attributes: status_code: The status code to use in a response if this is raised. - response_text: The response text to use in a response if this is + response_text: The response text to use in a response if this + is raised. """ super().__init__() diff --git a/src/mock_vws/_services_validators/image_validators.py b/src/mock_vws/_services_validators/image_validators.py index 2dd703391..c5744efff 100644 --- a/src/mock_vws/_services_validators/image_validators.py +++ b/src/mock_vws/_services_validators/image_validators.py @@ -1,6 +1,4 @@ -""" -Image validators to use in the mock. -""" +"""Image validators to use in the mock.""" import binascii import io diff --git a/src/mock_vws/_services_validators/json_validators.py b/src/mock_vws/_services_validators/json_validators.py index 1f97f2784..9d04eec29 100644 --- a/src/mock_vws/_services_validators/json_validators.py +++ b/src/mock_vws/_services_validators/json_validators.py @@ -1,6 +1,4 @@ -""" -Validators for given JSON. -""" +"""Validators for given JSON.""" import json import logging diff --git a/src/mock_vws/_services_validators/key_validators.py b/src/mock_vws/_services_validators/key_validators.py index 85f4a3f77..b07533fe0 100644 --- a/src/mock_vws/_services_validators/key_validators.py +++ b/src/mock_vws/_services_validators/key_validators.py @@ -1,6 +1,4 @@ -""" -Validators for JSON keys. -""" +"""Validators for JSON keys.""" import json import logging diff --git a/src/mock_vws/_services_validators/metadata_validators.py b/src/mock_vws/_services_validators/metadata_validators.py index 7ad3a1851..0695de3db 100644 --- a/src/mock_vws/_services_validators/metadata_validators.py +++ b/src/mock_vws/_services_validators/metadata_validators.py @@ -1,6 +1,4 @@ -""" -Validators for application metadata. -""" +"""Validators for application metadata.""" import binascii import json @@ -20,7 +18,8 @@ @beartype def validate_metadata_size(*, request_body: bytes) -> None: - """Validate that the given application metadata is a string or 1024 * 1024 + """Validate that the given application metadata is a string or 1024 * + 1024 bytes or fewer. Args: diff --git a/src/mock_vws/_services_validators/name_validators.py b/src/mock_vws/_services_validators/name_validators.py index 604c8a1a0..37e511931 100644 --- a/src/mock_vws/_services_validators/name_validators.py +++ b/src/mock_vws/_services_validators/name_validators.py @@ -1,6 +1,4 @@ -""" -Validators for target names. -""" +"""Validators for target names.""" import json import logging @@ -26,7 +24,8 @@ def validate_name_characters_in_range( request_method: str, request_path: str, ) -> None: - """Validate the characters in the name argument given to a VWS endpoint. + """Validate the characters in the name argument given to a VWS + endpoint. Args: request_body: The body of the request. @@ -179,7 +178,8 @@ def validate_name_does_not_exist_existing_target( request_path: str, databases: Iterable[VuforiaDatabase], ) -> None: - """Validate that the name does not exist for any existing target apart from + """Validate that the name does not exist for any existing target apart + from the one being updated. Args: diff --git a/src/mock_vws/_services_validators/project_state_validators.py b/src/mock_vws/_services_validators/project_state_validators.py index 09fed3d92..468e6188a 100644 --- a/src/mock_vws/_services_validators/project_state_validators.py +++ b/src/mock_vws/_services_validators/project_state_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the project state. -""" +"""Validators for the project state.""" import logging from collections.abc import Iterable, Mapping diff --git a/src/mock_vws/_services_validators/target_validators.py b/src/mock_vws/_services_validators/target_validators.py index 1f6a9e0a2..4dbee04b1 100644 --- a/src/mock_vws/_services_validators/target_validators.py +++ b/src/mock_vws/_services_validators/target_validators.py @@ -1,6 +1,4 @@ -""" -Validators for given target IDs. -""" +"""Validators for given target IDs.""" import logging from collections.abc import Iterable, Mapping diff --git a/src/mock_vws/_services_validators/width_validators.py b/src/mock_vws/_services_validators/width_validators.py index e1d77c596..ab47947d2 100644 --- a/src/mock_vws/_services_validators/width_validators.py +++ b/src/mock_vws/_services_validators/width_validators.py @@ -1,6 +1,4 @@ -""" -Validators for the width field. -""" +"""Validators for the width field.""" import json import logging diff --git a/src/mock_vws/database.py b/src/mock_vws/database.py index 1d3b62659..2e28a9f61 100644 --- a/src/mock_vws/database.py +++ b/src/mock_vws/database.py @@ -1,6 +1,4 @@ -""" -Utilities for managing mock Vuforia databases. -""" +"""Utilities for managing mock Vuforia databases.""" import uuid from collections.abc import Iterable @@ -16,9 +14,7 @@ @beartype class DatabaseDict(TypedDict): - """ - A dictionary type which represents a database. - """ + """A dictionary type which represents a database.""" database_name: str server_access_key: str @@ -31,9 +27,7 @@ class DatabaseDict(TypedDict): @beartype def _random_hex() -> str: - """ - Return a random hex value. - """ + """Return a random hex value.""" return uuid.uuid4().hex @@ -78,9 +72,7 @@ class VuforiaDatabase: target_quota: int = 1000 def to_dict(self) -> DatabaseDict: - """ - Dump a target to a dictionary which can be loaded as JSON. - """ + """Dump a target to a dictionary which can be loaded as JSON.""" targets = [target.to_dict() for target in self.targets] return { "database_name": self.database_name, @@ -93,9 +85,7 @@ def to_dict(self) -> DatabaseDict: } def get_target(self, target_id: str) -> Target: - """ - Return a target from the database with the given ID. - """ + """Return a target from the database with the given ID.""" (target,) = ( target for target in self.targets if target.target_id == target_id ) @@ -103,9 +93,7 @@ def get_target(self, target_id: str) -> Target: @classmethod def from_dict(cls, database_dict: DatabaseDict) -> Self: - """ - Load a database from a dictionary. - """ + """Load a database from a dictionary.""" return cls( database_name=database_dict["database_name"], server_access_key=database_dict["server_access_key"], @@ -121,16 +109,12 @@ def from_dict(cls, database_dict: DatabaseDict) -> Self: @property def not_deleted_targets(self) -> set[Target]: - """ - All targets which have not been deleted. - """ + """All targets which have not been deleted.""" return {target for target in self.targets if not target.delete_date} @property def active_targets(self) -> set[Target]: - """ - All active targets. - """ + """All active targets.""" return { target for target in self.not_deleted_targets @@ -140,9 +124,7 @@ def active_targets(self) -> set[Target]: @property def inactive_targets(self) -> set[Target]: - """ - All inactive targets. - """ + """All inactive targets.""" return { target for target in self.not_deleted_targets @@ -152,9 +134,7 @@ def inactive_targets(self) -> set[Target]: @property def failed_targets(self) -> set[Target]: - """ - All failed targets. - """ + """All failed targets.""" return { target for target in self.not_deleted_targets @@ -163,9 +143,7 @@ def failed_targets(self) -> set[Target]: @property def processing_targets(self) -> set[Target]: - """ - All processing targets. - """ + """All processing targets.""" return { target for target in self.not_deleted_targets diff --git a/src/mock_vws/image_matchers.py b/src/mock_vws/image_matchers.py index eba39996a..2aa954794 100644 --- a/src/mock_vws/image_matchers.py +++ b/src/mock_vws/image_matchers.py @@ -1,6 +1,4 @@ -""" -Matchers for query and duplicate requests. -""" +"""Matchers for query and duplicate requests.""" import io from typing import Protocol, runtime_checkable @@ -16,9 +14,7 @@ @runtime_checkable class ImageMatcher(Protocol): - """ - Protocol for a matcher for query and duplicate requests. - """ + """Protocol for a matcher for query and duplicate requests.""" def __call__( self, @@ -38,9 +34,7 @@ def __call__( @beartype class ExactMatcher: - """ - A matcher which returns whether two images are exactly equal. - """ + """A matcher which returns whether two images are exactly equal.""" def __call__( self, @@ -59,7 +53,8 @@ def __call__( @beartype class StructuralSimilarityMatcher: """ - A matcher which returns whether two images are similar using SSIM. + A matcher which returns whether two images are similar using + SSIM. """ def __call__( diff --git a/src/mock_vws/states.py b/src/mock_vws/states.py index 7233fd8c9..e57a09734 100644 --- a/src/mock_vws/states.py +++ b/src/mock_vws/states.py @@ -1,6 +1,4 @@ -""" -Vuforia database states. -""" +"""Vuforia database states.""" from enum import StrEnum, auto, unique @@ -10,9 +8,7 @@ @beartype @unique class States(StrEnum): - """ - Constants representing various web service states. - """ + """Constants representing various web service states.""" WORKING = auto() diff --git a/src/mock_vws/target.py b/src/mock_vws/target.py index b04c3ff52..afd8f20b1 100644 --- a/src/mock_vws/target.py +++ b/src/mock_vws/target.py @@ -1,6 +1,4 @@ -""" -A fake implementation of a target for the Vuforia Web Services API. -""" +"""A fake implementation of a target for the Vuforia Web Services API.""" import base64 import datetime @@ -22,9 +20,7 @@ class TargetDict(TypedDict): - """ - A dictionary type which represents a target. - """ + """A dictionary type which represents a target.""" name: str width: float @@ -41,17 +37,13 @@ class TargetDict(TypedDict): @beartype def _random_hex() -> str: - """ - Return a random hex value. - """ + """Return a random hex value.""" return uuid.uuid4().hex @beartype def _time_now() -> datetime.datetime: - """ - Return the current time in the GMT time zone. - """ + """Return the current time in the GMT time zone.""" gmt = ZoneInfo(key="GMT") return datetime.datetime.now(tz=gmt) @@ -82,7 +74,8 @@ class Target: @property def _post_processing_status(self) -> TargetStatuses: - """Return the status of the target, or what it will be when processing + """Return the status of the target, or what it will be when + processing is finished. The status depends on the standard deviation of the color bands. @@ -128,16 +121,12 @@ def status(self) -> str: @property def _post_processing_target_rating(self) -> int: - """ - The rating of the target after processing. - """ + """The rating of the target after processing.""" return self.target_tracking_rater(image_content=self.image_value) @property def tracking_rating(self) -> int: - """ - Return the tracking rating of the target recognition image. - """ + """Return the tracking rating of the target recognition image.""" pre_rating_time = datetime.timedelta( # That this is half of the total processing time is unrealistic. # In VWS it is not a constant percentage. @@ -157,9 +146,7 @@ def tracking_rating(self) -> int: @classmethod def from_dict(cls, target_dict: TargetDict) -> Self: - """ - Load a target from a dictionary. - """ + """Load a target from a dictionary.""" timezone = ZoneInfo(key="GMT") name = target_dict["name"] active_flag = target_dict["active_flag"] @@ -201,9 +188,7 @@ def from_dict(cls, target_dict: TargetDict) -> Self: ) def to_dict(self) -> TargetDict: - """ - Dump a target to a dictionary which can be loaded as JSON. - """ + """Dump a target to a dictionary which can be loaded as JSON.""" delete_date: str | None = None if self.delete_date: delete_date = self.delete_date.isoformat() diff --git a/src/mock_vws/target_manager.py b/src/mock_vws/target_manager.py index 9dc08870a..8042f588e 100644 --- a/src/mock_vws/target_manager.py +++ b/src/mock_vws/target_manager.py @@ -1,6 +1,4 @@ -""" -A fake implementation of a Vuforia target manager. -""" +"""A fake implementation of a Vuforia target manager.""" from typing import TYPE_CHECKING @@ -15,13 +13,13 @@ @beartype class TargetManager: """ - A target manager as per https://developer.vuforia.com/target-manager. + A target manager. + + See https://developer.vuforia.com/target-manager. """ def __init__(self) -> None: - """ - Create a target manager with no databases. - """ + """Create a target manager with no databases.""" self._databases: Iterable[VuforiaDatabase] = set() def remove_database(self, database: VuforiaDatabase) -> None: @@ -85,7 +83,5 @@ def add_database(self, database: VuforiaDatabase) -> None: @property def databases(self) -> set[VuforiaDatabase]: - """ - All cloud databases. - """ + """All cloud databases.""" return set(self._databases) diff --git a/src/mock_vws/target_raters.py b/src/mock_vws/target_raters.py index d52c48122..ad75099fb 100644 --- a/src/mock_vws/target_raters.py +++ b/src/mock_vws/target_raters.py @@ -1,6 +1,4 @@ -""" -Raters for target quality. -""" +"""Raters for target quality.""" import functools import io @@ -46,9 +44,7 @@ def _get_brisque_target_tracking_rating(*, image_content: bytes) -> int: @runtime_checkable class TargetTrackingRater(Protocol): - """ - Protocol for a rater of target quality. - """ + """Protocol for a rater of target quality.""" def __call__(self, image_content: bytes) -> int: """The target tracking rating. @@ -63,9 +59,7 @@ def __call__(self, image_content: bytes) -> int: @beartype class RandomTargetTrackingRater: - """ - A rater which returns a random number. - """ + """A rater which returns a random number.""" def __call__(self, image_content: bytes) -> int: """A random target tracking rating. @@ -79,9 +73,7 @@ def __call__(self, image_content: bytes) -> int: @beartype class HardcodedTargetTrackingRater: - """ - A rater which returns a hardcoded number. - """ + """A rater which returns a hardcoded number.""" def __init__(self, rating: int) -> None: """ @@ -102,9 +94,7 @@ def __call__(self, image_content: bytes) -> int: @beartype class BrisqueTargetTrackingRater: - """ - A rater which returns a rating based on a BRISQUE score. - """ + """A rater which returns a rating based on a BRISQUE score.""" def __call__(self, image_content: bytes) -> int: """A rating based on a BRISQUE score. 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 ce7b979b7..64ef1427f 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 base64 import binascii @@ -22,9 +20,7 @@ @pytest.fixture(name="vws_client") def fixture_vws_client(vuforia_database: VuforiaDatabase) -> VWS: - """ - A VWS client for an active VWS database. - """ + """A VWS client for an active VWS database.""" return VWS( server_access_key=vuforia_database.server_access_key, server_secret_key=vuforia_database.server_secret_key, @@ -33,9 +29,7 @@ def fixture_vws_client(vuforia_database: VuforiaDatabase) -> VWS: @pytest.fixture def cloud_reco_client(vuforia_database: VuforiaDatabase) -> CloudRecoService: - """ - A query client for an active VWS database. - """ + """A query client for an active VWS database.""" return CloudRecoService( client_access_key=vuforia_database.client_access_key, client_secret_key=vuforia_database.client_secret_key, @@ -44,9 +38,7 @@ def cloud_reco_client(vuforia_database: VuforiaDatabase) -> CloudRecoService: @pytest.fixture(name="inactive_vws_client") def fixture_inactive_vws_client(inactive_database: VuforiaDatabase) -> VWS: - """ - A client for an inactive VWS database. - """ + """A client for an inactive VWS database.""" return VWS( server_access_key=inactive_database.server_access_key, server_secret_key=inactive_database.server_secret_key, @@ -57,9 +49,7 @@ def fixture_inactive_vws_client(inactive_database: VuforiaDatabase) -> VWS: def inactive_cloud_reco_client( inactive_database: VuforiaDatabase, ) -> CloudRecoService: - """ - A query client for an inactive VWS database. - """ + """A query client for an inactive VWS database.""" return CloudRecoService( client_access_key=inactive_database.client_access_key, client_secret_key=inactive_database.client_secret_key, @@ -99,7 +89,8 @@ def target_id( ) def endpoint(request: pytest.FixtureRequest) -> Endpoint: """ - Return details of an endpoint for the Target API or the Query API. + Return details of an endpoint for the Target API or the Query + API. """ endpoint_fixture: Endpoint = request.getfixturevalue(argname=request.param) return endpoint_fixture @@ -126,7 +117,8 @@ def endpoint(request: pytest.FixtureRequest) -> Endpoint: ], ) def not_base64_encoded_processable(request: pytest.FixtureRequest) -> str: - """Return a string which is not decodable as base64 data, but Vuforia will + """Return a string which is not decodable as base64 data, but Vuforia + will respond as if this is valid base64 data. ``UNPROCESSABLE_ENTITY`` when this is given. @@ -150,7 +142,8 @@ def not_base64_encoded_processable(request: pytest.FixtureRequest) -> str: ) def not_base64_encoded_not_processable(request: pytest.FixtureRequest) -> str: """ - Return a string which is not decodable as base64 data, and Vuforia will + Return a string which is not decodable as base64 data, and Vuforia + will return an ``UNPROCESSABLE_ENTITY`` response when this is given. """ not_base64_encoded_string: str = request.param diff --git a/tests/mock_vws/__init__.py b/tests/mock_vws/__init__.py index bb7d2138d..55becaf36 100644 --- a/tests/mock_vws/__init__.py +++ b/tests/mock_vws/__init__.py @@ -1,6 +1,4 @@ -""" -A mock implementation of Vuforia Web Services. -""" +"""A mock implementation of Vuforia Web Services.""" import pytest diff --git a/tests/mock_vws/fixtures/__init__.py b/tests/mock_vws/fixtures/__init__.py index fd67d619b..3ab52191a 100644 --- a/tests/mock_vws/fixtures/__init__.py +++ b/tests/mock_vws/fixtures/__init__.py @@ -1,3 +1 @@ -""" -Common fixtures. -""" +"""Common fixtures.""" diff --git a/tests/mock_vws/fixtures/credentials.py b/tests/mock_vws/fixtures/credentials.py index 5fbc1ed9d..90fe125b4 100644 --- a/tests/mock_vws/fixtures/credentials.py +++ b/tests/mock_vws/fixtures/credentials.py @@ -1,6 +1,4 @@ -""" -Fixtures for credentials for Vuforia databases. -""" +"""Fixtures for credentials for Vuforia databases.""" from pathlib import Path @@ -12,9 +10,7 @@ class _VuforiaDatabaseSettings(BaseSettings): - """ - Settings for a Vuforia database. - """ + """Settings for a Vuforia database.""" target_manager_database_name: str server_access_key: str @@ -30,9 +26,7 @@ class _VuforiaDatabaseSettings(BaseSettings): class _InactiveVuforiaDatabaseSettings(_VuforiaDatabaseSettings): - """ - Settings for an inactive Vuforia database. - """ + """Settings for an inactive Vuforia database.""" model_config = SettingsConfigDict( env_prefix="INACTIVE_VUFORIA_", @@ -43,9 +37,7 @@ class _InactiveVuforiaDatabaseSettings(_VuforiaDatabaseSettings): @pytest.fixture def vuforia_database() -> VuforiaDatabase: - """ - Return VWS credentials from environment variables. - """ + """Return VWS credentials from environment variables.""" settings = _VuforiaDatabaseSettings.model_validate(obj={}) return VuforiaDatabase( database_name=settings.target_manager_database_name, @@ -60,7 +52,8 @@ def vuforia_database() -> VuforiaDatabase: @pytest.fixture def inactive_database() -> VuforiaDatabase: """ - Return VWS credentials for an inactive project from environment variables. + Return VWS credentials for an inactive project from environment + variables. """ settings = _InactiveVuforiaDatabaseSettings.model_validate(obj={}) return VuforiaDatabase( diff --git a/tests/mock_vws/fixtures/prepared_requests.py b/tests/mock_vws/fixtures/prepared_requests.py index ac813c943..6a1d93aa8 100644 --- a/tests/mock_vws/fixtures/prepared_requests.py +++ b/tests/mock_vws/fixtures/prepared_requests.py @@ -1,6 +1,4 @@ -""" -Fixtures which prepare requests. -""" +"""Fixtures which prepare requests.""" import base64 import io @@ -40,9 +38,7 @@ def add_target( vuforia_database: VuforiaDatabase, image_file_failed_state: io.BytesIO, ) -> Endpoint: - """ - Return details of the endpoint for adding a target. - """ + """Return details of the endpoint for adding a target.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -97,9 +93,7 @@ def delete_target( target_id: str, vws_client: VWS, ) -> Endpoint: - """ - Return details of the endpoint for deleting a target. - """ + """Return details of the endpoint for deleting a target.""" _wait_for_target_processed(vws_client=vws_client, target_id=target_id) date = rfc_1123_date() request_path = f"/targets/{target_id}" @@ -140,7 +134,8 @@ def delete_target( @pytest.fixture def database_summary(vuforia_database: VuforiaDatabase) -> Endpoint: """ - Return details of the endpoint for getting details about the database. + Return details of the endpoint for getting details about the + database. """ date = rfc_1123_date() request_path = "/summary" @@ -233,9 +228,7 @@ def get_target( target_id: str, vws_client: VWS, ) -> Endpoint: - """ - Return details of the endpoint for getting details of a target. - """ + """Return details of the endpoint for getting details of a target.""" _wait_for_target_processed(vws_client=vws_client, target_id=target_id) date = rfc_1123_date() request_path = f"/targets/{target_id}" @@ -276,9 +269,7 @@ def get_target( @pytest.fixture def target_list(vuforia_database: VuforiaDatabase) -> Endpoint: - """ - Return details of the endpoint for getting a list of targets. - """ + """Return details of the endpoint for getting a list of targets.""" date = rfc_1123_date() request_path = "/targets" method = HTTPMethod.GET @@ -323,7 +314,8 @@ def target_summary( vws_client: VWS, ) -> Endpoint: """ - Return details of the endpoint for getting a summary report of a target. + Return details of the endpoint for getting a summary report of a + target. """ _wait_for_target_processed(vws_client=vws_client, target_id=target_id) date = rfc_1123_date() @@ -369,9 +361,7 @@ def update_target( target_id: str, vws_client: VWS, ) -> Endpoint: - """ - Return details of the endpoint for updating a target. - """ + """Return details of the endpoint for updating a target.""" _wait_for_target_processed(vws_client=vws_client, target_id=target_id) data: dict[str, Any] = {} request_path = f"/targets/{target_id}" @@ -419,7 +409,8 @@ def query( high_quality_image: io.BytesIO, ) -> Endpoint: """ - Return details of the endpoint for making an image recognition query. + Return details of the endpoint for making an image recognition + query. """ image_content = high_quality_image.getvalue() date = rfc_1123_date() diff --git a/tests/mock_vws/fixtures/vuforia_backends.py b/tests/mock_vws/fixtures/vuforia_backends.py index ddfdbf16c..39013b5b9 100644 --- a/tests/mock_vws/fixtures/vuforia_backends.py +++ b/tests/mock_vws/fixtures/vuforia_backends.py @@ -1,6 +1,4 @@ -""" -Choose which backends to use for the tests. -""" +"""Choose which backends to use for the tests.""" import contextlib import logging @@ -66,9 +64,7 @@ def _enable_use_real_vuforia( inactive_database: VuforiaDatabase, monkeypatch: pytest.MonkeyPatch, ) -> Generator[None]: - """ - Test against the real Vuforia. - """ + """Test against the real Vuforia.""" assert monkeypatch assert inactive_database _delete_all_targets(database_keys=working_database) @@ -82,9 +78,7 @@ def _enable_use_mock_vuforia( inactive_database: VuforiaDatabase, monkeypatch: pytest.MonkeyPatch, ) -> Generator[None]: - """ - Test against the in-memory mock Vuforia. - """ + """Test against the in-memory mock Vuforia.""" assert monkeypatch working_database = VuforiaDatabase( database_name=working_database.database_name, @@ -116,9 +110,7 @@ def _enable_use_docker_in_memory( inactive_database: VuforiaDatabase, monkeypatch: pytest.MonkeyPatch, ) -> Generator[None]: - """ - Test against mock Vuforia created to be run in a container. - """ + """Test against mock Vuforia created to be run in a container.""" # We set ``wsgi.input_terminated`` to ``True`` so that when going through # ``requests`` in our tests, the Flask applications # have the given ``Content-Length`` headers and the given data in @@ -183,9 +175,7 @@ def _enable_use_docker_in_memory( class VuforiaBackend(Enum): - """ - Backends for tests. - """ + """Backends for tests.""" REAL = "Real Vuforia" MOCK = "In Memory Mock Vuforia" @@ -195,7 +185,8 @@ class VuforiaBackend(Enum): @beartype def pytest_addoption(parser: pytest.Parser) -> None: """ - Add options to the pytest command line for skipping tests with particular + Add options to the pytest command line for skipping tests with + particular backends. """ for backend in VuforiaBackend: @@ -219,9 +210,7 @@ def pytest_collection_modifyitems( config: pytest.Config, items: list[pytest.Function], ) -> None: - """ - Skip Docker tests if requested. - """ + """Skip Docker tests if requested.""" skip_docker_build_tests_option = "--skip-docker_build_tests" skip_docker_build_tests_marker = pytest.mark.skip( reason=( @@ -246,7 +235,8 @@ def fixture_verify_mock_vuforia( inactive_database: VuforiaDatabase, monkeypatch: pytest.MonkeyPatch, ) -> Generator[None]: - """Test functions which use this fixture are run multiple times. Once with + """Test functions which use this fixture are run multiple times. Once + with the real Vuforia, and once with each mock. This is useful for verifying the mocks. @@ -289,7 +279,8 @@ def mock_only_vuforia( inactive_database: VuforiaDatabase, monkeypatch: pytest.MonkeyPatch, ) -> Generator[None]: - """Test functions which use this fixture are run multiple times. Once with + """Test functions which use this fixture are run multiple times. Once + with the each mock. This is useful for testing the mock using fixtures which connect to diff --git a/tests/mock_vws/test_add_target.py b/tests/mock_vws/test_add_target.py index 7134b994b..d732dc94f 100644 --- a/tests/mock_vws/test_add_target.py +++ b/tests/mock_vws/test_add_target.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the add target endpoint. -""" +"""Tests for the mock of the add target endpoint.""" import base64 import io @@ -88,9 +86,7 @@ def assert_success(response: Response) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestContentTypes: - """ - Tests for the `Content-Type` header. - """ + """Tests for the `Content-Type` header.""" @staticmethod @pytest.mark.parametrize( @@ -111,9 +107,7 @@ def test_content_types( image_file_failed_state: io.BytesIO, content_type: str, ) -> None: - """ - Any non-empty ``Content-Type`` header is allowed. - """ + """Any non-empty ``Content-Type`` header is allowed.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -139,7 +133,8 @@ def test_empty_content_type( image_file_failed_state: io.BytesIO, ) -> None: """ - An ``UNAUTHORIZED`` response is given if an empty ``Content-Type`` + An ``UNAUTHORIZED`` response is given if an empty ``Content- + Type`` header is given. """ image_data = image_file_failed_state.getvalue() @@ -171,9 +166,7 @@ def test_empty_content_type( @pytest.mark.usefixtures("verify_mock_vuforia") class TestMissingData: - """ - Tests for giving incomplete data. - """ + """Tests for giving incomplete data.""" @staticmethod @pytest.mark.parametrize( @@ -185,9 +178,7 @@ def test_missing_data( image_file_failed_state: io.BytesIO, data_to_remove: str, ) -> None: - """ - `name`, `width` and `image` are all required. - """ + """`name`, `width` and `image` are all required.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii", @@ -212,9 +203,7 @@ def test_missing_data( @pytest.mark.usefixtures("verify_mock_vuforia") class TestWidth: - """ - Tests for the target width field. - """ + """Tests for the target width field.""" @staticmethod @pytest.mark.parametrize( @@ -227,9 +216,7 @@ def test_width_invalid( image_file_failed_state: io.BytesIO, width: int | str | None, ) -> None: - """ - The width must be a number greater than zero. - """ + """The width must be a number greater than zero.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -255,9 +242,7 @@ def test_width_valid( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - Positive numbers are valid widths. - """ + """Positive numbers are valid widths.""" vws_client.add_target( name="example", width=0.01, @@ -269,9 +254,7 @@ def test_width_valid( @pytest.mark.usefixtures("verify_mock_vuforia") class TestTargetName: - """ - Tests for the target name field. - """ + """Tests for the target name field.""" _MAX_CHAR_VALUE = 65535 _MAX_NAME_LENGTH = 64 @@ -294,9 +277,7 @@ def test_name_valid( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - Names between 1 and 64 characters in length are valid. - """ + """Names between 1 and 64 characters in length are valid.""" vws_client.add_target( name=name, width=1, @@ -335,7 +316,8 @@ def test_name_invalid( vws_client: VWS, ) -> None: """ - A target's name must be a string of length 0 < N < 65, with characters + A target's name must be a string of length 0 < N < 65, with + characters in a particular range. """ image_data = image_file_failed_state.getvalue() @@ -370,9 +352,7 @@ def test_existing_target_name( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - Only one target can have a given name. - """ + """Only one target can have a given name.""" vws_client.add_target( name="example_name", width=1, @@ -401,9 +381,7 @@ def test_deleted_existing_target_name( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - A target can be added with the name of a deleted target. - """ + """A target can be added with the name of a deleted target.""" target_id = vws_client.add_target( name="example_name", width=1, @@ -437,7 +415,8 @@ def test_image_valid( image_files_failed_state: io.BytesIO, ) -> None: """ - JPEG and PNG files in the RGB and greyscale color spaces are allowed. + JPEG and PNG files in the RGB and greyscale color spaces are + allowed. """ vws_client.add_target( name="example_name", @@ -453,7 +432,8 @@ def test_bad_image_format_or_color_space( vws_client: VWS, ) -> None: """ - An `UNPROCESSABLE_ENTITY` response is returned if an image which is not + An `UNPROCESSABLE_ENTITY` response is returned if an image which + is not a JPEG or PNG file is given, or if the given image is not in the greyscale or RGB color space. """ @@ -477,9 +457,7 @@ def test_corrupted( corrupted_image_file: io.BytesIO, vws_client: VWS, ) -> None: - """ - An error is returned when the given image is corrupted. - """ + """An error is returned when the given image is corrupted.""" with pytest.raises(expected_exception=BadImageError) as exc: vws_client.add_target( name="example_name", @@ -498,7 +476,8 @@ def test_corrupted( @staticmethod def test_image_file_size_too_large(vws_client: VWS) -> None: """ - An ``ImageTooLargeError`` result is returned if the image file size is + An ``ImageTooLargeError`` result is returned if the image file + size is above a certain threshold. """ max_bytes = 2.3 * 1024 * 1024 @@ -567,7 +546,8 @@ def test_not_base64_encoded_processable( vws_client: VWS, not_base64_encoded_processable: str, ) -> None: - """Some strings which are not valid base64 encoded strings are allowed + """Some strings which are not valid base64 encoded strings are + allowed as an image without getting a "Fail" response. This is because Vuforia treats them as valid base64, but then @@ -595,7 +575,8 @@ def test_not_base64_encoded_not_processable( ) -> None: """ Some strings which are not valid base64 encoded strings are not - processable by Vuforia, and then when given as an image Vuforia returns + processable by Vuforia, and then when given as an image Vuforia + returns a "Fail" response. """ data = { @@ -616,7 +597,8 @@ def test_not_base64_encoded_not_processable( @staticmethod def test_not_image(vws_client: VWS) -> None: """ - If the given image is not an image file then a `BadImageError` result + If the given image is not an image file then a `BadImageError` + result is returned. """ with pytest.raises(expected_exception=BadImageError) as exc: @@ -643,9 +625,7 @@ def test_invalid_type( invalid_type_image: int | None, vws_client: VWS, ) -> None: - """ - If the given image is not a string, a `Fail` result is returned. - """ + """If the given image is not a string, a `Fail` result is returned.""" data = { "name": "example_name", "width": 1, @@ -664,9 +644,7 @@ def test_invalid_type( @pytest.mark.usefixtures("verify_mock_vuforia") class TestActiveFlag: - """ - Tests for the active flag parameter. - """ + """Tests for the active flag parameter.""" @staticmethod @pytest.mark.parametrize( @@ -679,9 +657,7 @@ def test_valid( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - Boolean values and NULL are valid active flags. - """ + """Boolean values and NULL are valid active flags.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii", @@ -709,7 +685,8 @@ def test_invalid( vws_client: VWS, ) -> None: """ - Values which are not Boolean values or NULL are not valid active flags. + Values which are not Boolean values or NULL are not valid active + flags. """ active_flag = "string" image_data = image_file_failed_state.getvalue() @@ -743,9 +720,7 @@ def test_not_set( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - The active flag defaults to True if it is not set. - """ + """The active flag defaults to True if it is not set.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -768,9 +743,7 @@ def test_set_to_none( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - The active flag defaults to True if it is set to NULL. - """ + """The active flag defaults to True if it is set to NULL.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -794,7 +767,8 @@ def test_set_to_none( @pytest.mark.usefixtures("verify_mock_vuforia") class TestUnexpectedData: """ - Tests for passing data which is not mandatory or allowed to the endpoint. + Tests for passing data which is not mandatory or allowed to the + endpoint. """ @staticmethod @@ -803,7 +777,8 @@ def test_invalid_extra_data( image_file_failed_state: io.BytesIO, ) -> None: """ - A `BAD_REQUEST` response is returned when unexpected data is given. + A `BAD_REQUEST` response is returned when unexpected data is + given. """ image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( @@ -829,9 +804,7 @@ def test_invalid_extra_data( @pytest.mark.usefixtures("verify_mock_vuforia") class TestApplicationMetadata: - """ - Tests for the application metadata parameter. - """ + """Tests for the application metadata parameter.""" @staticmethod @pytest.mark.parametrize( @@ -847,9 +820,7 @@ def test_base64_encoded( metadata: bytes, vws_client: VWS, ) -> None: - """ - A base64 encoded string is valid application metadata. - """ + """A base64 encoded string is valid application metadata.""" metadata_encoded = base64.b64encode(s=metadata).decode( encoding="ascii" ) @@ -867,9 +838,7 @@ def test_null( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - NULL is valid application metadata. - """ + """NULL is valid application metadata.""" image_data = image_file_failed_state.getvalue() image_data_encoded = base64.b64encode(s=image_data).decode( encoding="ascii" @@ -926,7 +895,8 @@ def test_not_base64_encoded_processable( vws_client: VWS, ) -> None: """ - Some strings which are not valid base64 encoded strings are allowed as + Some strings which are not valid base64 encoded strings are + allowed as application metadata. """ vws_client.add_target( @@ -944,7 +914,8 @@ def test_not_base64_encoded_not_processable( vws_client: VWS, ) -> None: """ - Some strings which are not valid base64 encoded strings are not allowed + Some strings which are not valid base64 encoded strings are not + allowed as application metadata. """ with pytest.raises(expected_exception=FailError) as exc: @@ -968,7 +939,8 @@ def test_metadata_too_large( vws_client: VWS, ) -> None: """ - A base64 encoded string of greater than 1024 * 1024 bytes is too large + A base64 encoded string of greater than 1024 * 1024 bytes is too + large for application metadata. """ metadata = b"a" * (_MAX_METADATA_BYTES + 1) @@ -994,9 +966,7 @@ def test_metadata_too_large( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project( @@ -1004,7 +974,8 @@ def test_inactive_project( inactive_vws_client: VWS, ) -> None: """ - If the project is inactive, a FORBIDDEN response is returned. + If the project is inactive, a FORBIDDEN response is + returned. """ with pytest.raises(expected_exception=ProjectInactiveError) as exc: inactive_vws_client.add_target( diff --git a/tests/mock_vws/test_authorization_header.py b/tests/mock_vws/test_authorization_header.py index 3cde8cd05..c017c41ad 100644 --- a/tests/mock_vws/test_authorization_header.py +++ b/tests/mock_vws/test_authorization_header.py @@ -1,6 +1,4 @@ -""" -Tests for the `Authorization` header. -""" +"""Tests for the `Authorization` header.""" import io import json @@ -28,13 +26,15 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestAuthorizationHeader: """ - Tests for what happens when the `Authorization` header is not as expected. + Tests for what happens when the `Authorization` header is not as + expected. """ @staticmethod def test_missing(endpoint: Endpoint) -> None: """ - An `UNAUTHORIZED` response is returned when no `Authorization` header + An `UNAUTHORIZED` response is returned when no `Authorization` + header is given. """ date = rfc_1123_date() @@ -82,13 +82,12 @@ def test_missing(endpoint: Endpoint) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestMalformed: - """ - Tests for passing a malformed ``Authorization`` header. - """ + """Tests for passing a malformed ``Authorization`` header.""" @staticmethod def test_one_part_no_space(endpoint: Endpoint) -> None: - """A valid authorization string is two "parts" when split on a space. + """A valid authorization string is two "parts" when split on a + space. When a string is given which is one "part", a ``BAD_REQUEST`` or @@ -142,7 +141,8 @@ def test_one_part_no_space(endpoint: Endpoint) -> None: @staticmethod def test_one_part_with_space(endpoint: Endpoint) -> None: - """A valid authorization string is two "parts" when split on a space. + """A valid authorization string is two "parts" when split on a + space. When a string is given which is one "part", a ``BAD_REQUEST`` or @@ -242,16 +242,15 @@ def test_missing_signature(endpoint: Endpoint) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestBadKey: - """ - Tests for making requests with incorrect keys. - """ + """Tests for making requests with incorrect keys.""" @staticmethod def test_bad_access_key_services( vuforia_database: VuforiaDatabase, ) -> None: """ - If the server access key given does not match any database, a ``Fail`` + If the server access key given does not match any database, a + ``Fail`` response is returned. """ vws_client = VWS( diff --git a/tests/mock_vws/test_content_length.py b/tests/mock_vws/test_content_length.py index 12160dc2e..41e34fe24 100644 --- a/tests/mock_vws/test_content_length.py +++ b/tests/mock_vws/test_content_length.py @@ -1,6 +1,4 @@ -""" -Tests for the ``Content-Length`` header. -""" +"""Tests for the ``Content-Length`` header.""" import textwrap from http import HTTPStatus @@ -30,7 +28,8 @@ class TestIncorrect: @staticmethod def test_not_integer(endpoint: Endpoint) -> None: """ - A ``BAD_REQUEST`` error is given when the given ``Content-Length`` is + A ``BAD_REQUEST`` error is given when the given ``Content- + Length`` is not an integer. """ if not endpoint.headers.get("Content-Type"): @@ -92,9 +91,7 @@ def test_not_integer(endpoint: Endpoint) -> None: @staticmethod @pytest.mark.skip(reason="It takes too long to run this test.") def test_too_large(endpoint: Endpoint) -> None: # pragma: no cover - """ - An error is given if the given content length is too large. - """ + """An error is given if the given content length is too large.""" if not endpoint.headers.get("Content-Type"): pytest.skip(reason="No Content-Type header for this request") @@ -150,7 +147,8 @@ def test_too_large(endpoint: Endpoint) -> None: # pragma: no cover @staticmethod def test_too_small(endpoint: Endpoint) -> None: """ - An ``UNAUTHORIZED`` response is given if the given content length is + An ``UNAUTHORIZED`` response is given if the given content + length is too small. """ if not endpoint.headers.get("Content-Type"): diff --git a/tests/mock_vws/test_database_summary.py b/tests/mock_vws/test_database_summary.py index d1ce06f32..e0220319f 100644 --- a/tests/mock_vws/test_database_summary.py +++ b/tests/mock_vws/test_database_summary.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the database summary endpoint. -""" +"""Tests for the mock of the database summary endpoint.""" import io import logging @@ -25,9 +23,7 @@ @beartype def _log_attempt_number(retry_state: RetryCallState) -> None: - """ - Log the attempt number of a retry. - """ + """Log the attempt number of a retry.""" attempt_number: int = retry_state.attempt_number message = f"Attempt number: {attempt_number}" LOGGER.debug(msg=message) @@ -92,7 +88,8 @@ def _wait_for_image_numbers( @pytest.mark.usefixtures("verify_mock_vuforia") class TestDatabaseSummary: """ - Tests for the mock of the database summary endpoint at `GET /summary`. + Tests for the mock of the database summary endpoint at `GET + /summary`. """ @staticmethod @@ -100,9 +97,7 @@ def test_success( vuforia_database: VuforiaDatabase, vws_client: VWS, ) -> None: - """ - It is possible to get a success response. - """ + """It is possible to get a success response.""" report = vws_client.get_database_summary_report() assert report.name == vuforia_database.database_name @@ -116,9 +111,7 @@ def test_success( @staticmethod def test_active_images(vws_client: VWS, target_id: str) -> None: - """ - The number of images in the active state is returned. - """ + """The number of images in the active state is returned.""" vws_client.wait_for_target_processed(target_id=target_id) _wait_for_image_numbers( @@ -134,9 +127,7 @@ def test_failed_images( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - The number of images with a 'failed' status is returned. - """ + """The number of images with a 'failed' status is returned.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -161,7 +152,8 @@ def test_inactive_images( image_file_success_state_low_rating: io.BytesIO, ) -> None: """ - The number of images with a False active_flag and a 'success' status is + The number of images with a False active_flag and a 'success' + status is returned. """ target_id = vws_client.add_target( @@ -187,9 +179,7 @@ def test_inactive_failed( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - An image with a 'failed' status does not show as inactive. - """ + """An image with a 'failed' status does not show as inactive.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -213,9 +203,7 @@ def test_deleted( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - Deleted targets are not shown in the summary. - """ + """Deleted targets are not shown in the summary.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -250,9 +238,7 @@ class TestProcessingImages: def test_processing_images( image_file_success_state_low_rating: io.BytesIO, ) -> None: - """ - The number of images in the processing state is returned. - """ + """The number of images in the processing state is returned.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -280,9 +266,7 @@ def test_processing_images( @pytest.mark.usefixtures("verify_mock_vuforia") class TestQuotas: - """ - Tests for quotas and thresholds. - """ + """Tests for quotas and thresholds.""" @staticmethod def test_quotas(vws_client: VWS) -> None: @@ -301,9 +285,7 @@ def test_quotas(vws_client: VWS) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestRecos: - """ - Tests for the recognition count fields. - """ + """Tests for the recognition count fields.""" @staticmethod def test_query_request( @@ -311,7 +293,8 @@ def test_query_request( high_quality_image: io.BytesIO, vws_client: VWS, ) -> None: - """The ``*_recos`` counts seem to be delayed by a significant amount of + """The ``*_recos`` counts seem to be delayed by a significant + amount of time. We therefore test that they exist, are integers and do not @@ -343,14 +326,13 @@ def test_query_request( @pytest.mark.usefixtures("verify_mock_vuforia") class TestRequestUsage: - """ - Tests for the ``request_usage`` field. - """ + """Tests for the ``request_usage`` field.""" @staticmethod def test_target_request(vws_client: VWS) -> None: """ - The ``request_usage`` count does not increase with each request to the + The ``request_usage`` count does not increase with each request + to the target API. """ report = vws_client.get_database_summary_report() @@ -366,7 +348,8 @@ def test_bad_target_request( vws_client: VWS, ) -> None: """ - The ``request_usage`` count does not increase with each request to the + The ``request_usage`` count does not increase with each request + to the target API, even if it is a bad request. """ report = vws_client.get_database_summary_report() @@ -394,7 +377,8 @@ def test_query_request( vws_client: VWS, ) -> None: """ - The ``request_usage`` count does not increase with each query. + The ``request_usage`` count does not increase with each + query. """ report = vws_client.get_database_summary_report() original_request_usage = report.request_usage @@ -408,15 +392,11 @@ def test_query_request( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project( inactive_vws_client: VWS, ) -> None: - """ - The project's active state does not affect the database summary. - """ + """The project's active state does not affect the database summary.""" inactive_vws_client.get_database_summary_report() diff --git a/tests/mock_vws/test_date_header.py b/tests/mock_vws/test_date_header.py index 9c4c2302d..eea178ac3 100644 --- a/tests/mock_vws/test_date_header.py +++ b/tests/mock_vws/test_date_header.py @@ -1,6 +1,4 @@ -""" -Tests for the `Date` header. -""" +"""Tests for the `Date` header.""" import json from datetime import datetime, timedelta @@ -30,14 +28,13 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestMissing: - """ - Tests for what happens when the `Date` header is missing. - """ + """Tests for what happens when the `Date` header is missing.""" @staticmethod def test_no_date_header(endpoint: Endpoint) -> None: """ - A `BAD_REQUEST` response is returned when no `Date` header is given. + A `BAD_REQUEST` response is returned when no `Date` header is + given. """ authorization_string = authorization_header( access_key=endpoint.access_key, @@ -102,7 +99,8 @@ class TestFormat: @staticmethod def test_incorrect_date_format(endpoint: Endpoint) -> None: - """A `BAD_REQUEST` response is returned when the date given in the date + """A `BAD_REQUEST` response is returned when the date given in the + date header is not in the expected format (RFC 1123) to VWS API. An `UNAUTHORIZED` response is returned to the VWQ API. @@ -166,14 +164,16 @@ def test_incorrect_date_format(endpoint: Endpoint) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestSkewedTime: """ - Tests for what happens when the `Date` header is given with an unexpected + Tests for what happens when the `Date` header is given with an + unexpected time. """ @staticmethod def test_date_out_of_range_after(endpoint: Endpoint) -> None: """If the date header is more than five minutes (target API) or 65 - minutes (query API) after the request is sent, a `FORBIDDEN` response + minutes (query API) after the request is sent, a `FORBIDDEN` + response is returned. Because there is a small delay in sending requests and Vuforia @@ -249,7 +249,8 @@ def test_date_out_of_range_after(endpoint: Endpoint) -> None: @staticmethod def test_date_out_of_range_before(endpoint: Endpoint) -> None: """If the date header is more than five minutes (target API) or 65 - minutes (query API) before the request is sent, a `FORBIDDEN` response + minutes (query API) before the request is sent, a `FORBIDDEN` + response is returned. Because there is a small delay in sending requests and Vuforia @@ -324,7 +325,8 @@ def test_date_out_of_range_before(endpoint: Endpoint) -> None: @staticmethod def test_date_in_range_after(endpoint: Endpoint) -> None: - """If a date header is within five minutes after the request is sent, + """If a date header is within five minutes after the request is + sent, no error is returned. Because there is a small delay in sending requests and Vuforia @@ -387,7 +389,8 @@ def test_date_in_range_after(endpoint: Endpoint) -> None: @staticmethod def test_date_in_range_before(endpoint: Endpoint) -> None: - """If a date header is within five minutes before the request is sent, + """If a date header is within five minutes before the request is + sent, no error is returned. Because there is a small delay in sending requests and Vuforia diff --git a/tests/mock_vws/test_delete_target.py b/tests/mock_vws/test_delete_target.py index 755d9b24c..9c3f68d1e 100644 --- a/tests/mock_vws/test_delete_target.py +++ b/tests/mock_vws/test_delete_target.py @@ -1,6 +1,4 @@ -""" -Tests for deleting targets. -""" +"""Tests for deleting targets.""" from http import HTTPStatus @@ -18,13 +16,12 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestDelete: - """ - Tests for deleting targets. - """ + """Tests for deleting targets.""" @staticmethod def test_no_wait(target_id: str, vws_client: VWS) -> None: - """When attempting to delete a target immediately after creating it, a + """When attempting to delete a target immediately after creating + it, a `FORBIDDEN` response is returned. This is because the target goes into a processing state. @@ -45,9 +42,7 @@ def test_no_wait(target_id: str, vws_client: VWS) -> None: @staticmethod def test_processed(target_id: str, vws_client: VWS) -> None: - """ - When a target has finished processing, it can be deleted. - """ + """When a target has finished processing, it can be deleted.""" vws_client.wait_for_target_processed(target_id=target_id) vws_client.delete_target(target_id=target_id) @@ -57,14 +52,13 @@ def test_processed(target_id: str, vws_client: VWS) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: """ - If the project is inactive, a FORBIDDEN response is returned. + If the project is inactive, a FORBIDDEN response is + returned. """ target_id = "abc12345a" with pytest.raises(expected_exception=ProjectInactiveError) as exc: diff --git a/tests/mock_vws/test_docker.py b/tests/mock_vws/test_docker.py index d3d18c16a..0484cb253 100644 --- a/tests/mock_vws/test_docker.py +++ b/tests/mock_vws/test_docker.py @@ -1,6 +1,4 @@ -""" -Tests for running the mock server in Docker. -""" +"""Tests for running the mock server in Docker.""" import io import uuid @@ -37,9 +35,7 @@ ) @beartype def wait_for_health_check(container: Container) -> None: - """ - Wait for a container to pass its health check. - """ + """Wait for a container to pass its health check.""" container.reload() health_status = container.attrs["State"]["Health"]["Status"] # In theory this might not be hit by coverage. @@ -97,7 +93,8 @@ def test_build_and_run( request: pytest.FixtureRequest, ) -> None: """ - It is possible to build Docker images which combine to make a working mock + It is possible to build Docker images which combine to make a + working mock application. """ repository_root = request.config.rootpath diff --git a/tests/mock_vws/test_flask_app_usage.py b/tests/mock_vws/test_flask_app_usage.py index d79b998fe..fffd06804 100644 --- a/tests/mock_vws/test_flask_app_usage.py +++ b/tests/mock_vws/test_flask_app_usage.py @@ -1,6 +1,4 @@ -""" -Tests for the usage of the mock Flask application. -""" +"""Tests for the usage of the mock Flask application.""" import io import json @@ -28,9 +26,7 @@ @pytest.fixture(autouse=True) def _(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]: - """ - Enable a mock service backed by the Flask applications. - """ + """Enable a mock service backed by the Flask applications.""" with responses.RequestsMock( assert_all_requests_are_fired=False, ) as mock_obj: @@ -61,9 +57,7 @@ def _(monkeypatch: pytest.MonkeyPatch) -> Iterator[None]: class TestProcessingTime: - """ - Tests for the time taken to process targets in the mock. - """ + """Tests for the time taken to process targets in the mock.""" # There is a race condition in this test type - if tests start to # fail, consider increasing the leeway. @@ -73,9 +67,7 @@ def test_default( self, image_file_failed_state: io.BytesIO, ) -> None: - """ - By default, targets in the mock takes 2 seconds to be processed. - """ + """By default, targets in the mock takes 2 seconds to be processed.""" database = VuforiaDatabase() databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" requests.post(url=databases_url, json=database.to_dict(), timeout=30) @@ -93,9 +85,7 @@ def test_custom( image_file_failed_state: io.BytesIO, monkeypatch: pytest.MonkeyPatch, ) -> None: - """ - It is possible to set a custom processing time. - """ + """It is possible to set a custom processing time.""" seconds = 5.0 monkeypatch.setenv( name="PROCESSING_TIME_SECONDS", @@ -115,14 +105,13 @@ def test_custom( class TestAddDatabase: - """ - Tests for adding databases to the mock. - """ + """Tests for adding databases to the mock.""" @staticmethod def test_duplicate_keys() -> None: """ - It is not possible to have multiple databases with matching keys. + It is not possible to have multiple databases with matching + keys. """ database = VuforiaDatabase( server_access_key="1", @@ -180,9 +169,7 @@ def test_duplicate_keys() -> None: @staticmethod def test_give_no_details(high_quality_image: io.BytesIO) -> None: - """ - It is possible to create a database without giving any data. - """ + """It is possible to create a database without giving any data.""" databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" response = requests.post(url=databases_url, json={}, timeout=30) assert response.status_code == HTTPStatus.CREATED @@ -208,14 +195,13 @@ def test_give_no_details(high_quality_image: io.BytesIO) -> None: class TestDeleteDatabase: - """ - Tests for deleting databases from the mock. - """ + """Tests for deleting databases from the mock.""" @staticmethod def test_not_found() -> None: """ - A 404 error is returned when trying to delete a database which does not + A 404 error is returned when trying to delete a database which + does not exist. """ databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" @@ -225,9 +211,7 @@ def test_not_found() -> None: @staticmethod def test_delete_database() -> None: - """ - It is possible to delete a database. - """ + """It is possible to delete a database.""" databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" response = requests.post(url=databases_url, json={}, timeout=30) assert response.status_code == HTTPStatus.CREATED @@ -242,18 +226,14 @@ def test_delete_database() -> None: class TestQueryImageMatchers: - """ - Tests for query image matchers. - """ + """Tests for query image matchers.""" @staticmethod def test_exact_match( high_quality_image: io.BytesIO, monkeypatch: pytest.MonkeyPatch, ) -> None: - """ - The exact matcher matches only exactly the same images. - """ + """The exact matcher matches only exactly the same images.""" monkeypatch.setenv(name="QUERY_IMAGE_MATCHER", value="exact") database = VuforiaDatabase() @@ -297,9 +277,7 @@ def test_structural_similarity_matcher( different_high_quality_image: io.BytesIO, monkeypatch: pytest.MonkeyPatch, ) -> None: - """ - The structural similarity matcher matches similar images. - """ + """The structural similarity matcher matches similar images.""" monkeypatch.setenv( name="QUERY_IMAGE_MATCHER", value="structural_similarity", @@ -346,18 +324,14 @@ def test_structural_similarity_matcher( class TestDuplicatesImageMatchers: - """ - Tests for duplicates image matchers. - """ + """Tests for duplicates image matchers.""" @staticmethod def test_exact_match( high_quality_image: io.BytesIO, monkeypatch: pytest.MonkeyPatch, ) -> None: - """ - The exact matcher matches only exactly the same images. - """ + """The exact matcher matches only exactly the same images.""" monkeypatch.setenv(name="DUPLICATES_IMAGE_MATCHER", value="exact") database = VuforiaDatabase() vws_client = VWS( @@ -406,9 +380,7 @@ def test_structural_similarity_matcher( high_quality_image: io.BytesIO, monkeypatch: pytest.MonkeyPatch, ) -> None: - """ - The structural similarity matcher matches similar images. - """ + """The structural similarity matcher matches similar images.""" monkeypatch.setenv( name="DUPLICATES_IMAGE_MATCHER", value="structural_similarity", @@ -447,18 +419,14 @@ def test_structural_similarity_matcher( class TestTargetRaters: - """ - Tests for using target raters. - """ + """Tests for using target raters.""" @staticmethod def test_default( image_file_success_state_low_rating: io.BytesIO, high_quality_image: io.BytesIO, ) -> None: - """ - By default, the BRISQUE target rater is used. - """ + """By default, the BRISQUE target rater is used.""" database = VuforiaDatabase() databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" requests.post(url=databases_url, json=database.to_dict(), timeout=30) @@ -507,9 +475,7 @@ def test_brisque( image_file_success_state_low_rating: io.BytesIO, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to use the BRISQUE target rater. - """ + """It is possible to use the BRISQUE target rater.""" monkeypatch.setenv(name="TARGET_RATER", value="brisque") database = VuforiaDatabase() @@ -559,9 +525,7 @@ def test_perfect( monkeypatch: pytest.MonkeyPatch, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to use the perfect target rater. - """ + """It is possible to use the perfect target rater.""" monkeypatch.setenv(name="TARGET_RATER", value="perfect") database = VuforiaDatabase() databases_url = _EXAMPLE_URL_FOR_TARGET_MANAGER + "/databases" @@ -600,9 +564,7 @@ def test_random( monkeypatch: pytest.MonkeyPatch, high_quality_image: io.BytesIO, ) -> None: - """ - It is possible to use the random target rater. - """ + """It is possible to use the random target rater.""" monkeypatch.setenv(name="TARGET_RATER", value="random") database = VuforiaDatabase() diff --git a/tests/mock_vws/test_get_duplicates.py b/tests/mock_vws/test_get_duplicates.py index c52b64730..5634e8737 100644 --- a/tests/mock_vws/test_get_duplicates.py +++ b/tests/mock_vws/test_get_duplicates.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the get duplicates endpoint. -""" +"""Tests for the mock of the get duplicates endpoint.""" import copy import io @@ -15,9 +13,7 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestDuplicates: - """ - Tests for the mock of the target duplicates endpoint. - """ + """Tests for the mock of the target duplicates endpoint.""" @staticmethod def test_duplicates( @@ -25,9 +21,7 @@ def test_duplicates( image_file_success_state_low_rating: io.BytesIO, vws_client: VWS, ) -> None: - """ - Target IDs of the exact same targets are returned. - """ + """Target IDs of the exact same targets are returned.""" image_data = high_quality_image different_image_data = image_file_success_state_low_rating @@ -70,9 +64,7 @@ def test_duplicates_not_same( high_quality_image: io.BytesIO, vws_client: VWS, ) -> None: - """ - Target IDs of similar targets are returned. - """ + """Target IDs of similar targets are returned.""" image_data = high_quality_image similar_image_data = copy.copy(x=image_data) similar_image_buffer = io.BytesIO() @@ -111,9 +103,7 @@ def test_status( image_file_failed_state: io.BytesIO, vws_client: VWS, ) -> None: - """ - Targets are not duplicates if the status is not 'success'. - """ + """Targets are not duplicates if the status is not 'success'.""" original_target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -147,9 +137,7 @@ def test_status( @pytest.mark.usefixtures("verify_mock_vuforia") class TestActiveFlag: - """ - Tests for the effects of the active flag on duplicate matching. - """ + """Tests for the effects of the active flag on duplicate matching.""" @staticmethod def test_active_flag( @@ -157,7 +145,8 @@ def test_active_flag( vws_client: VWS, ) -> None: """Targets with `active_flag` set to `False` can have duplicates. - Targets with `active_flag` set to `False` are not found as duplicates. + Targets with `active_flag` set to `False` are not found as + duplicates. https://developer.vuforia.com/library/web-api/cloud-targets-web-services-api#check says: @@ -201,9 +190,7 @@ def test_active_flag( @pytest.mark.usefixtures("verify_mock_vuforia") class TestProcessing: - """ - Tests for targets in the processing stage. - """ + """Tests for targets in the processing stage.""" @staticmethod def test_processing( @@ -254,14 +241,13 @@ def test_processing( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: """ - If the project is inactive, a FORBIDDEN response is returned. + If the project is inactive, a FORBIDDEN response is + returned. """ with pytest.raises(expected_exception=ProjectInactiveError): inactive_vws_client.get_duplicate_targets( diff --git a/tests/mock_vws/test_get_target.py b/tests/mock_vws/test_get_target.py index 435982bc5..e0d22f634 100644 --- a/tests/mock_vws/test_get_target.py +++ b/tests/mock_vws/test_get_target.py @@ -14,18 +14,14 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestGetRecord: - """ - Tests for getting a target record. - """ + """Tests for getting a target record.""" @staticmethod def test_get_vws_target( vws_client: VWS, image_file_failed_state: io.BytesIO, ) -> None: - """ - Details of a target are returned. - """ + """Details of a target are returned.""" name = "my_example_name" width = 1234 @@ -61,7 +57,8 @@ def test_fail_status( image_file_failed_state: io.BytesIO, ) -> None: """ - When a 1x1 image is given, the status changes from 'processing' to + When a 1x1 image is given, the status changes from 'processing' + to 'failed' after some time. """ target_id = vws_client.add_target( @@ -83,7 +80,8 @@ def test_success_status( image_file_success_state_low_rating: io.BytesIO, vws_client: VWS, ) -> None: - """When a random, large enough image is given, the status changes from + """When a random, large enough image is given, the status changes + from 'processing' to 'success' after some time. The mock is much more lenient than the real implementation of @@ -118,9 +116,7 @@ def _get_target_tracking_rating( vws_client: VWS, image_file: io.BytesIO, ) -> int: - """ - Get the tracking rating of a target with the given image. - """ + """Get the tracking rating of a target with the given image.""" target_id = vws_client.add_target( name=f"example_{uuid.uuid4().hex}", width=1, @@ -147,9 +143,7 @@ def test_target_quality( high_quality_image: io.BytesIO, image_file_success_state_low_rating: io.BytesIO, ) -> None: - """ - The target tracking rating is as expected. - """ + """The target tracking rating is as expected.""" high_quality_image_tracking_rating = _get_target_tracking_rating( vws_client=vws_client, image_file=high_quality_image, @@ -166,14 +160,10 @@ def test_target_quality( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: - """ - The project's active state does not affect getting a target. - """ + """The project's active state does not affect getting a target.""" with pytest.raises(expected_exception=UnknownTargetError): inactive_vws_client.get_target_record(target_id=uuid.uuid4().hex) diff --git a/tests/mock_vws/test_invalid_given_id.py b/tests/mock_vws/test_invalid_given_id.py index 7857868e8..067867f75 100644 --- a/tests/mock_vws/test_invalid_given_id.py +++ b/tests/mock_vws/test_invalid_given_id.py @@ -1,5 +1,6 @@ """ -Tests for passing invalid target IDs to endpoints which require a target ID to +Tests for passing invalid target IDs to endpoints which require a target +ID to be given. """ @@ -17,7 +18,8 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestInvalidGivenID: """ - Tests for giving an invalid ID to endpoints which require a target ID to be + Tests for giving an invalid ID to endpoints which require a target + ID to be given. """ @@ -28,7 +30,8 @@ def test_not_real_id( target_id: str, ) -> None: """ - A `NOT_FOUND` error is returned when an endpoint is given a target ID + A `NOT_FOUND` error is returned when an endpoint is given a + target ID of a target which does not exist. """ if not endpoint.path_url.endswith(target_id): diff --git a/tests/mock_vws/test_invalid_json.py b/tests/mock_vws/test_invalid_json.py index afc3b75ea..55d01ff6d 100644 --- a/tests/mock_vws/test_invalid_json.py +++ b/tests/mock_vws/test_invalid_json.py @@ -1,6 +1,4 @@ -""" -Tests for giving invalid JSON to endpoints. -""" +"""Tests for giving invalid JSON to endpoints.""" import json from datetime import datetime, timedelta @@ -25,15 +23,11 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestInvalidJSON: - """ - Tests for giving invalid JSON to endpoints. - """ + """Tests for giving invalid JSON to endpoints.""" @staticmethod def test_invalid_json(endpoint: Endpoint) -> None: - """ - Giving invalid JSON to endpoints returns error responses. - """ + """Giving invalid JSON to endpoints returns error responses.""" content = b"a" gmt = ZoneInfo(key="GMT") now = datetime.now(tz=gmt) @@ -108,9 +102,7 @@ def test_invalid_json(endpoint: Endpoint) -> None: @staticmethod def test_invalid_json_with_skewed_time(endpoint: Endpoint) -> None: - """ - Giving invalid JSON to endpoints returns error responses. - """ + """Giving invalid JSON to endpoints returns error responses.""" # We use a skew of 70 because the maximum allowed skew for services is # 5 minutes, and for query is 65 minutes. 70 is comfortably larger than # the max of these two. diff --git a/tests/mock_vws/test_query.py b/tests/mock_vws/test_query.py index f2a34c16b..49151ccdb 100644 --- a/tests/mock_vws/test_query.py +++ b/tests/mock_vws/test_query.py @@ -147,9 +147,7 @@ def _query( @pytest.mark.usefixtures("verify_mock_vuforia") class TestContentType: - """ - Tests for the Content-Type header. - """ + """Tests for the Content-Type header.""" @staticmethod @pytest.mark.parametrize( @@ -208,9 +206,7 @@ def test_incorrect_no_boundary( resp_cache_control: str | None, resp_text: str, ) -> None: - """ - With bad Content-Type headers we get a variety of results. - """ + """With bad Content-Type headers we get a variety of results.""" image_content = high_quality_image.getvalue() date = rfc_1123_date() request_path = "/v1/query" @@ -272,8 +268,10 @@ def test_incorrect_with_boundary( vuforia_database: VuforiaDatabase, ) -> None: """ - If a Content-Type header which is not ``multipart/form-data`` is given - with the correct boundary, an ``UNSUPPORTED_MEDIA_TYPE`` response is + If a Content-Type header which is not ``multipart/form-data`` is + given + with the correct boundary, an ``UNSUPPORTED_MEDIA_TYPE`` response + is given. """ image_content = high_quality_image.getvalue() @@ -348,7 +346,8 @@ def test_no_boundary( content_type: str, ) -> None: """ - If no boundary is given, an ``INTERNAL_SERVER_ERROR`` is returned. + If no boundary is given, an ``INTERNAL_SERVER_ERROR`` is + returned. """ image_content = high_quality_image.getvalue() date = rfc_1123_date() @@ -408,9 +407,7 @@ def test_bogus_boundary( high_quality_image: io.BytesIO, vuforia_database: VuforiaDatabase, ) -> None: - """ - If a bogus boundary is given, a ``BAD_REQUEST`` is returned. - """ + """If a bogus boundary is given, a ``BAD_REQUEST`` is returned.""" image_content = high_quality_image.getvalue() date = rfc_1123_date() request_path = "/v1/query" @@ -472,7 +469,8 @@ def test_extra_section( vuforia_database: VuforiaDatabase, ) -> None: """ - If sections that are not the boundary section are given in the header, + If sections that are not the boundary section are given in the + header, that is fine. """ image_content = high_quality_image.getvalue() @@ -525,9 +523,7 @@ def test_extra_section( @pytest.mark.usefixtures("verify_mock_vuforia") class TestSuccess: - """ - Tests for successful calls to the query endpoint. - """ + """Tests for successful calls to the query endpoint.""" @staticmethod def test_no_results( @@ -535,7 +531,8 @@ def test_no_results( cloud_reco_client: CloudRecoService, ) -> None: """ - When there are no matching images in the database, an empty list of + When there are no matching images in the database, an empty list + of results is returned. """ results = cloud_reco_client.query(image=high_quality_image) @@ -548,7 +545,8 @@ def test_match_exact( vws_client: VWS, ) -> None: """ - If the exact high quality image that was added is queried for, target + If the exact high quality image that was added is queried for, + target data is shown. """ image_file = high_quality_image @@ -626,7 +624,8 @@ def test_match_similar( cloud_reco_client: CloudRecoService, ) -> None: """ - If a similar image to one that was added is queried for, target data is + If a similar image to one that was added is queried for, target + data is shown. """ metadata_encoded = base64.b64encode(s=b"example").decode( @@ -675,8 +674,10 @@ def test_not_base64_encoded_processable( cloud_reco_client: CloudRecoService, ) -> None: """ - Vuforia accepts some metadata strings which are not valid base64. - When a target with such a string is matched by a query, Vuforia returns + Vuforia accepts some metadata strings which are not valid + base64. + When a target with such a string is matched by a query, Vuforia + returns an interesting result: * If the metadata string is a length one greater than a multiple of 4, @@ -717,14 +718,13 @@ def test_not_base64_encoded_processable( @pytest.mark.usefixtures("verify_mock_vuforia") class TestIncorrectFields: - """ - Tests for incorrect and unexpected fields. - """ + """Tests for incorrect and unexpected fields.""" @staticmethod def test_missing_image(vuforia_database: VuforiaDatabase) -> None: """ - If an image is not given, a ``BAD_REQUEST`` response is returned. + If an image is not given, a ``BAD_REQUEST`` response is + returned. """ response = _query(vuforia_database=vuforia_database, body={}) @@ -744,7 +744,8 @@ def test_extra_fields( vuforia_database: VuforiaDatabase, ) -> None: """ - If extra fields are given, a ``BAD_REQUEST`` response is returned. + If extra fields are given, a ``BAD_REQUEST`` response is + returned. """ image_content = high_quality_image.getvalue() body = { @@ -792,9 +793,7 @@ def test_missing_image_and_extra_fields( @pytest.mark.usefixtures("verify_mock_vuforia") class TestMaxNumResults: - """ - Tests for the ``max_num_results`` parameter. - """ + """Tests for the ``max_num_results`` parameter.""" @staticmethod def test_default( @@ -802,9 +801,7 @@ def test_default( vuforia_database: VuforiaDatabase, vws_client: VWS, ) -> None: - """ - The default ``max_num_results`` is 1. - """ + """The default ``max_num_results`` is 1.""" image_content = high_quality_image.getvalue() target_id_1 = vws_client.add_target( @@ -871,9 +868,7 @@ def test_valid_works( vws_client: VWS, cloud_reco_client: CloudRecoService, ) -> None: - """ - A maximum of ``max_num_results`` results are returned. - """ + """A maximum of ``max_num_results`` results are returned.""" _add_and_wait_for_targets( image=high_quality_image, vws_client=vws_client, @@ -895,7 +890,8 @@ def test_out_of_range( num_results: int, cloud_reco_client: CloudRecoService, ) -> None: - """An error is returned if ``max_num_results`` is given as an integer + """An error is returned if ``max_num_results`` is given as an + integer out of the range (1, 50). The documentation at @@ -935,7 +931,8 @@ def test_invalid_type( vuforia_database: VuforiaDatabase, num_results: bytes, ) -> None: - """An error is returned if ``max_num_results`` is given as something + """An error is returned if ``max_num_results`` is given as + something other than an integer. Integers greater than 2147483647 are not considered integers @@ -970,9 +967,7 @@ def _add_and_wait_for_targets( vws_client: VWS, num_targets: int, ) -> None: - """ - Add targets with the given image. - """ + """Add targets with the given image.""" target_ids: Iterable[str] = set() for _ in range(num_targets): target_id = vws_client.add_target( @@ -990,9 +985,7 @@ def _add_and_wait_for_targets( @pytest.mark.usefixtures("verify_mock_vuforia") class TestIncludeTargetData: - """ - Tests for the ``include_target_data`` parameter. - """ + """Tests for the ``include_target_data`` parameter.""" @staticmethod def test_default( @@ -1000,9 +993,7 @@ def test_default( vws_client: VWS, vuforia_database: VuforiaDatabase, ) -> None: - """ - The default ``include_target_data`` is 'top'. - """ + """The default ``include_target_data`` is 'top'.""" _add_and_wait_for_targets( image=high_quality_image, vws_client=vws_client, @@ -1034,7 +1025,8 @@ def test_top( vws_client: VWS, ) -> None: """ - When ``include_target_data`` is set to "top" (case insensitive), only + When ``include_target_data`` is set to "top" (case insensitive), + only the first result includes target data. """ _add_and_wait_for_targets( @@ -1069,7 +1061,8 @@ def test_none( vws_client: VWS, ) -> None: """ - When ``include_target_data`` is set to "none" (case insensitive), no + When ``include_target_data`` is set to "none" (case + insensitive), no results include target data. """ _add_and_wait_for_targets( @@ -1104,7 +1097,8 @@ def test_all( vws_client: VWS, ) -> None: """ - When ``include_target_data`` is set to "all" (case insensitive), all + When ``include_target_data`` is set to "all" (case insensitive), + all results include target data. """ _add_and_wait_for_targets( @@ -1139,7 +1133,8 @@ def test_invalid_value( include_target_data: str | bool | int, ) -> None: """ - A ``BAD_REQUEST`` error is given when a string that is not one of + A ``BAD_REQUEST`` error is given when a string that is not one + of 'none', 'top' or 'all' (case insensitive). """ image_content = high_quality_image.getvalue() @@ -1168,9 +1163,7 @@ def test_invalid_value( @pytest.mark.usefixtures("verify_mock_vuforia") class TestAcceptHeader: - """ - Tests for the ``Accept`` header. - """ + """Tests for the ``Accept`` header.""" @staticmethod @pytest.mark.parametrize( @@ -1187,8 +1180,8 @@ def test_valid( vuforia_database: VuforiaDatabase, extra_headers: dict[str, str], ) -> None: - """ - An ``Accept`` header can be given iff its value is "application/json". + """An ``Accept`` header can be given iff its value is + "application/json". """ image_content = high_quality_image.getvalue() date = rfc_1123_date() @@ -1242,7 +1235,8 @@ def test_invalid( vuforia_database: VuforiaDatabase, ) -> None: """ - A NOT_ACCEPTABLE response is returned if an ``Accept`` header is given + A NOT_ACCEPTABLE response is returned if an ``Accept`` header is + given with a value which is not "application/json". """ image_content = high_quality_image.getvalue() @@ -1302,9 +1296,7 @@ def test_invalid( @pytest.mark.usefixtures("verify_mock_vuforia") class TestActiveFlag: - """ - Tests for active versus inactive targets. - """ + """Tests for active versus inactive targets.""" @staticmethod def test_inactive( @@ -1312,9 +1304,7 @@ def test_inactive( vws_client: VWS, cloud_reco_client: CloudRecoService, ) -> None: - """ - Images which are not active are not matched. - """ + """Images which are not active are not matched.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -1330,25 +1320,22 @@ def test_inactive( @pytest.mark.usefixtures("verify_mock_vuforia") class TestBadImage: - """ - Tests for bad images. - """ + """Tests for bad images.""" @staticmethod def test_corrupted( corrupted_image_file: io.BytesIO, cloud_reco_client: CloudRecoService, ) -> None: - """ - No error is returned when a corrupted image is given. - """ + """No error is returned when a corrupted image is given.""" results = cloud_reco_client.query(image=corrupted_image_file) assert results == [] @staticmethod def test_not_image(cloud_reco_client: CloudRecoService) -> None: """ - An ``UNPROCESSABLE_ENTITY`` response is returned when a non-image is + An ``UNPROCESSABLE_ENTITY`` response is returned when a non- + image is given. """ not_image_data = b"not_image_data" @@ -1384,15 +1371,14 @@ def test_not_image(cloud_reco_client: CloudRecoService) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestMaximumImageFileSize: - """ - Tests for maximum image file sizes. - """ + """Tests for maximum image file sizes.""" @staticmethod def test_png(cloud_reco_client: CloudRecoService) -> None: """ According to - https://developer.vuforia.com/library/web-api/vuforia-query-web-api. + https://developer.vuforia.com/library/web-api/vuforia-query-web- + api. the maximum file size is "2MiB for PNG". Above this limit, a ``REQUEST_ENTITY_TOO_LARGE`` response is returned. @@ -1462,7 +1448,8 @@ def test_png(cloud_reco_client: CloudRecoService) -> None: def test_jpeg(cloud_reco_client: CloudRecoService) -> None: """ According to - https://developer.vuforia.com/library/web-api/vuforia-query-web-api. + https://developer.vuforia.com/library/web-api/vuforia-query-web- + api. the maximum file size is "512 KiB for JPEG". However, this test shows that the maximum size for JPEG is 2 MiB. @@ -1532,16 +1519,15 @@ def test_jpeg(cloud_reco_client: CloudRecoService) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestMaximumImageDimensions: - """ - Tests for maximum image dimensions. - """ + """Tests for maximum image dimensions.""" @staticmethod def test_max_height( cloud_reco_client: CloudRecoService, ) -> None: """ - An error is returned when an image with a height greater than 30000 is + An error is returned when an image with a height greater than + 30000 is given. """ width = 1 @@ -1593,7 +1579,8 @@ def test_max_height( @staticmethod def test_max_width(cloud_reco_client: CloudRecoService) -> None: """ - An error is returned when an image with a width greater than 30000 is + An error is returned when an image with a width greater than + 30000 is given. """ height = 1 @@ -1644,9 +1631,7 @@ def test_max_width(cloud_reco_client: CloudRecoService) -> None: @staticmethod def test_max_pixels(cloud_reco_client: CloudRecoService) -> None: - """ - No error is returned for an 835 x 835 image. - """ + """No error is returned for an 835 x 835 image.""" # If we make this 836 then we hit REQUEST_ENTITY_TOO_LARGE errors. max_height = max_width = 835 png_not_too_wide = make_image_file( @@ -1662,9 +1647,7 @@ def test_max_pixels(cloud_reco_client: CloudRecoService) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestImageFormats: - """ - Tests for various image formats. - """ + """Tests for various image formats.""" @staticmethod @pytest.mark.parametrize(argnames="file_format", argvalues=["png", "jpeg"]) @@ -1673,9 +1656,7 @@ def test_supported( file_format: str, cloud_reco_client: CloudRecoService, ) -> None: - """ - PNG and JPEG formats are supported. - """ + """PNG and JPEG formats are supported.""" image_buffer = io.BytesIO() pil_image = Image.open(fp=high_quality_image) pil_image.save(fp=image_buffer, format=file_format) @@ -1690,9 +1671,7 @@ def test_unsupported( high_quality_image: io.BytesIO, cloud_reco_client: CloudRecoService, ) -> None: - """ - File formats which are not PNG or JPEG are not supported. - """ + """File formats which are not PNG or JPEG are not supported.""" file_format = "tiff" image_buffer = io.BytesIO() pil_image = Image.open(fp=high_quality_image) @@ -1730,9 +1709,7 @@ def test_unsupported( @pytest.mark.usefixtures("verify_mock_vuforia") class TestProcessing: - """ - Tests for targets in the processing state. - """ + """Tests for targets in the processing state.""" @staticmethod @pytest.mark.parametrize(argnames="active_flag", argvalues=[True, False]) @@ -1744,7 +1721,8 @@ def test_processing( active_flag: bool, ) -> None: """ - When a target with a matching image is in the processing state it is + When a target with a matching image is in the processing state + it is not matched. """ target_id = vws_client.add_target( @@ -1776,9 +1754,7 @@ def test_processing( @pytest.mark.usefixtures("verify_mock_vuforia") class TestUpdate: - """ - Tests for updated targets. - """ + """Tests for updated targets.""" @staticmethod def test_updated_target( @@ -1855,9 +1831,7 @@ def test_updated_target( @pytest.mark.usefixtures("verify_mock_vuforia") class TestDeleted: - """ - Tests for matching deleted targets. - """ + """Tests for matching deleted targets.""" @staticmethod def test_deleted_active( @@ -1865,9 +1839,7 @@ def test_deleted_active( vws_client: VWS, cloud_reco_client: CloudRecoService, ) -> None: - """ - Deleted targets are not matched. - """ + """Deleted targets are not matched.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -1904,7 +1876,8 @@ def test_deleted_inactive( cloud_reco_client: CloudRecoService, ) -> None: """ - No error is returned when querying for an image of recently deleted, + No error is returned when querying for an image of recently + deleted, inactive target. """ target_id = vws_client.add_target( @@ -1922,9 +1895,7 @@ def test_deleted_inactive( @pytest.mark.usefixtures("verify_mock_vuforia") class TestTargetStatusFailed: - """ - Tests for targets with the status "failed". - """ + """Tests for targets with the status "failed".""" @staticmethod def test_status_failed( @@ -1932,9 +1903,7 @@ def test_status_failed( vws_client: VWS, cloud_reco_client: CloudRecoService, ) -> None: - """ - Targets with the status "failed" are not found in query results. - """ + """Targets with the status "failed" are not found in query results.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -2041,9 +2010,7 @@ def test_date_formats( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project( @@ -2051,7 +2018,8 @@ def test_inactive_project( inactive_cloud_reco_client: CloudRecoService, ) -> None: """ - If the project is inactive, a FORBIDDEN response is returned. + If the project is inactive, a FORBIDDEN response is + returned. """ with pytest.raises( expected_exception=InactiveProjectError diff --git a/tests/mock_vws/test_requests_mock_usage.py b/tests/mock_vws/test_requests_mock_usage.py index 3cb3471f6..f80b3c078 100644 --- a/tests/mock_vws/test_requests_mock_usage.py +++ b/tests/mock_vws/test_requests_mock_usage.py @@ -1,6 +1,4 @@ -""" -Tests for the usage of the mock for ``requests``. -""" +"""Tests for the usage of the mock for ``requests``.""" import datetime import email.utils @@ -32,9 +30,7 @@ def _not_exact_matcher( first_image_content: bytes, second_image_content: bytes, ) -> bool: - """ - A matcher which returns True if the images are not the same. - """ + """A matcher which returns True if the images are not the same.""" return first_image_content != second_image_content @@ -59,7 +55,8 @@ def request_unmocked_address() -> None: @beartype def request_mocked_address() -> None: """ - Make a request, using `requests` to an address that is mocked by `MockVWS`. + Make a request, using `requests` to an address that is mocked by + `MockVWS`. """ requests.get( url="https://vws.vuforia.com/summary", @@ -73,14 +70,13 @@ def request_mocked_address() -> None: class TestRealHTTP: - """ - Tests for making requests to mocked and unmocked addresses. - """ + """Tests for making requests to mocked and unmocked addresses.""" @staticmethod def test_default() -> None: """ - By default, the mock stops any requests made with `requests` to non- + By default, the mock stops any requests made with `requests` to + non- Vuforia addresses, but not to mocked Vuforia endpoints. """ with MockVWS(): @@ -102,7 +98,8 @@ def test_default() -> None: @staticmethod def test_real_http() -> None: """ - When the `real_http` parameter given to the context manager is set to + When the `real_http` parameter given to the context manager is + set to `True`, requests made to unmocked addresses are not stopped. """ with ( @@ -115,18 +112,14 @@ def test_real_http() -> None: class TestProcessingTime: - """ - Tests for the time taken to process targets in the mock. - """ + """Tests for the time taken to process targets in the mock.""" # There is a race condition in this test type - if tests start to # fail, consider increasing the leeway. LEEWAY = 0.5 def test_default(self, image_file_failed_state: io.BytesIO) -> None: - """ - By default, targets in the mock takes 2 seconds to be processed. - """ + """By default, targets in the mock takes 2 seconds to be processed.""" database = VuforiaDatabase() with MockVWS() as mock: mock.add_database(database=database) @@ -139,9 +132,7 @@ def test_default(self, image_file_failed_state: io.BytesIO) -> None: assert expected - self.LEEWAY < time_taken < expected + self.LEEWAY def test_custom(self, image_file_failed_state: io.BytesIO) -> None: - """ - It is possible to set a custom processing time. - """ + """It is possible to set a custom processing time.""" database = VuforiaDatabase() seconds = 5 with MockVWS(processing_time_seconds=seconds) as mock: @@ -156,15 +147,11 @@ def test_custom(self, image_file_failed_state: io.BytesIO) -> None: class TestDatabaseName: - """ - Tests for the database name. - """ + """Tests for the database name.""" @staticmethod def test_default() -> None: - """ - By default, the database has a random name. - """ + """By default, the database has a random name.""" database_details = VuforiaDatabase() other_database_details = VuforiaDatabase() assert ( @@ -174,23 +161,17 @@ def test_default() -> None: @staticmethod def test_custom_name() -> None: - """ - It is possible to set a custom database name. - """ + """It is possible to set a custom database name.""" database_details = VuforiaDatabase(database_name="foo") assert database_details.database_name == "foo" class TestCustomBaseURLs: - """ - Tests for using custom base URLs. - """ + """Tests for using custom base URLs.""" @staticmethod def test_custom_base_vws_url() -> None: - """ - It is possible to use a custom base VWS URL. - """ + """It is possible to use a custom base VWS URL.""" with MockVWS( base_vws_url="https://vuforia.vws.example.com", real_http=False, @@ -211,9 +192,7 @@ def test_custom_base_vws_url() -> None: @staticmethod def test_custom_base_vwq_url() -> None: - """ - It is possible to use a custom base cloud recognition URL. - """ + """It is possible to use a custom base cloud recognition URL.""" with MockVWS( base_vwq_url="https://vuforia.vwq.example.com", real_http=False, @@ -237,9 +216,7 @@ def test_custom_base_vwq_url() -> None: @staticmethod def test_no_scheme() -> None: - """ - An error if raised if a URL is given with no scheme. - """ + """An error if raised if a URL is given with no scheme.""" with pytest.raises(expected_exception=MissingSchemeError) as vws_exc: MockVWS(base_vws_url="vuforia.vws.example.com") @@ -258,14 +235,13 @@ def test_no_scheme() -> None: class TestTargets: - """ - Tests for target representations. - """ + """Tests for target representations.""" @staticmethod def test_to_dict(high_quality_image: io.BytesIO) -> None: """ - It is possible to dump a target to a dictionary and load it back. + It is possible to dump a target to a dictionary and load it + back. """ database = VuforiaDatabase() @@ -297,7 +273,8 @@ def test_to_dict(high_quality_image: io.BytesIO) -> None: @staticmethod def test_to_dict_deleted(high_quality_image: io.BytesIO) -> None: """ - It is possible to dump a deleted target to a dictionary and load it + It is possible to dump a deleted target to a dictionary and load + it back. """ database = VuforiaDatabase() @@ -331,14 +308,13 @@ def test_to_dict_deleted(high_quality_image: io.BytesIO) -> None: class TestDatabaseToDict: - """ - Tests for dumping a database to a dictionary. - """ + """Tests for dumping a database to a dictionary.""" @staticmethod def test_to_dict(high_quality_image: io.BytesIO) -> None: """ - It is possible to dump a database to a dictionary and load it back. + It is possible to dump a database to a dictionary and load it + back. """ database = VuforiaDatabase() vws_client = VWS( @@ -366,14 +342,13 @@ def test_to_dict(high_quality_image: io.BytesIO) -> None: class TestDateHeader: - """ - Tests for the date header in responses from mock routes. - """ + """Tests for the date header in responses from mock routes.""" @staticmethod def test_date_changes() -> None: """ - The date that the response is sent is in the response Date header. + The date that the response is sent is in the response Date + header. """ new_year = 2012 new_time = datetime.datetime( @@ -396,14 +371,13 @@ def test_date_changes() -> None: class TestAddDatabase: - """ - Tests for adding databases to the mock. - """ + """Tests for adding databases to the mock.""" @staticmethod def test_duplicate_keys() -> None: """ - It is not possible to have multiple databases with matching keys. + It is not possible to have multiple databases with matching + keys. """ database = VuforiaDatabase( server_access_key="1", @@ -457,15 +431,11 @@ def test_duplicate_keys() -> None: class TestQueryImageMatchers: - """ - Tests for query image matchers. - """ + """Tests for query image matchers.""" @staticmethod def test_exact_match(high_quality_image: io.BytesIO) -> None: - """ - The exact matcher matches only exactly the same images. - """ + """The exact matcher matches only exactly the same images.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -501,9 +471,7 @@ def test_exact_match(high_quality_image: io.BytesIO) -> None: @staticmethod def test_custom_matcher(high_quality_image: io.BytesIO) -> None: - """ - It is possible to use a custom matcher. - """ + """It is possible to use a custom matcher.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -542,9 +510,7 @@ def test_structural_similarity_matcher( high_quality_image: io.BytesIO, different_high_quality_image: io.BytesIO, ) -> None: - """ - The structural similarity matcher matches similar images. - """ + """The structural similarity matcher matches similar images.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -587,15 +553,11 @@ def test_structural_similarity_matcher( class TestDuplicatesImageMatchers: - """ - Tests for duplicates image matchers. - """ + """Tests for duplicates image matchers.""" @staticmethod def test_exact_match(high_quality_image: io.BytesIO) -> None: - """ - The exact matcher matches only exactly the same images. - """ + """The exact matcher matches only exactly the same images.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -639,9 +601,7 @@ def test_exact_match(high_quality_image: io.BytesIO) -> None: @staticmethod def test_custom_matcher(high_quality_image: io.BytesIO) -> None: - """ - It is possible to use a custom matcher. - """ + """It is possible to use a custom matcher.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -687,9 +647,7 @@ def test_custom_matcher(high_quality_image: io.BytesIO) -> None: def test_structural_similarity_matcher( high_quality_image: io.BytesIO, ) -> None: - """ - The structural similarity matcher matches similar images. - """ + """The structural similarity matcher matches similar images.""" database = VuforiaDatabase() vws_client = VWS( server_access_key=database.server_access_key, @@ -728,15 +686,11 @@ def test_structural_similarity_matcher( # Flask app. @pytest.mark.usefixtures("mock_only_vuforia") class TestDataTypes: - """ - Tests for sending various data types. - """ + """Tests for sending various data types.""" @staticmethod def test_text(endpoint: Endpoint) -> None: - """ - It is possible to send strings to VWS endpoints. - """ + """It is possible to send strings to VWS endpoints.""" netloc = urlparse(url=endpoint.base_url).netloc if netloc == "cloudreco.vuforia.com": diff --git a/tests/mock_vws/test_target_list.py b/tests/mock_vws/test_target_list.py index 3cc4ea27d..b83db3dfd 100644 --- a/tests/mock_vws/test_target_list.py +++ b/tests/mock_vws/test_target_list.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the target list endpoint. -""" +"""Tests for the mock of the target list endpoint.""" import pytest from vws import VWS @@ -8,18 +6,14 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestTargetList: - """ - Tests for the mock of the target list endpoint at `/targets`. - """ + """Tests for the mock of the target list endpoint at `/targets`.""" @staticmethod def test_includes_targets( vws_client: VWS, target_id: str, ) -> None: - """ - Targets in the database are returned in the list. - """ + """Targets in the database are returned in the list.""" assert vws_client.list_targets() == [target_id] @staticmethod @@ -27,9 +21,7 @@ def test_deleted( vws_client: VWS, target_id: str, ) -> None: - """ - Deleted targets are not returned in the list. - """ + """Deleted targets are not returned in the list.""" vws_client.wait_for_target_processed(target_id=target_id) vws_client.delete_target(target_id=target_id) assert not vws_client.list_targets() @@ -37,14 +29,10 @@ def test_deleted( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: - """ - The project's active state does not affect the target list. - """ + """The project's active state does not affect the target list.""" # No exception is raised. inactive_vws_client.list_targets() diff --git a/tests/mock_vws/test_target_raters.py b/tests/mock_vws/test_target_raters.py index 997833f41..27dbc8cb4 100644 --- a/tests/mock_vws/test_target_raters.py +++ b/tests/mock_vws/test_target_raters.py @@ -1,6 +1,4 @@ -""" -Tests for target quality raters. -""" +"""Tests for target quality raters.""" import io @@ -15,7 +13,8 @@ def test_random_target_tracking_rater() -> None: """ - Test that the random target tracking rater returns a random number. + Test that the random target tracking rater returns a random + number. """ rater = RandomTargetTrackingRater() image_content = b"content" @@ -36,7 +35,8 @@ def test_random_target_tracking_rater() -> None: @pytest.mark.parametrize(argnames="rating", argvalues=range(-10, 10)) def test_hardcoded_target_tracking_rater(rating: int) -> None: """ - Test that the hardcoded target tracking rater returns the hardcoded number. + Test that the hardcoded target tracking rater returns the hardcoded + number. """ rater = HardcodedTargetTrackingRater(rating=rating) image_content = b"content" @@ -45,17 +45,13 @@ def test_hardcoded_target_tracking_rater(rating: int) -> None: class TestBrisqueTargetTrackingRater: - """ - Tests for the BRISQUE target tracking rater. - """ + """Tests for the BRISQUE target tracking rater.""" @staticmethod def test_low_quality_image( image_file_success_state_low_rating: io.BytesIO, ) -> None: - """ - Test that a low quality image returns a low rating. - """ + """Test that a low quality image returns a low rating.""" rater = BrisqueTargetTrackingRater() image_content = image_file_success_state_low_rating.getvalue() rating = rater(image_content=image_content) @@ -63,9 +59,7 @@ def test_low_quality_image( @staticmethod def test_high_quality_image(high_quality_image: io.BytesIO) -> None: - """ - Test that a high quality image returns a high rating. - """ + """Test that a high quality image returns a high rating.""" rater = BrisqueTargetTrackingRater() image_content = high_quality_image.getvalue() rating = rater(image_content=image_content) @@ -75,9 +69,7 @@ def test_high_quality_image(high_quality_image: io.BytesIO) -> None: def test_different_high_quality_image( different_high_quality_image: io.BytesIO, ) -> None: - """ - Test that a high quality image returns a high rating. - """ + """Test that a high quality image returns a high rating.""" rater = BrisqueTargetTrackingRater() image_content = different_high_quality_image.getvalue() rating = rater(image_content=image_content) diff --git a/tests/mock_vws/test_target_summary.py b/tests/mock_vws/test_target_summary.py index c432e78b4..61fbd76ce 100644 --- a/tests/mock_vws/test_target_summary.py +++ b/tests/mock_vws/test_target_summary.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the target summary endpoint. -""" +"""Tests for the mock of the target summary endpoint.""" import datetime import io @@ -17,9 +15,7 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestTargetSummary: - """ - Tests for the target summary endpoint. - """ + """Tests for the target summary endpoint.""" @staticmethod @pytest.mark.parametrize(argnames="active_flag", argvalues=[True, False]) @@ -30,9 +26,7 @@ def test_target_summary( *, active_flag: bool, ) -> None: - """ - A target summary is returned. - """ + """A target summary is returned.""" name = uuid.uuid4().hex gmt = ZoneInfo(key="GMT") date_before_add_target = datetime.datetime.now(tz=gmt).date() @@ -81,7 +75,8 @@ def test_after_processing( image_fixture_name: str, expected_status: TargetStatuses, ) -> None: - """After processing is completed, the tracking rating is in the range + """After processing is completed, the tracking rating is in the + range of 0 to 5. The documentation says: @@ -122,9 +117,7 @@ def test_after_processing( @pytest.mark.usefixtures("verify_mock_vuforia") class TestRecognitionCounts: - """ - Tests for the recognition counts in the summary. - """ + """Tests for the recognition counts in the summary.""" @staticmethod def test_recognition( @@ -132,9 +125,7 @@ def test_recognition( cloud_reco_client: CloudRecoService, high_quality_image: io.BytesIO, ) -> None: - """ - The recognition counts stay at 0 even after recognitions. - """ + """The recognition counts stay at 0 even after recognitions.""" target_id = vws_client.add_target( name="example", width=1, @@ -158,15 +149,11 @@ def test_recognition( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: - """ - The project's active state does not affect getting a target. - """ + """The project's active state does not affect getting a target.""" with pytest.raises(expected_exception=UnknownTargetError): inactive_vws_client.get_target_summary_report( target_id=uuid.uuid4().hex, diff --git a/tests/mock_vws/test_unexpected_json.py b/tests/mock_vws/test_unexpected_json.py index c7f96856e..497119268 100644 --- a/tests/mock_vws/test_unexpected_json.py +++ b/tests/mock_vws/test_unexpected_json.py @@ -1,6 +1,4 @@ -""" -Tests for giving JSON data to endpoints which do not expect it. -""" +"""Tests for giving JSON data to endpoints which do not expect it.""" import json from http import HTTPStatus @@ -16,14 +14,13 @@ @pytest.mark.usefixtures("verify_mock_vuforia") class TestUnexpectedJSON: - """ - Tests for giving JSON to endpoints which do not expect it. - """ + """Tests for giving JSON to endpoints which do not expect it.""" @staticmethod def test_does_not_take_data(endpoint: Endpoint) -> None: """ - Giving JSON to endpoints which do not take any JSON data returns error + Giving JSON to endpoints which do not take any JSON data returns + error responses. """ if ( diff --git a/tests/mock_vws/test_update_target.py b/tests/mock_vws/test_update_target.py index 3b6a0db1e..1dddaffcc 100644 --- a/tests/mock_vws/test_update_target.py +++ b/tests/mock_vws/test_update_target.py @@ -1,6 +1,4 @@ -""" -Tests for the mock of the update target endpoint. -""" +"""Tests for the mock of the update target endpoint.""" import base64 import io @@ -65,9 +63,7 @@ def _update_target( @pytest.mark.usefixtures("verify_mock_vuforia") class TestUpdate: - """ - Tests for updating targets. - """ + """Tests for updating targets.""" @staticmethod @pytest.mark.parametrize( @@ -86,7 +82,8 @@ def test_content_types( content_type: str, ) -> None: """ - The ``Content-Type`` header does not change the response as long as it + The ``Content-Type`` header does not change the response as long + as it is not empty. """ target_id = vws_client.add_target( @@ -120,7 +117,8 @@ def test_empty_content_type( image_file_failed_state: io.BytesIO, ) -> None: """ - An ``UNAUTHORIZED`` response is given if an empty ``Content-Type`` + An ``UNAUTHORIZED`` response is given if an empty ``Content- + Type`` header is given. """ target_id = vws_client.add_target( @@ -152,9 +150,7 @@ def test_no_fields_given( vws_client: VWS, target_id: str, ) -> None: - """ - No data fields are required. - """ + """No data fields are required.""" vws_client.wait_for_target_processed(target_id=target_id) response = _update_target( @@ -185,9 +181,7 @@ def test_no_fields_given( @pytest.mark.usefixtures("verify_mock_vuforia") class TestUnexpectedData: - """ - Tests for passing data which is not allowed to the endpoint. - """ + """Tests for passing data which is not allowed to the endpoint.""" @staticmethod def test_invalid_extra_data( @@ -195,7 +189,8 @@ def test_invalid_extra_data( target_id: str, ) -> None: """ - A `BAD_REQUEST` response is returned when unexpected data is given. + A `BAD_REQUEST` response is returned when unexpected data is + given. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -215,9 +210,7 @@ def test_invalid_extra_data( @pytest.mark.usefixtures("verify_mock_vuforia") class TestWidth: - """ - Tests for the target width field. - """ + """Tests for the target width field.""" @staticmethod @pytest.mark.parametrize( @@ -230,9 +223,7 @@ def test_width_invalid( width: int | str | None, target_id: str, ) -> None: - """ - The width must be a number greater than zero. - """ + """The width must be a number greater than zero.""" vws_client.wait_for_target_processed(target_id=target_id) target_details = vws_client.get_target_record(target_id=target_id) @@ -256,9 +247,7 @@ def test_width_invalid( @staticmethod def test_width_valid(vws_client: VWS, target_id: str) -> None: - """ - Positive numbers are valid widths. - """ + """Positive numbers are valid widths.""" vws_client.wait_for_target_processed(target_id=target_id) width = 0.01 @@ -269,9 +258,7 @@ def test_width_valid(vws_client: VWS, target_id: str) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestActiveFlag: - """ - Tests for the active flag parameter. - """ + """Tests for the active flag parameter.""" @staticmethod @pytest.mark.parametrize( @@ -289,9 +276,7 @@ def test_active_flag( initial_active_flag: bool, desired_active_flag: bool, ) -> None: - """ - Setting the active flag to a Boolean value changes it. - """ + """Setting the active flag to a Boolean value changes it.""" target_id = vws_client.add_target( name=uuid.uuid4().hex, width=1, @@ -320,7 +305,8 @@ def test_invalid( desired_active_flag: str | None, ) -> None: """ - Values which are not Boolean values are not valid active flags. + Values which are not Boolean values are not valid active + flags. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -340,9 +326,7 @@ def test_invalid( @pytest.mark.usefixtures("verify_mock_vuforia") class TestApplicationMetadata: - """ - Tests for the application metadata parameter. - """ + """Tests for the application metadata parameter.""" @staticmethod @pytest.mark.parametrize( @@ -358,9 +342,7 @@ def test_base64_encoded( metadata: bytes, vws_client: VWS, ) -> None: - """ - A base64 encoded string is valid application metadata. - """ + """A base64 encoded string is valid application metadata.""" metadata_encoded = base64.b64encode(s=metadata).decode( encoding="ascii" ) @@ -377,9 +359,7 @@ def test_invalid_type( target_id: str, invalid_metadata: int | None, ) -> None: - """ - Non-string values cannot be given as valid application metadata. - """ + """Non-string values cannot be given as valid application metadata.""" vws_client.wait_for_target_processed(target_id=target_id) with pytest.raises(expected_exception=FailError) as exc: @@ -402,7 +382,8 @@ def test_not_base64_encoded_processable( not_base64_encoded_processable: str, ) -> None: """ - Some strings which are not valid base64 encoded strings are allowed as + Some strings which are not valid base64 encoded strings are + allowed as application metadata. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -419,7 +400,8 @@ def test_not_base64_encoded_not_processable( not_base64_encoded_not_processable: str, ) -> None: """ - Some strings which are not valid base64 encoded strings are not allowed + Some strings which are not valid base64 encoded strings are not + allowed as application metadata. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -439,7 +421,8 @@ def test_not_base64_encoded_not_processable( @staticmethod def test_metadata_too_large(vws_client: VWS, target_id: str) -> None: """ - A base64 encoded string of greater than 1024 * 1024 bytes is too large + A base64 encoded string of greater than 1024 * 1024 bytes is too + large for application metadata. """ metadata = b"a" * (_MAX_METADATA_BYTES + 1) @@ -463,9 +446,7 @@ def test_metadata_too_large(vws_client: VWS, target_id: str) -> None: @pytest.mark.usefixtures("verify_mock_vuforia") class TestTargetName: - """ - Tests for the target name field. - """ + """Tests for the target name field.""" _MAX_CHAR_VALUE = 65535 _MAX_NAME_LENGTH = 64 @@ -537,9 +518,7 @@ def test_name_invalid( status_code: int, result_code: ResultCodes, ) -> None: - """ - A target's name must be a string of length 0 < N < 65. - """ + """A target's name must be a string of length 0 < N < 65.""" vws_client.wait_for_target_processed(target_id=target_id) with pytest.raises(expected_exception=VWSError) as exc: @@ -560,9 +539,7 @@ def test_existing_target_name( image_file_success_state_low_rating: io.BytesIO, vws_client: VWS, ) -> None: - """ - Only one target can have a given name. - """ + """Only one target can have a given name.""" first_target_name = "example_name" second_target_name = "another_example_name" @@ -602,9 +579,7 @@ def test_same_name_given( image_file_success_state_low_rating: io.BytesIO, vws_client: VWS, ) -> None: - """ - Updating a target with its own name does not give an error. - """ + """Updating a target with its own name does not give an error.""" name = "example" target_id = vws_client.add_target( @@ -636,7 +611,8 @@ def test_image_valid( vws_client: VWS, ) -> None: """ - JPEG and PNG files in the RGB and greyscale color spaces are allowed. + JPEG and PNG files in the RGB and greyscale color spaces are + allowed. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -652,8 +628,10 @@ def test_bad_image_format_or_color_space( vws_client: VWS, ) -> None: """ - A `BAD_IMAGE` response is returned if an image which is not a JPEG or - PNG file is given, or if the given image is not in the greyscale or RGB + A `BAD_IMAGE` response is returned if an image which is not a + JPEG or + PNG file is given, or if the given image is not in the greyscale or + RGB color space. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -669,9 +647,7 @@ def test_corrupted( corrupted_image_file: io.BytesIO, target_id: str, ) -> None: - """ - An error is returned when the given image is corrupted. - """ + """An error is returned when the given image is corrupted.""" vws_client.wait_for_target_processed(target_id=target_id) with pytest.raises(expected_exception=BadImageError) as exc: vws_client.update_target( @@ -688,7 +664,8 @@ def test_corrupted( @staticmethod def test_image_too_large(target_id: str, vws_client: VWS) -> None: """ - An `ImageTooLargeError` result is returned if the image is above a + An `ImageTooLargeError` result is returned if the image is above + a certain threshold. """ max_bytes = 2.3 * 1024 * 1024 @@ -750,7 +727,8 @@ def test_not_base64_encoded_processable( target_id: str, not_base64_encoded_processable: str, ) -> None: - """Some strings which are not valid base64 encoded strings are allowed + """Some strings which are not valid base64 encoded strings are + allowed as an image without getting a "Fail" response. This is because Vuforia treats them as valid base64, but then @@ -779,7 +757,8 @@ def test_not_base64_encoded_not_processable( ) -> None: """ Some strings which are not valid base64 encoded strings are not - processable by Vuforia, and then when given as an image Vuforia returns + processable by Vuforia, and then when given as an image Vuforia + returns a "Fail" response. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -800,7 +779,8 @@ def test_not_base64_encoded_not_processable( @staticmethod def test_not_image(target_id: str, vws_client: VWS) -> None: """ - If the given image is not an image file then a `BadImageError` result + If the given image is not an image file then a `BadImageError` + result is returned. """ vws_client.wait_for_target_processed(target_id=target_id) @@ -827,9 +807,7 @@ def test_invalid_type( target_id: str, vws_client: VWS, ) -> None: - """ - If the given image is not a string, a `Fail` result is returned. - """ + """If the given image is not a string, a `Fail` result is returned.""" vws_client.wait_for_target_processed(target_id=target_id) with pytest.raises(expected_exception=FailError) as exc: @@ -888,14 +866,13 @@ def test_rating_can_change( @pytest.mark.usefixtures("verify_mock_vuforia") class TestInactiveProject: - """ - Tests for inactive projects. - """ + """Tests for inactive projects.""" @staticmethod def test_inactive_project(inactive_vws_client: VWS) -> None: """ - If the project is inactive, a FORBIDDEN response is returned. + If the project is inactive, a FORBIDDEN response is + returned. """ with pytest.raises(expected_exception=ProjectInactiveError): inactive_vws_client.update_target(target_id=uuid.uuid4().hex) diff --git a/tests/mock_vws/utils/__init__.py b/tests/mock_vws/utils/__init__.py index 241c13ec4..c554e4571 100644 --- a/tests/mock_vws/utils/__init__.py +++ b/tests/mock_vws/utils/__init__.py @@ -1,6 +1,4 @@ -""" -Utilities for tests. -""" +"""Utilities for tests.""" import io import secrets @@ -55,9 +53,7 @@ class Endpoint: secret_key: str def send(self) -> Response: - """ - Send the request. - """ + """Send the request.""" request = requests.Request( method=self.method, url=urljoin(base=self.base_url, url=self.path_url), @@ -79,9 +75,7 @@ def send(self) -> Response: @property def auth_header_content_type(self) -> str: - """ - The content type to use for the `Authorization` header. - """ + """The content type to use for the `Authorization` header.""" full_content_type = dict(self.headers).get("Content-Type", "") return full_content_type.split(sep=";")[0] diff --git a/tests/mock_vws/utils/assertions.py b/tests/mock_vws/utils/assertions.py index 8ea4ea12b..e026fed02 100644 --- a/tests/mock_vws/utils/assertions.py +++ b/tests/mock_vws/utils/assertions.py @@ -1,6 +1,4 @@ -""" -Assertion helpers. -""" +"""Assertion helpers.""" import copy import datetime @@ -169,7 +167,8 @@ def assert_vws_response( @beartype def assert_query_success(*, response: Response) -> None: - """Assert that the given response is a success response for performing an + """Assert that the given response is a success response for performing + an image recognition query. Raises: diff --git a/tests/mock_vws/utils/retries.py b/tests/mock_vws/utils/retries.py index 6d7a7d491..02e980e0b 100644 --- a/tests/mock_vws/utils/retries.py +++ b/tests/mock_vws/utils/retries.py @@ -1,6 +1,4 @@ -""" -Helpers for retrying requests to VWS. -""" +"""Helpers for retrying requests to VWS.""" from tenacity import retry from tenacity.retry import retry_if_exception_type diff --git a/tests/mock_vws/utils/too_many_requests.py b/tests/mock_vws/utils/too_many_requests.py index aae3742af..c35cb54d1 100644 --- a/tests/mock_vws/utils/too_many_requests.py +++ b/tests/mock_vws/utils/too_many_requests.py @@ -1,6 +1,4 @@ -""" -Helpers for handling too many requests errors. -""" +"""Helpers for handling too many requests errors.""" from http import HTTPStatus diff --git a/tests/mock_vws/utils/usage_test_helpers.py b/tests/mock_vws/utils/usage_test_helpers.py index b3012312e..6c85dc0f6 100644 --- a/tests/mock_vws/utils/usage_test_helpers.py +++ b/tests/mock_vws/utils/usage_test_helpers.py @@ -1,6 +1,4 @@ -""" -Helpers for testing the usage of the mocks. -""" +"""Helpers for testing the usage of the mocks.""" import datetime import io @@ -16,9 +14,7 @@ def processing_time_seconds( vuforia_database: VuforiaDatabase, image: io.BytesIO, ) -> float: - """ - Return the time taken to process a target in the database. - """ + """Return the time taken to process a target in the database.""" vws_client = VWS( server_access_key=vuforia_database.server_access_key, server_secret_key=vuforia_database.server_secret_key,