vws-python-mock 2026.8.4__py3-none-any.whl

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 (62) hide show
  1. mock_vws/__init__.py +9 -0
  2. mock_vws/_base64_decoding.py +35 -0
  3. mock_vws/_constants.py +84 -0
  4. mock_vws/_database_matchers.py +107 -0
  5. mock_vws/_flask_server/Dockerfile +32 -0
  6. mock_vws/_flask_server/__init__.py +1 -0
  7. mock_vws/_flask_server/healthcheck.py +31 -0
  8. mock_vws/_flask_server/target_manager.py +447 -0
  9. mock_vws/_flask_server/vwq.py +173 -0
  10. mock_vws/_flask_server/vws.py +954 -0
  11. mock_vws/_mock_common.py +75 -0
  12. mock_vws/_model_target_web_api.py +486 -0
  13. mock_vws/_query_tools.py +136 -0
  14. mock_vws/_query_validators/__init__.py +128 -0
  15. mock_vws/_query_validators/accept_header_validators.py +31 -0
  16. mock_vws/_query_validators/auth_validators.py +143 -0
  17. mock_vws/_query_validators/content_length_validators.py +90 -0
  18. mock_vws/_query_validators/content_type_validators.py +65 -0
  19. mock_vws/_query_validators/date_validators.py +110 -0
  20. mock_vws/_query_validators/exceptions.py +769 -0
  21. mock_vws/_query_validators/fields_validators.py +47 -0
  22. mock_vws/_query_validators/image_validators.py +197 -0
  23. mock_vws/_query_validators/include_target_data_validators.py +51 -0
  24. mock_vws/_query_validators/num_results_validators.py +64 -0
  25. mock_vws/_query_validators/project_state_validators.py +49 -0
  26. mock_vws/_requests_mock_server/__init__.py +1 -0
  27. mock_vws/_requests_mock_server/decorators.py +275 -0
  28. mock_vws/_requests_mock_server/mock_web_query_api.py +139 -0
  29. mock_vws/_requests_mock_server/mock_web_services_api.py +954 -0
  30. mock_vws/_respx_mock_server/__init__.py +1 -0
  31. mock_vws/_respx_mock_server/decorators.py +186 -0
  32. mock_vws/_services_validators/__init__.py +186 -0
  33. mock_vws/_services_validators/active_flag_validators.py +43 -0
  34. mock_vws/_services_validators/auth_validators.py +124 -0
  35. mock_vws/_services_validators/content_length_validators.py +102 -0
  36. mock_vws/_services_validators/content_type_validators.py +42 -0
  37. mock_vws/_services_validators/date_validators.py +78 -0
  38. mock_vws/_services_validators/exceptions.py +858 -0
  39. mock_vws/_services_validators/image_validators.py +220 -0
  40. mock_vws/_services_validators/json_validators.py +69 -0
  41. mock_vws/_services_validators/key_validators.py +171 -0
  42. mock_vws/_services_validators/metadata_validators.py +106 -0
  43. mock_vws/_services_validators/name_validators.py +235 -0
  44. mock_vws/_services_validators/project_state_validators.py +76 -0
  45. mock_vws/_services_validators/request_quota_validators.py +42 -0
  46. mock_vws/_services_validators/target_quota_validators.py +41 -0
  47. mock_vws/_services_validators/target_validators.py +69 -0
  48. mock_vws/_services_validators/width_validators.py +38 -0
  49. mock_vws/database.py +257 -0
  50. mock_vws/database_type.py +13 -0
  51. mock_vws/image_matchers.py +124 -0
  52. mock_vws/model_target.py +79 -0
  53. mock_vws/py.typed +0 -0
  54. mock_vws/states.py +20 -0
  55. mock_vws/target.py +285 -0
  56. mock_vws/target_manager.py +178 -0
  57. mock_vws/target_raters.py +109 -0
  58. vws_python_mock-2026.8.4.dist-info/METADATA +177 -0
  59. vws_python_mock-2026.8.4.dist-info/RECORD +62 -0
  60. vws_python_mock-2026.8.4.dist-info/WHEEL +5 -0
  61. vws_python_mock-2026.8.4.dist-info/licenses/LICENSE +21 -0
  62. vws_python_mock-2026.8.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,858 @@
1
+ """Exceptions to raise from validators."""
2
+
3
+ import email.utils
4
+ import textwrap
5
+ import uuid
6
+ from collections.abc import Mapping
7
+ from http import HTTPStatus
8
+
9
+ from beartype import beartype
10
+
11
+ from mock_vws._constants import ResultCodes
12
+ from mock_vws._mock_common import json_dump
13
+
14
+
15
+ @beartype
16
+ class ValidatorError(Exception):
17
+ """
18
+ A base class for exceptions thrown from mock Vuforia services
19
+ endpoints.
20
+ """
21
+
22
+ status_code: HTTPStatus
23
+ response_text: str
24
+ headers: Mapping[str, str]
25
+
26
+
27
+ @beartype
28
+ class UnknownTargetError(ValidatorError):
29
+ """Exception raised when Vuforia returns a response with a result code
30
+ 'UnknownTarget'.
31
+ """
32
+
33
+ def __init__(self) -> None:
34
+ """
35
+ Attributes:
36
+ status_code: The status code to use in a response if this is
37
+ raised.
38
+ response_text: The response text to use in a response if this
39
+ is
40
+ raised.
41
+ """
42
+ super().__init__()
43
+ self.status_code = HTTPStatus.NOT_FOUND
44
+ body = {
45
+ "transaction_id": uuid.uuid4().hex,
46
+ "result_code": ResultCodes.UNKNOWN_TARGET.value,
47
+ }
48
+ self.response_text = json_dump(body=body)
49
+ date = email.utils.formatdate(
50
+ timeval=None,
51
+ localtime=False,
52
+ usegmt=True,
53
+ )
54
+ self.headers = {
55
+ "Connection": "keep-alive",
56
+ "Content-Type": "application/json",
57
+ "server": "envoy",
58
+ "Date": date,
59
+ "x-envoy-upstream-service-time": "5",
60
+ "Content-Length": str(object=len(self.response_text)),
61
+ "strict-transport-security": "max-age=31536000",
62
+ "x-aws-region": "us-east-2, us-west-2",
63
+ "x-content-type-options": "nosniff",
64
+ }
65
+
66
+
67
+ @beartype
68
+ class ProjectInactiveError(ValidatorError):
69
+ """Exception raised when Vuforia returns a response with a result code
70
+ 'ProjectInactive'.
71
+ """
72
+
73
+ def __init__(self) -> None:
74
+ """
75
+ Attributes:
76
+ status_code: The status code to use in a response if this is
77
+ raised.
78
+ response_text: The response text to use in a response if this
79
+ is
80
+ raised.
81
+ """
82
+ super().__init__()
83
+ self.status_code = HTTPStatus.FORBIDDEN
84
+ body = {
85
+ "transaction_id": uuid.uuid4().hex,
86
+ "result_code": ResultCodes.PROJECT_INACTIVE.value,
87
+ }
88
+ self.response_text = json_dump(body=body)
89
+ date = email.utils.formatdate(
90
+ timeval=None,
91
+ localtime=False,
92
+ usegmt=True,
93
+ )
94
+ self.headers = {
95
+ "Connection": "keep-alive",
96
+ "Content-Type": "application/json",
97
+ "server": "envoy",
98
+ "Date": date,
99
+ "x-envoy-upstream-service-time": "5",
100
+ "Content-Length": str(object=len(self.response_text)),
101
+ "strict-transport-security": "max-age=31536000",
102
+ "x-aws-region": "us-east-2, us-west-2",
103
+ "x-content-type-options": "nosniff",
104
+ }
105
+
106
+
107
+ @beartype
108
+ class RequestQuotaReachedError(ValidatorError):
109
+ """Exception raised when a database's request quota is exhausted.
110
+
111
+ This response is based on Vuforia's documented status code and its common
112
+ VWS error response shape. It has not been verified against a real database
113
+ with an exhausted quota.
114
+ """
115
+
116
+ def __init__(self) -> None:
117
+ """
118
+ Attributes:
119
+ status_code: The status code to use in the response.
120
+ response_text: The response text to use in the response.
121
+ headers: The response headers.
122
+ """
123
+ super().__init__()
124
+ self.status_code = HTTPStatus.FORBIDDEN
125
+ body = {
126
+ "transaction_id": uuid.uuid4().hex,
127
+ "result_code": ResultCodes.REQUEST_QUOTA_REACHED.value,
128
+ }
129
+ self.response_text = json_dump(body=body)
130
+ date = email.utils.formatdate(
131
+ timeval=None,
132
+ localtime=False,
133
+ usegmt=True,
134
+ )
135
+ self.headers = {
136
+ "Connection": "keep-alive",
137
+ "Content-Type": "application/json",
138
+ "server": "envoy",
139
+ "Date": date,
140
+ "x-envoy-upstream-service-time": "5",
141
+ "Content-Length": str(object=len(self.response_text)),
142
+ "strict-transport-security": "max-age=31536000",
143
+ "x-aws-region": "us-east-2, us-west-2",
144
+ "x-content-type-options": "nosniff",
145
+ }
146
+
147
+
148
+ @beartype
149
+ class TargetQuotaReachedError(ValidatorError):
150
+ """Exception raised when a database's target quota is exhausted."""
151
+
152
+ def __init__(self) -> None:
153
+ """Initialize a ``TargetQuotaReached`` response."""
154
+ super().__init__()
155
+ self.status_code = HTTPStatus.FORBIDDEN
156
+ body = {
157
+ "transaction_id": uuid.uuid4().hex,
158
+ "result_code": ResultCodes.TARGET_QUOTA_REACHED.value,
159
+ }
160
+ self.response_text = json_dump(body=body)
161
+ date = email.utils.formatdate(
162
+ timeval=None,
163
+ localtime=False,
164
+ usegmt=True,
165
+ )
166
+ self.headers = {
167
+ "Connection": "keep-alive",
168
+ "Content-Type": "application/json",
169
+ "server": "envoy",
170
+ "Date": date,
171
+ "x-envoy-upstream-service-time": "5",
172
+ "Content-Length": str(object=len(self.response_text)),
173
+ "strict-transport-security": "max-age=31536000",
174
+ "x-aws-region": "us-east-2, us-west-2",
175
+ "x-content-type-options": "nosniff",
176
+ }
177
+
178
+
179
+ @beartype
180
+ class ProjectSuspendedError(ValidatorError):
181
+ """Exception raised when a database has been suspended."""
182
+
183
+ def __init__(self) -> None:
184
+ """Initialize a ``ProjectSuspended`` response."""
185
+ super().__init__()
186
+ self.status_code = HTTPStatus.FORBIDDEN
187
+ body = {
188
+ "transaction_id": uuid.uuid4().hex,
189
+ "result_code": ResultCodes.PROJECT_SUSPENDED.value,
190
+ }
191
+ self.response_text = json_dump(body=body)
192
+ date = email.utils.formatdate(
193
+ timeval=None,
194
+ localtime=False,
195
+ usegmt=True,
196
+ )
197
+ self.headers = {
198
+ "Connection": "keep-alive",
199
+ "Content-Type": "application/json",
200
+ "server": "envoy",
201
+ "Date": date,
202
+ "x-envoy-upstream-service-time": "5",
203
+ "Content-Length": str(object=len(self.response_text)),
204
+ "strict-transport-security": "max-age=31536000",
205
+ "x-aws-region": "us-east-2, us-west-2",
206
+ "x-content-type-options": "nosniff",
207
+ }
208
+
209
+
210
+ @beartype
211
+ class ProjectHasNoAPIAccessError(ValidatorError):
212
+ """Exception raised when a database cannot make API requests."""
213
+
214
+ def __init__(self) -> None:
215
+ """Initialize a ``ProjectHasNoAPIAccess`` response."""
216
+ super().__init__()
217
+ self.status_code = HTTPStatus.FORBIDDEN
218
+ body = {
219
+ "transaction_id": uuid.uuid4().hex,
220
+ "result_code": ResultCodes.PROJECT_HAS_NO_API_ACCESS.value,
221
+ }
222
+ self.response_text = json_dump(body=body)
223
+ date = email.utils.formatdate(
224
+ timeval=None,
225
+ localtime=False,
226
+ usegmt=True,
227
+ )
228
+ self.headers = {
229
+ "Connection": "keep-alive",
230
+ "Content-Type": "application/json",
231
+ "server": "envoy",
232
+ "Date": date,
233
+ "x-envoy-upstream-service-time": "5",
234
+ "Content-Length": str(object=len(self.response_text)),
235
+ "strict-transport-security": "max-age=31536000",
236
+ "x-aws-region": "us-east-2, us-west-2",
237
+ "x-content-type-options": "nosniff",
238
+ }
239
+
240
+
241
+ @beartype
242
+ class AuthenticationFailureError(ValidatorError):
243
+ """Exception raised when Vuforia returns a response with a result code
244
+ 'AuthenticationFailure'.
245
+ """
246
+
247
+ def __init__(self) -> None:
248
+ """
249
+ Attributes:
250
+ status_code: The status code to use in a response if this is
251
+ raised.
252
+ response_text: The response text to use in a response if this
253
+ is
254
+ raised.
255
+ """
256
+ super().__init__()
257
+ self.status_code = HTTPStatus.UNAUTHORIZED
258
+ body = {
259
+ "transaction_id": uuid.uuid4().hex,
260
+ "result_code": ResultCodes.AUTHENTICATION_FAILURE.value,
261
+ }
262
+ self.response_text = json_dump(body=body)
263
+ date = email.utils.formatdate(
264
+ timeval=None,
265
+ localtime=False,
266
+ usegmt=True,
267
+ )
268
+ self.headers = {
269
+ "Connection": "keep-alive",
270
+ "Content-Type": "application/json",
271
+ "server": "envoy",
272
+ "Date": date,
273
+ "x-envoy-upstream-service-time": "5",
274
+ "Content-Length": str(object=len(self.response_text)),
275
+ "strict-transport-security": "max-age=31536000",
276
+ "x-aws-region": "us-east-2, us-west-2",
277
+ "x-content-type-options": "nosniff",
278
+ }
279
+
280
+
281
+ @beartype
282
+ class FailError(ValidatorError):
283
+ """Exception raised when Vuforia returns a response with a result code
284
+ 'Fail'.
285
+ """
286
+
287
+ def __init__(self, *, status_code: HTTPStatus) -> None:
288
+ """
289
+ Attributes:
290
+ status_code: The status code to use in a response if this is
291
+ raised.
292
+ response_text: The response text to use in a response if this
293
+ is
294
+ raised.
295
+ """
296
+ super().__init__()
297
+ self.status_code = status_code
298
+ body = {
299
+ "transaction_id": uuid.uuid4().hex,
300
+ "result_code": ResultCodes.FAIL.value,
301
+ }
302
+ self.response_text = json_dump(body=body)
303
+ date = email.utils.formatdate(
304
+ timeval=None,
305
+ localtime=False,
306
+ usegmt=True,
307
+ )
308
+ self.headers = {
309
+ "Connection": "keep-alive",
310
+ "Content-Type": "application/json",
311
+ "server": "envoy",
312
+ "Date": date,
313
+ "x-envoy-upstream-service-time": "5",
314
+ "Content-Length": str(object=len(self.response_text)),
315
+ "strict-transport-security": "max-age=31536000",
316
+ "x-aws-region": "us-east-2, us-west-2",
317
+ "x-content-type-options": "nosniff",
318
+ }
319
+
320
+
321
+ @beartype
322
+ class BadRequestError(ValidatorError):
323
+ """Exception raised when Vuforia returns a response with a result code
324
+ 'BadRequest'.
325
+ """
326
+
327
+ def __init__(self) -> None:
328
+ """
329
+ Attributes:
330
+ status_code: The status code to use in a response if this is
331
+ raised.
332
+ response_text: The response text to use in a response if this
333
+ is
334
+ raised.
335
+ """
336
+ super().__init__()
337
+ self.status_code = HTTPStatus.BAD_REQUEST
338
+ body = {
339
+ "transaction_id": uuid.uuid4().hex,
340
+ "result_code": ResultCodes.BAD_REQUEST.value,
341
+ }
342
+ self.response_text = json_dump(body=body)
343
+ date = email.utils.formatdate(
344
+ timeval=None,
345
+ localtime=False,
346
+ usegmt=True,
347
+ )
348
+ self.headers = {
349
+ "Connection": "keep-alive",
350
+ "Content-Type": "application/json",
351
+ "server": "envoy",
352
+ "Date": date,
353
+ "x-envoy-upstream-service-time": "5",
354
+ "Content-Length": str(object=len(self.response_text)),
355
+ "strict-transport-security": "max-age=31536000",
356
+ "x-aws-region": "us-east-2, us-west-2",
357
+ "x-content-type-options": "nosniff",
358
+ }
359
+
360
+
361
+ @beartype
362
+ class MetadataTooLargeError(ValidatorError):
363
+ """Exception raised when Vuforia returns a response with a result code
364
+ 'MetadataTooLarge'.
365
+ """
366
+
367
+ def __init__(self) -> None:
368
+ """
369
+ Attributes:
370
+ status_code: The status code to use in a response if this is
371
+ raised.
372
+ response_text: The response text to use in a response if this
373
+ is
374
+ raised.
375
+ """
376
+ super().__init__()
377
+ self.status_code = HTTPStatus.UNPROCESSABLE_ENTITY
378
+ body = {
379
+ "transaction_id": uuid.uuid4().hex,
380
+ "result_code": ResultCodes.METADATA_TOO_LARGE.value,
381
+ }
382
+ self.response_text = json_dump(body=body)
383
+ date = email.utils.formatdate(
384
+ timeval=None,
385
+ localtime=False,
386
+ usegmt=True,
387
+ )
388
+ self.headers = {
389
+ "Connection": "keep-alive",
390
+ "Content-Type": "application/json",
391
+ "server": "envoy",
392
+ "Date": date,
393
+ "x-envoy-upstream-service-time": "5",
394
+ "Content-Length": str(object=len(self.response_text)),
395
+ "strict-transport-security": "max-age=31536000",
396
+ "x-aws-region": "us-east-2, us-west-2",
397
+ "x-content-type-options": "nosniff",
398
+ }
399
+
400
+
401
+ @beartype
402
+ class TargetNameExistError(ValidatorError):
403
+ """Exception raised when Vuforia returns a response with a result code
404
+ 'TargetNameExist'.
405
+ """
406
+
407
+ def __init__(self) -> None:
408
+ """
409
+ Attributes:
410
+ status_code: The status code to use in a response if this is
411
+ raised.
412
+ response_text: The response text to use in a response if this
413
+ is
414
+ raised.
415
+ """
416
+ super().__init__()
417
+ self.status_code = HTTPStatus.FORBIDDEN
418
+ body = {
419
+ "transaction_id": uuid.uuid4().hex,
420
+ "result_code": ResultCodes.TARGET_NAME_EXIST.value,
421
+ }
422
+ self.response_text = json_dump(body=body)
423
+ date = email.utils.formatdate(
424
+ timeval=None,
425
+ localtime=False,
426
+ usegmt=True,
427
+ )
428
+ self.headers = {
429
+ "Connection": "keep-alive",
430
+ "Content-Type": "application/json",
431
+ "server": "envoy",
432
+ "Date": date,
433
+ "x-envoy-upstream-service-time": "5",
434
+ "Content-Length": str(object=len(self.response_text)),
435
+ "strict-transport-security": "max-age=31536000",
436
+ "x-aws-region": "us-east-2, us-west-2",
437
+ "x-content-type-options": "nosniff",
438
+ }
439
+
440
+
441
+ @beartype
442
+ class BadImageError(ValidatorError):
443
+ """Exception raised when Vuforia returns a response with a result code
444
+ 'BadImage'.
445
+ """
446
+
447
+ def __init__(self) -> None:
448
+ """
449
+ Attributes:
450
+ status_code: The status code to use in a response if this is
451
+ raised.
452
+ response_text: The response text to use in a response if this
453
+ is
454
+ raised.
455
+ """
456
+ super().__init__()
457
+ self.status_code = HTTPStatus.UNPROCESSABLE_ENTITY
458
+ body = {
459
+ "transaction_id": uuid.uuid4().hex,
460
+ "result_code": ResultCodes.BAD_IMAGE.value,
461
+ }
462
+ self.response_text = json_dump(body=body)
463
+ date = email.utils.formatdate(
464
+ timeval=None,
465
+ localtime=False,
466
+ usegmt=True,
467
+ )
468
+ self.headers = {
469
+ "Connection": "keep-alive",
470
+ "Content-Type": "application/json",
471
+ "server": "envoy",
472
+ "Date": date,
473
+ "x-envoy-upstream-service-time": "5",
474
+ "Content-Length": str(object=len(self.response_text)),
475
+ "strict-transport-security": "max-age=31536000",
476
+ "x-aws-region": "us-east-2, us-west-2",
477
+ "x-content-type-options": "nosniff",
478
+ }
479
+
480
+
481
+ @beartype
482
+ class ImageTooLargeError(ValidatorError):
483
+ """Exception raised when Vuforia returns a response with a result code
484
+ 'ImageTooLarge'.
485
+ """
486
+
487
+ def __init__(self) -> None:
488
+ """
489
+ Attributes:
490
+ status_code: The status code to use in a response if this is
491
+ raised.
492
+ response_text: The response text to use in a response if this
493
+ is
494
+ raised.
495
+ """
496
+ super().__init__()
497
+ self.status_code = HTTPStatus.UNPROCESSABLE_ENTITY
498
+ body = {
499
+ "transaction_id": uuid.uuid4().hex,
500
+ "result_code": ResultCodes.IMAGE_TOO_LARGE.value,
501
+ }
502
+ self.response_text = json_dump(body=body)
503
+ date = email.utils.formatdate(
504
+ timeval=None,
505
+ localtime=False,
506
+ usegmt=True,
507
+ )
508
+ self.headers = {
509
+ "Connection": "keep-alive",
510
+ "Content-Type": "application/json",
511
+ "server": "envoy",
512
+ "Date": date,
513
+ "x-envoy-upstream-service-time": "5",
514
+ "Content-Length": str(object=len(self.response_text)),
515
+ "strict-transport-security": "max-age=31536000",
516
+ "x-aws-region": "us-east-2, us-west-2",
517
+ "x-content-type-options": "nosniff",
518
+ }
519
+
520
+
521
+ @beartype
522
+ class RequestTimeTooSkewedError(ValidatorError):
523
+ """Exception raised when Vuforia returns a response with a result code
524
+ 'RequestTimeTooSkewed'.
525
+ """
526
+
527
+ def __init__(self) -> None:
528
+ """
529
+ Attributes:
530
+ status_code: The status code to use in a response if this is
531
+ raised.
532
+ response_text: The response text to use in a response if this
533
+ is
534
+ raised.
535
+ """
536
+ super().__init__()
537
+ self.status_code = HTTPStatus.FORBIDDEN
538
+ body = {
539
+ "transaction_id": uuid.uuid4().hex,
540
+ "result_code": ResultCodes.REQUEST_TIME_TOO_SKEWED.value,
541
+ }
542
+ self.response_text = json_dump(body=body)
543
+ date = email.utils.formatdate(
544
+ timeval=None,
545
+ localtime=False,
546
+ usegmt=True,
547
+ )
548
+ self.headers = {
549
+ "Connection": "keep-alive",
550
+ "Content-Type": "application/json",
551
+ "server": "envoy",
552
+ "Date": date,
553
+ "x-envoy-upstream-service-time": "5",
554
+ "Content-Length": str(object=len(self.response_text)),
555
+ "strict-transport-security": "max-age=31536000",
556
+ "x-aws-region": "us-east-2, us-west-2",
557
+ "x-content-type-options": "nosniff",
558
+ }
559
+
560
+
561
+ @beartype
562
+ class ContentLengthHeaderTooLargeError(ValidatorError):
563
+ """
564
+ Exception raised when the given content length header is too
565
+ large.
566
+ """
567
+
568
+ # We skip coverage here as running a test to cover this is very slow.
569
+ def __init__(self) -> None: # pragma: no cover
570
+ """
571
+ Attributes:
572
+ status_code: The status code to use in a response if this is
573
+ raised.
574
+ response_text: The response text to use in a response if this
575
+ is
576
+ raised.
577
+ """
578
+ super().__init__()
579
+ self.status_code = HTTPStatus.REQUEST_TIMEOUT
580
+ date = email.utils.formatdate(
581
+ timeval=None,
582
+ localtime=False,
583
+ usegmt=True,
584
+ )
585
+ self.response_text = "stream timeout"
586
+ self.headers = {
587
+ "Content-Length": str(object=len(self.response_text)),
588
+ "Date": date,
589
+ "server": "envoy",
590
+ "Content-Type": "text/plain",
591
+ "Connection": "close",
592
+ }
593
+
594
+
595
+ @beartype
596
+ class ContentLengthHeaderNotIntError(ValidatorError):
597
+ """
598
+ Exception raised when the given content length header is not an
599
+ integer.
600
+ """
601
+
602
+ def __init__(self) -> None:
603
+ """
604
+ Attributes:
605
+ status_code: The status code to use in a response if this is
606
+ raised.
607
+ response_text: The response text to use in a response if this
608
+ is
609
+ raised.
610
+ """
611
+ super().__init__()
612
+ self.status_code = HTTPStatus.BAD_REQUEST
613
+ self.response_text = textwrap.dedent(
614
+ text="""\
615
+ <html>\r
616
+ <head><title>400 Bad Request</title></head>\r
617
+ <body>\r
618
+ <center><h1>400 Bad Request</h1></center>\r
619
+ </body>\r
620
+ </html>\r
621
+ """,
622
+ )
623
+ date = email.utils.formatdate(
624
+ timeval=None,
625
+ localtime=False,
626
+ usegmt=True,
627
+ )
628
+ self.headers = {
629
+ "Connection": "close",
630
+ "Content-Length": str(object=len(self.response_text)),
631
+ "Date": date,
632
+ "Server": "awselb/2.0",
633
+ "Content-Type": "text/html",
634
+ }
635
+
636
+
637
+ @beartype
638
+ class UnnecessaryRequestBodyError(ValidatorError):
639
+ """Exception raised when a request body is given but not necessary."""
640
+
641
+ def __init__(self) -> None:
642
+ """
643
+ Attributes:
644
+ status_code: The status code to use in a response if this is
645
+ raised.
646
+ response_text: The response text to use in a response if this
647
+ is
648
+ raised.
649
+ """
650
+ super().__init__()
651
+ self.status_code = HTTPStatus.BAD_REQUEST
652
+ self.response_text = ""
653
+ date = email.utils.formatdate(
654
+ timeval=None,
655
+ localtime=False,
656
+ usegmt=True,
657
+ )
658
+ self.headers = {
659
+ "server": "envoy",
660
+ "Date": date,
661
+ "x-envoy-upstream-service-time": "5",
662
+ "Content-Length": str(object=len(self.response_text)),
663
+ }
664
+
665
+
666
+ @beartype
667
+ class TargetStatusNotSuccessError(ValidatorError):
668
+ """
669
+ Exception raised when trying to update a target that does not have a
670
+ success status.
671
+ """
672
+
673
+ def __init__(self) -> None:
674
+ """
675
+ Attributes:
676
+ status_code: The status code to use in a response if this is
677
+ raised.
678
+ response_text: The response text to use in a response if this
679
+ is
680
+ raised.
681
+ """
682
+ super().__init__()
683
+ self.status_code = HTTPStatus.FORBIDDEN
684
+ body = {
685
+ "transaction_id": uuid.uuid4().hex,
686
+ "result_code": ResultCodes.TARGET_STATUS_NOT_SUCCESS.value,
687
+ }
688
+ self.response_text = json_dump(body=body)
689
+ date = email.utils.formatdate(
690
+ timeval=None,
691
+ localtime=False,
692
+ usegmt=True,
693
+ )
694
+ self.headers = {
695
+ "Connection": "keep-alive",
696
+ "Content-Type": "application/json",
697
+ "server": "envoy",
698
+ "Date": date,
699
+ "x-envoy-upstream-service-time": "5",
700
+ "Content-Length": str(object=len(self.response_text)),
701
+ "strict-transport-security": "max-age=31536000",
702
+ "x-aws-region": "us-east-2, us-west-2",
703
+ "x-content-type-options": "nosniff",
704
+ }
705
+
706
+
707
+ @beartype
708
+ class InvalidAcceptHeaderError(ValidatorError):
709
+ """Exception raised when an unsupported Accept header is given."""
710
+
711
+ def __init__(self) -> None:
712
+ """
713
+ Attributes:
714
+ status_code: The status code to use in a response if this is
715
+ raised.
716
+ response_text: The response text to use in a response if this
717
+ is
718
+ raised.
719
+ """
720
+ super().__init__()
721
+ self.status_code = HTTPStatus.BAD_REQUEST
722
+ body = {
723
+ "transaction_id": uuid.uuid4().hex,
724
+ "result_code": ResultCodes.INVALID_ACCEPT_HEADER.value,
725
+ }
726
+ self.response_text = json_dump(body=body)
727
+ date = email.utils.formatdate(
728
+ timeval=None,
729
+ localtime=False,
730
+ usegmt=True,
731
+ )
732
+ self.headers = {
733
+ "Connection": "keep-alive",
734
+ "Content-Type": "application/json",
735
+ "server": "envoy",
736
+ "Date": date,
737
+ "x-envoy-upstream-service-time": "5",
738
+ "Content-Length": str(object=len(self.response_text)),
739
+ "strict-transport-security": "max-age=31536000",
740
+ "x-aws-region": "us-east-2, us-west-2",
741
+ "x-content-type-options": "nosniff",
742
+ }
743
+
744
+
745
+ @beartype
746
+ class InvalidInstanceIdError(ValidatorError):
747
+ """Exception raised when an invalid instance_id is given."""
748
+
749
+ def __init__(self) -> None:
750
+ """
751
+ Attributes:
752
+ status_code: The status code to use in a response if this is
753
+ raised.
754
+ response_text: The response text to use in a response if this
755
+ is
756
+ raised.
757
+ """
758
+ super().__init__()
759
+ self.status_code = HTTPStatus.UNPROCESSABLE_ENTITY
760
+ body = {
761
+ "transaction_id": uuid.uuid4().hex,
762
+ "result_code": ResultCodes.INVALID_INSTANCE_ID.value,
763
+ }
764
+ self.response_text = json_dump(body=body)
765
+ date = email.utils.formatdate(
766
+ timeval=None,
767
+ localtime=False,
768
+ usegmt=True,
769
+ )
770
+ self.headers = {
771
+ "Connection": "keep-alive",
772
+ "Content-Type": "application/json",
773
+ "server": "envoy",
774
+ "Date": date,
775
+ "x-envoy-upstream-service-time": "5",
776
+ "Content-Length": str(object=len(self.response_text)),
777
+ "strict-transport-security": "max-age=31536000",
778
+ "x-aws-region": "us-east-2, us-west-2",
779
+ "x-content-type-options": "nosniff",
780
+ }
781
+
782
+
783
+ @beartype
784
+ class InvalidTargetTypeError(ValidatorError):
785
+ """Exception raised when the target type is not valid for the
786
+ operation.
787
+ """
788
+
789
+ def __init__(self) -> None:
790
+ """
791
+ Attributes:
792
+ status_code: The status code to use in a response if this is
793
+ raised.
794
+ response_text: The response text to use in a response if this
795
+ is
796
+ raised.
797
+ """
798
+ super().__init__()
799
+ self.status_code = HTTPStatus.UNPROCESSABLE_ENTITY
800
+ body = {
801
+ "transaction_id": uuid.uuid4().hex,
802
+ "result_code": ResultCodes.INVALID_TARGET_TYPE.value,
803
+ }
804
+ self.response_text = json_dump(body=body)
805
+ date = email.utils.formatdate(
806
+ timeval=None,
807
+ localtime=False,
808
+ usegmt=True,
809
+ )
810
+ self.headers = {
811
+ "Connection": "keep-alive",
812
+ "Content-Type": "application/json",
813
+ "server": "envoy",
814
+ "Date": date,
815
+ "x-envoy-upstream-service-time": "5",
816
+ "Content-Length": str(object=len(self.response_text)),
817
+ "strict-transport-security": "max-age=31536000",
818
+ "x-aws-region": "us-east-2, us-west-2",
819
+ "x-content-type-options": "nosniff",
820
+ }
821
+
822
+
823
+ @beartype
824
+ class TargetStatusProcessingError(ValidatorError):
825
+ """Exception raised when trying to delete a target which is processing."""
826
+
827
+ def __init__(self) -> None:
828
+ """
829
+ Attributes:
830
+ status_code: The status code to use in a response if this is
831
+ raised.
832
+ response_text: The response text to use in a response if this
833
+ is
834
+ raised.
835
+ """
836
+ super().__init__()
837
+ self.status_code = HTTPStatus.FORBIDDEN
838
+ body = {
839
+ "transaction_id": uuid.uuid4().hex,
840
+ "result_code": ResultCodes.TARGET_STATUS_PROCESSING.value,
841
+ }
842
+ self.response_text = json_dump(body=body)
843
+ date = email.utils.formatdate(
844
+ timeval=None,
845
+ localtime=False,
846
+ usegmt=True,
847
+ )
848
+ self.headers = {
849
+ "Connection": "keep-alive",
850
+ "Content-Type": "application/json",
851
+ "server": "envoy",
852
+ "Date": date,
853
+ "x-envoy-upstream-service-time": "5",
854
+ "Content-Length": str(object=len(self.response_text)),
855
+ "strict-transport-security": "max-age=31536000",
856
+ "x-aws-region": "us-east-2, us-west-2",
857
+ "x-content-type-options": "nosniff",
858
+ }