vws-python-mock 2026.2.18.1__tar.gz → 2026.2.18.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/CHANGELOG.rst +4 -0
  2. {vws_python_mock-2026.2.18.1/src/vws_python_mock.egg-info → vws_python_mock-2026.2.18.2}/PKG-INFO +1 -1
  3. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_constants.py +1 -0
  4. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/__init__.py +1 -1
  5. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/exceptions.py +40 -0
  6. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/json_validators.py +9 -2
  7. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2/src/vws_python_mock.egg-info}/PKG-INFO +1 -1
  8. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/conftest.py +1 -0
  9. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/fixtures/prepared_requests.py +48 -0
  10. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_date_header.py +12 -0
  11. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_invalid_json.py +6 -1
  12. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/utils/__init__.py +1 -1
  13. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.git_archival.txt +0 -0
  14. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.gitattributes +0 -0
  15. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/dependabot.yml +0 -0
  16. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/dependabot-merge.yml +0 -0
  17. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/docker-build.yml +0 -0
  18. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/lint.yml +0 -0
  19. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/publish-site.yml +0 -0
  20. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/release.yml +0 -0
  21. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.github/workflows/test.yml +0 -0
  22. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.gitignore +0 -0
  23. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.pre-commit-config.yaml +0 -0
  24. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.prettierrc +0 -0
  25. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.vscode/extensions.json +0 -0
  26. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/.vscode/settings.json +0 -0
  27. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/CODE_OF_CONDUCT.rst +0 -0
  28. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/LICENSE +0 -0
  29. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/MANIFEST.in +0 -0
  30. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/README.rst +0 -0
  31. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/admin/__init__.py +0 -0
  32. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/admin/create_secrets_files.py +0 -0
  33. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/admin/vumark_template.svg +0 -0
  34. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/ci/__init__.py +0 -0
  35. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/ci/decrypt_secret.sh +0 -0
  36. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/ci/test_custom_linters.py +0 -0
  37. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/conftest.py +0 -0
  38. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docker-bake.hcl +0 -0
  39. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/__init__.py +0 -0
  40. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/basic-example.rst +0 -0
  41. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/changelog.rst +0 -0
  42. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/ci-setup.rst +0 -0
  43. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/conf.py +0 -0
  44. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/contributing.rst +0 -0
  45. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/differences-to-vws.rst +0 -0
  46. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/docker.rst +0 -0
  47. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/getting-started.rst +0 -0
  48. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/index.rst +0 -0
  49. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/installation.rst +0 -0
  50. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/mock-api-reference.rst +0 -0
  51. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/release-process.rst +0 -0
  52. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/docs/source/versioning-and-api-stability.rst +0 -0
  53. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/pyproject.toml +0 -0
  54. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/secrets.tar.gpg +0 -0
  55. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/setup.cfg +0 -0
  56. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/spelling_private_dict.txt +0 -0
  57. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/__init__.py +0 -0
  58. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_base64_decoding.py +0 -0
  59. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_database_matchers.py +0 -0
  60. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/Dockerfile +0 -0
  61. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/__init__.py +0 -0
  62. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/healthcheck.py +0 -0
  63. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/target_manager.py +0 -0
  64. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/vwq.py +0 -0
  65. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_flask_server/vws.py +0 -0
  66. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_mock_common.py +0 -0
  67. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_tools.py +0 -0
  68. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/__init__.py +0 -0
  69. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/accept_header_validators.py +0 -0
  70. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/auth_validators.py +0 -0
  71. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/content_length_validators.py +0 -0
  72. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/content_type_validators.py +0 -0
  73. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/date_validators.py +0 -0
  74. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/exceptions.py +0 -0
  75. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/fields_validators.py +0 -0
  76. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/image_validators.py +0 -0
  77. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/include_target_data_validators.py +0 -0
  78. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/num_results_validators.py +0 -0
  79. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_query_validators/project_state_validators.py +0 -0
  80. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_requests_mock_server/__init__.py +0 -0
  81. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_requests_mock_server/decorators.py +0 -0
  82. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_requests_mock_server/mock_web_query_api.py +0 -0
  83. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_requests_mock_server/mock_web_services_api.py +0 -0
  84. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/active_flag_validators.py +0 -0
  85. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/auth_validators.py +0 -0
  86. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/content_length_validators.py +0 -0
  87. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/content_type_validators.py +0 -0
  88. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/date_validators.py +0 -0
  89. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/image_validators.py +0 -0
  90. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/key_validators.py +0 -0
  91. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/metadata_validators.py +0 -0
  92. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/name_validators.py +0 -0
  93. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/project_state_validators.py +0 -0
  94. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/target_validators.py +0 -0
  95. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/_services_validators/width_validators.py +0 -0
  96. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/database.py +0 -0
  97. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/image_matchers.py +0 -0
  98. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/py.typed +0 -0
  99. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/states.py +0 -0
  100. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/target.py +0 -0
  101. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/target_manager.py +0 -0
  102. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/mock_vws/target_raters.py +0 -0
  103. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/vws_python_mock.egg-info/SOURCES.txt +0 -0
  104. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/vws_python_mock.egg-info/dependency_links.txt +0 -0
  105. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/vws_python_mock.egg-info/not-zip-safe +0 -0
  106. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/vws_python_mock.egg-info/requires.txt +0 -0
  107. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/src/vws_python_mock.egg-info/top_level.txt +0 -0
  108. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/__init__.py +0 -0
  109. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/__init__.py +0 -0
  110. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/fixtures/__init__.py +0 -0
  111. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/fixtures/credentials.py +0 -0
  112. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/fixtures/vuforia_backends.py +0 -0
  113. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_add_target.py +0 -0
  114. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_authorization_header.py +0 -0
  115. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_content_length.py +0 -0
  116. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_database_summary.py +0 -0
  117. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_delete_target.py +0 -0
  118. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_docker.py +0 -0
  119. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_flask_app_usage.py +0 -0
  120. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_get_duplicates.py +0 -0
  121. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_get_target.py +0 -0
  122. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_invalid_given_id.py +0 -0
  123. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_query.py +0 -0
  124. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_requests_mock_usage.py +0 -0
  125. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_target_list.py +0 -0
  126. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_target_raters.py +0 -0
  127. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_target_summary.py +0 -0
  128. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_target_validators.py +0 -0
  129. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_unexpected_json.py +0 -0
  130. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_update_target.py +0 -0
  131. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/test_vumark_generation_api.py +0 -0
  132. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/utils/assertions.py +0 -0
  133. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/utils/retries.py +0 -0
  134. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/utils/too_many_requests.py +0 -0
  135. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/tests/mock_vws/utils/usage_test_helpers.py +0 -0
  136. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/vuforia_secrets.env.example +0 -0
  137. {vws_python_mock-2026.2.18.1 → vws_python_mock-2026.2.18.2}/zizmor.yml +0 -0
@@ -4,6 +4,10 @@ Changelog
4
4
  Next
5
5
  ----
6
6
 
7
+ 2026.02.18.2
8
+ ------------
9
+
10
+
7
11
  2026.02.18.1
8
12
  ------------
9
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vws-python-mock
3
- Version: 2026.2.18.1
3
+ Version: 2026.2.18.2
4
4
  Summary: A mock for the Vuforia Web Services (VWS) API.
5
5
  Author-email: Adam Dangoor <adamdangoor@gmail.com>
6
6
  License-Expression: MIT
@@ -62,6 +62,7 @@ class ResultCodes(Enum):
62
62
  TOO_MANY_REQUESTS = "TooManyRequests"
63
63
  INVALID_ACCEPT_HEADER = "InvalidAcceptHeader"
64
64
  INVALID_INSTANCE_ID = "InvalidInstanceId"
65
+ BAD_REQUEST = "BadRequest"
65
66
 
66
67
 
67
68
  @beartype
@@ -103,7 +103,7 @@ def run_services_validators(
103
103
  validate_date_format(request_headers=request_headers)
104
104
  validate_date_in_range(request_headers=request_headers)
105
105
 
106
- validate_json(request_body=request_body)
106
+ validate_json(request_body=request_body, request_path=request_path)
107
107
 
108
108
  validate_keys(
109
109
  request_body=request_body,
@@ -184,6 +184,46 @@ class FailError(ValidatorError):
184
184
  }
185
185
 
186
186
 
187
+ @beartype
188
+ class BadRequestError(ValidatorError):
189
+ """Exception raised when Vuforia returns a response with a result code
190
+ 'BadRequest'.
191
+ """
192
+
193
+ def __init__(self) -> None:
194
+ """
195
+ Attributes:
196
+ status_code: The status code to use in a response if this is
197
+ raised.
198
+ response_text: The response text to use in a response if this
199
+ is
200
+ raised.
201
+ """
202
+ super().__init__()
203
+ self.status_code = HTTPStatus.BAD_REQUEST
204
+ body = {
205
+ "transaction_id": uuid.uuid4().hex,
206
+ "result_code": ResultCodes.BAD_REQUEST.value,
207
+ }
208
+ self.response_text = json_dump(body=body)
209
+ date = email.utils.formatdate(
210
+ timeval=None,
211
+ localtime=False,
212
+ usegmt=True,
213
+ )
214
+ self.headers = {
215
+ "Connection": "keep-alive",
216
+ "Content-Type": "application/json",
217
+ "server": "envoy",
218
+ "Date": date,
219
+ "x-envoy-upstream-service-time": "5",
220
+ "Content-Length": str(object=len(self.response_text)),
221
+ "strict-transport-security": "max-age=31536000",
222
+ "x-aws-region": "us-east-2, us-west-2",
223
+ "x-content-type-options": "nosniff",
224
+ }
225
+
226
+
187
227
  @beartype
188
228
  class MetadataTooLargeError(ValidatorError):
189
229
  """Exception raised when Vuforia returns a response with a result code
@@ -8,6 +8,7 @@ from json.decoder import JSONDecodeError
8
8
  from beartype import beartype
9
9
 
10
10
  from mock_vws._services_validators.exceptions import (
11
+ BadRequestError,
11
12
  FailError,
12
13
  UnnecessaryRequestBodyError,
13
14
  )
@@ -43,14 +44,18 @@ def validate_body_given(*, request_body: bytes, request_method: str) -> None:
43
44
 
44
45
 
45
46
  @beartype
46
- def validate_json(*, request_body: bytes) -> None:
47
+ def validate_json(*, request_body: bytes, request_path: str) -> None:
47
48
  """Validate that any given body is valid JSON.
48
49
 
49
50
  Args:
50
51
  request_body: The body of the request.
52
+ request_path: The path of the request.
51
53
 
52
54
  Raises:
53
- FailError: The request body includes invalid JSON.
55
+ BadRequestError: The request body includes invalid JSON for the
56
+ VuMark instance generation endpoint.
57
+ FailError: The request body includes invalid JSON for other
58
+ endpoints.
54
59
  """
55
60
  if not request_body:
56
61
  return
@@ -59,4 +64,6 @@ def validate_json(*, request_body: bytes) -> None:
59
64
  json.loads(s=request_body.decode())
60
65
  except JSONDecodeError as exc:
61
66
  _LOGGER.warning(msg="The request body is not valid JSON.")
67
+ if request_path.endswith("/instances"):
68
+ raise BadRequestError from exc
62
69
  raise FailError(status_code=HTTPStatus.BAD_REQUEST) from exc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vws-python-mock
3
- Version: 2026.2.18.1
3
+ Version: 2026.2.18.2
4
4
  Summary: A mock for the Vuforia Web Services (VWS) API.
5
5
  Author-email: Adam Dangoor <adamdangoor@gmail.com>
6
6
  License-Expression: MIT
@@ -85,6 +85,7 @@ def target_id(
85
85
  "target_summary",
86
86
  "update_target",
87
87
  "query",
88
+ "vumark_generate_instance",
88
89
  ],
89
90
  )
90
91
  def endpoint(request: pytest.FixtureRequest) -> Endpoint:
@@ -5,6 +5,7 @@ import io
5
5
  import json
6
6
  from http import HTTPMethod, HTTPStatus
7
7
  from typing import Any
8
+ from uuid import uuid4
8
9
 
9
10
  import pytest
10
11
  from urllib3.filepost import encode_multipart_formdata
@@ -13,6 +14,7 @@ from vws_auth_tools import authorization_header, rfc_1123_date
13
14
 
14
15
  from mock_vws._constants import ResultCodes
15
16
  from mock_vws.database import VuforiaDatabase
17
+ from tests.mock_vws.fixtures.credentials import VuMarkVuforiaDatabase
16
18
  from tests.mock_vws.utils import Endpoint
17
19
  from tests.mock_vws.utils.retries import RETRY_ON_TOO_MANY_REQUESTS
18
20
 
@@ -451,3 +453,49 @@ def query(
451
453
  access_key=access_key,
452
454
  secret_key=secret_key,
453
455
  )
456
+
457
+
458
+ @pytest.fixture
459
+ def vumark_generate_instance(
460
+ vumark_vuforia_database: VuMarkVuforiaDatabase,
461
+ ) -> Endpoint:
462
+ """Return details of the endpoint for generating a VuMark instance."""
463
+ request_path = f"/targets/{vumark_vuforia_database.target_id}/instances"
464
+ content_type = "application/json"
465
+ method = HTTPMethod.POST
466
+ content = json.dumps(obj={"instance_id": uuid4().hex}).encode(
467
+ encoding="utf-8"
468
+ )
469
+ date = rfc_1123_date()
470
+
471
+ access_key = vumark_vuforia_database.server_access_key
472
+ secret_key = vumark_vuforia_database.server_secret_key
473
+ authorization_string = authorization_header(
474
+ access_key=access_key,
475
+ secret_key=secret_key,
476
+ method=method,
477
+ content=content,
478
+ content_type=content_type,
479
+ date=date,
480
+ request_path=request_path,
481
+ )
482
+
483
+ headers = {
484
+ "Accept": "image/png",
485
+ "Authorization": authorization_string,
486
+ "Content-Length": str(object=len(content)),
487
+ "Content-Type": content_type,
488
+ "Date": date,
489
+ }
490
+
491
+ return Endpoint(
492
+ successful_headers_status_code=HTTPStatus.OK,
493
+ successful_headers_result_code=None,
494
+ base_url=VWS_HOST,
495
+ path_url=request_path,
496
+ method=method,
497
+ headers=headers,
498
+ data=content,
499
+ access_key=access_key,
500
+ secret_key=secret_key,
501
+ )
@@ -381,6 +381,12 @@ class TestSkewedTime:
381
381
  assert_query_success(response=response)
382
382
  return
383
383
 
384
+ if endpoint.successful_headers_result_code is None:
385
+ assert (
386
+ response.status_code == endpoint.successful_headers_status_code
387
+ )
388
+ return
389
+
384
390
  assert_vws_response(
385
391
  response=response,
386
392
  status_code=endpoint.successful_headers_status_code,
@@ -445,6 +451,12 @@ class TestSkewedTime:
445
451
  assert_query_success(response=response)
446
452
  return
447
453
 
454
+ if endpoint.successful_headers_result_code is None:
455
+ assert (
456
+ response.status_code == endpoint.successful_headers_status_code
457
+ )
458
+ return
459
+
448
460
  assert_vws_response(
449
461
  response=response,
450
462
  status_code=endpoint.successful_headers_status_code,
@@ -75,10 +75,15 @@ class TestInvalidJSON:
75
75
  assert_valid_date_header(response=response)
76
76
 
77
77
  if takes_json_data:
78
+ expected_result_code = (
79
+ ResultCodes.BAD_REQUEST
80
+ if endpoint.path_url.endswith("/instances")
81
+ else ResultCodes.FAIL
82
+ )
78
83
  assert_vws_failure(
79
84
  response=response,
80
85
  status_code=HTTPStatus.BAD_REQUEST,
81
- result_code=ResultCodes.FAIL,
86
+ result_code=expected_result_code,
82
87
  )
83
88
  return
84
89
 
@@ -47,7 +47,7 @@ class Endpoint:
47
47
  method: str
48
48
  headers: Mapping[str, str]
49
49
  data: bytes | str
50
- successful_headers_result_code: ResultCodes
50
+ successful_headers_result_code: ResultCodes | None
51
51
  successful_headers_status_code: int
52
52
  access_key: str
53
53
  secret_key: str