schemathesis 3.25.6__py3-none-any.whl → 3.39.7__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.
- schemathesis/__init__.py +6 -6
- schemathesis/_compat.py +2 -2
- schemathesis/_dependency_versions.py +4 -2
- schemathesis/_hypothesis.py +369 -56
- schemathesis/_lazy_import.py +1 -0
- schemathesis/_override.py +5 -4
- schemathesis/_patches.py +21 -0
- schemathesis/_rate_limiter.py +7 -0
- schemathesis/_xml.py +75 -22
- schemathesis/auths.py +78 -16
- schemathesis/checks.py +21 -9
- schemathesis/cli/__init__.py +783 -432
- schemathesis/cli/__main__.py +4 -0
- schemathesis/cli/callbacks.py +58 -13
- schemathesis/cli/cassettes.py +233 -47
- schemathesis/cli/constants.py +8 -2
- schemathesis/cli/context.py +22 -5
- schemathesis/cli/debug.py +2 -1
- schemathesis/cli/handlers.py +4 -1
- schemathesis/cli/junitxml.py +103 -22
- schemathesis/cli/options.py +15 -4
- schemathesis/cli/output/default.py +258 -112
- schemathesis/cli/output/short.py +23 -8
- schemathesis/cli/reporting.py +79 -0
- schemathesis/cli/sanitization.py +6 -0
- schemathesis/code_samples.py +5 -3
- schemathesis/constants.py +1 -0
- schemathesis/contrib/openapi/__init__.py +1 -1
- schemathesis/contrib/openapi/fill_missing_examples.py +3 -1
- schemathesis/contrib/openapi/formats/uuid.py +2 -1
- schemathesis/contrib/unique_data.py +3 -3
- schemathesis/exceptions.py +76 -65
- schemathesis/experimental/__init__.py +35 -0
- schemathesis/extra/_aiohttp.py +1 -0
- schemathesis/extra/_flask.py +4 -1
- schemathesis/extra/_server.py +1 -0
- schemathesis/extra/pytest_plugin.py +17 -25
- schemathesis/failures.py +77 -9
- schemathesis/filters.py +185 -8
- schemathesis/fixups/__init__.py +1 -0
- schemathesis/fixups/fast_api.py +2 -2
- schemathesis/fixups/utf8_bom.py +1 -2
- schemathesis/generation/__init__.py +20 -36
- schemathesis/generation/_hypothesis.py +59 -0
- schemathesis/generation/_methods.py +44 -0
- schemathesis/generation/coverage.py +931 -0
- schemathesis/graphql.py +0 -1
- schemathesis/hooks.py +89 -12
- schemathesis/internal/checks.py +84 -0
- schemathesis/internal/copy.py +22 -3
- schemathesis/internal/deprecation.py +6 -2
- schemathesis/internal/diff.py +15 -0
- schemathesis/internal/extensions.py +27 -0
- schemathesis/internal/jsonschema.py +2 -1
- schemathesis/internal/output.py +68 -0
- schemathesis/internal/result.py +1 -1
- schemathesis/internal/transformation.py +11 -0
- schemathesis/lazy.py +138 -25
- schemathesis/loaders.py +7 -5
- schemathesis/models.py +318 -211
- schemathesis/parameters.py +4 -0
- schemathesis/runner/__init__.py +50 -15
- schemathesis/runner/events.py +65 -5
- schemathesis/runner/impl/context.py +104 -0
- schemathesis/runner/impl/core.py +388 -177
- schemathesis/runner/impl/solo.py +19 -29
- schemathesis/runner/impl/threadpool.py +70 -79
- schemathesis/runner/probes.py +11 -9
- schemathesis/runner/serialization.py +150 -17
- schemathesis/sanitization.py +5 -1
- schemathesis/schemas.py +170 -102
- schemathesis/serializers.py +7 -2
- schemathesis/service/ci.py +1 -0
- schemathesis/service/client.py +39 -6
- schemathesis/service/events.py +5 -1
- schemathesis/service/extensions.py +224 -0
- schemathesis/service/hosts.py +6 -2
- schemathesis/service/metadata.py +25 -0
- schemathesis/service/models.py +211 -2
- schemathesis/service/report.py +6 -6
- schemathesis/service/serialization.py +45 -71
- schemathesis/service/usage.py +1 -0
- schemathesis/specs/graphql/_cache.py +26 -0
- schemathesis/specs/graphql/loaders.py +25 -5
- schemathesis/specs/graphql/nodes.py +1 -0
- schemathesis/specs/graphql/scalars.py +2 -2
- schemathesis/specs/graphql/schemas.py +130 -100
- schemathesis/specs/graphql/validation.py +1 -2
- schemathesis/specs/openapi/__init__.py +1 -0
- schemathesis/specs/openapi/_cache.py +123 -0
- schemathesis/specs/openapi/_hypothesis.py +78 -60
- schemathesis/specs/openapi/checks.py +504 -25
- schemathesis/specs/openapi/converter.py +31 -4
- schemathesis/specs/openapi/definitions.py +10 -17
- schemathesis/specs/openapi/examples.py +126 -12
- schemathesis/specs/openapi/expressions/__init__.py +37 -2
- schemathesis/specs/openapi/expressions/context.py +1 -1
- schemathesis/specs/openapi/expressions/extractors.py +26 -0
- schemathesis/specs/openapi/expressions/lexer.py +20 -18
- schemathesis/specs/openapi/expressions/nodes.py +29 -6
- schemathesis/specs/openapi/expressions/parser.py +26 -5
- schemathesis/specs/openapi/formats.py +44 -0
- schemathesis/specs/openapi/links.py +125 -42
- schemathesis/specs/openapi/loaders.py +77 -36
- schemathesis/specs/openapi/media_types.py +34 -0
- schemathesis/specs/openapi/negative/__init__.py +6 -3
- schemathesis/specs/openapi/negative/mutations.py +21 -6
- schemathesis/specs/openapi/parameters.py +39 -25
- schemathesis/specs/openapi/patterns.py +137 -0
- schemathesis/specs/openapi/references.py +37 -7
- schemathesis/specs/openapi/schemas.py +360 -241
- schemathesis/specs/openapi/security.py +25 -7
- schemathesis/specs/openapi/serialization.py +1 -0
- schemathesis/specs/openapi/stateful/__init__.py +198 -70
- schemathesis/specs/openapi/stateful/statistic.py +198 -0
- schemathesis/specs/openapi/stateful/types.py +14 -0
- schemathesis/specs/openapi/utils.py +6 -1
- schemathesis/specs/openapi/validation.py +1 -0
- schemathesis/stateful/__init__.py +35 -21
- schemathesis/stateful/config.py +97 -0
- schemathesis/stateful/context.py +135 -0
- schemathesis/stateful/events.py +274 -0
- schemathesis/stateful/runner.py +309 -0
- schemathesis/stateful/sink.py +68 -0
- schemathesis/stateful/state_machine.py +67 -38
- schemathesis/stateful/statistic.py +22 -0
- schemathesis/stateful/validation.py +100 -0
- schemathesis/targets.py +33 -1
- schemathesis/throttling.py +25 -5
- schemathesis/transports/__init__.py +354 -0
- schemathesis/transports/asgi.py +7 -0
- schemathesis/transports/auth.py +25 -2
- schemathesis/transports/content_types.py +3 -1
- schemathesis/transports/headers.py +2 -1
- schemathesis/transports/responses.py +9 -4
- schemathesis/types.py +9 -0
- schemathesis/utils.py +11 -16
- schemathesis-3.39.7.dist-info/METADATA +293 -0
- schemathesis-3.39.7.dist-info/RECORD +160 -0
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/WHEEL +1 -1
- schemathesis/specs/openapi/filters.py +0 -49
- schemathesis/specs/openapi/stateful/links.py +0 -92
- schemathesis-3.25.6.dist-info/METADATA +0 -356
- schemathesis-3.25.6.dist-info/RECORD +0 -134
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/entry_points.txt +0 -0
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,39 +2,46 @@
|
|
|
2
2
|
|
|
3
3
|
They all consist of primitive types and don't have references to schemas, app, etc.
|
|
4
4
|
"""
|
|
5
|
+
|
|
5
6
|
from __future__ import annotations
|
|
7
|
+
|
|
6
8
|
import logging
|
|
7
9
|
import re
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
+
import textwrap
|
|
11
|
+
from dataclasses import asdict, dataclass, field
|
|
12
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
10
13
|
|
|
11
|
-
from ..transports import serialize_payload
|
|
12
14
|
from ..code_samples import get_excluded_headers
|
|
13
15
|
from ..exceptions import (
|
|
14
|
-
FailureContext,
|
|
15
|
-
InternalError,
|
|
16
|
-
make_unique_by_key,
|
|
17
|
-
format_exception,
|
|
18
|
-
extract_requests_exception_details,
|
|
19
|
-
RuntimeErrorType,
|
|
20
|
-
DeadlineExceeded,
|
|
21
|
-
OperationSchemaError,
|
|
22
16
|
BodyInGetRequestError,
|
|
17
|
+
DeadlineExceeded,
|
|
18
|
+
InternalError,
|
|
23
19
|
InvalidRegularExpression,
|
|
20
|
+
OperationSchemaError,
|
|
21
|
+
RecursiveReferenceError,
|
|
22
|
+
RuntimeErrorType,
|
|
24
23
|
SerializationError,
|
|
25
24
|
UnboundPrefixError,
|
|
25
|
+
extract_requests_exception_details,
|
|
26
|
+
format_exception,
|
|
27
|
+
make_unique_by_key,
|
|
26
28
|
)
|
|
27
|
-
from ..models import Case, Check, Interaction, Request, Response, Status, TestResult
|
|
29
|
+
from ..models import Case, Check, Interaction, Request, Response, Status, TestPhase, TestResult, TransitionId
|
|
30
|
+
from ..transports import deserialize_payload, serialize_payload
|
|
28
31
|
|
|
29
32
|
if TYPE_CHECKING:
|
|
30
33
|
import hypothesis.errors
|
|
31
34
|
from requests.structures import CaseInsensitiveDict
|
|
32
35
|
|
|
36
|
+
from ..failures import FailureContext
|
|
37
|
+
from ..generation import DataGenerationMethod
|
|
38
|
+
|
|
33
39
|
|
|
34
40
|
@dataclass
|
|
35
41
|
class SerializedCase:
|
|
36
42
|
# Case data
|
|
37
43
|
id: str
|
|
44
|
+
generation_time: float
|
|
38
45
|
path_parameters: dict[str, Any] | None
|
|
39
46
|
headers: dict[str, Any] | None
|
|
40
47
|
cookies: dict[str, Any] | None
|
|
@@ -46,7 +53,9 @@ class SerializedCase:
|
|
|
46
53
|
method: str
|
|
47
54
|
url: str
|
|
48
55
|
path_template: str
|
|
56
|
+
full_path: str
|
|
49
57
|
verbose_name: str
|
|
58
|
+
transition_id: TransitionId | None
|
|
50
59
|
# Transport info
|
|
51
60
|
verify: bool
|
|
52
61
|
# Headers coming from sources outside data generation
|
|
@@ -59,6 +68,7 @@ class SerializedCase:
|
|
|
59
68
|
serialized_body = _serialize_body(request_data.body)
|
|
60
69
|
return cls(
|
|
61
70
|
id=case.id,
|
|
71
|
+
generation_time=case.generation_time,
|
|
62
72
|
path_parameters=case.path_parameters,
|
|
63
73
|
headers=dict(case.headers) if case.headers is not None else None,
|
|
64
74
|
cookies=case.cookies,
|
|
@@ -71,11 +81,21 @@ class SerializedCase:
|
|
|
71
81
|
method=case.method,
|
|
72
82
|
url=request_data.url,
|
|
73
83
|
path_template=case.path,
|
|
84
|
+
full_path=case.full_path,
|
|
74
85
|
verbose_name=case.operation.verbose_name,
|
|
86
|
+
transition_id=case.source.transition_id if case.source is not None else None,
|
|
75
87
|
verify=verify,
|
|
76
88
|
extra_headers=request_data.headers,
|
|
77
89
|
)
|
|
78
90
|
|
|
91
|
+
def deserialize_body(self) -> bytes | None:
|
|
92
|
+
"""Deserialize the test case body.
|
|
93
|
+
|
|
94
|
+
`SerializedCase` should be serializable to JSON, therefore body is encoded as base64 string
|
|
95
|
+
to support arbitrary binary data.
|
|
96
|
+
"""
|
|
97
|
+
return deserialize_payload(self.body)
|
|
98
|
+
|
|
79
99
|
|
|
80
100
|
def _serialize_body(body: str | bytes | None) -> str | None:
|
|
81
101
|
if body is None:
|
|
@@ -105,6 +125,7 @@ class SerializedCheck:
|
|
|
105
125
|
@classmethod
|
|
106
126
|
def from_check(cls, check: Check) -> SerializedCheck:
|
|
107
127
|
import requests
|
|
128
|
+
|
|
108
129
|
from ..transports.responses import WSGIResponse
|
|
109
130
|
|
|
110
131
|
if check.response is not None:
|
|
@@ -137,9 +158,32 @@ class SerializedCheck:
|
|
|
137
158
|
history=history,
|
|
138
159
|
)
|
|
139
160
|
|
|
161
|
+
@property
|
|
162
|
+
def title(self) -> str:
|
|
163
|
+
if self.context is not None:
|
|
164
|
+
return self.context.title
|
|
165
|
+
return f"Custom check failed: `{self.name}`"
|
|
166
|
+
|
|
167
|
+
@property
|
|
168
|
+
def formatted_message(self) -> str | None:
|
|
169
|
+
if self.context is not None:
|
|
170
|
+
if self.context.message:
|
|
171
|
+
message = self.context.message
|
|
172
|
+
else:
|
|
173
|
+
message = None
|
|
174
|
+
else:
|
|
175
|
+
message = self.message
|
|
176
|
+
if message is not None:
|
|
177
|
+
message = textwrap.indent(message, prefix=" ")
|
|
178
|
+
return message
|
|
179
|
+
|
|
140
180
|
|
|
141
181
|
def _get_headers(headers: dict[str, Any] | CaseInsensitiveDict) -> dict[str, str]:
|
|
142
|
-
return {
|
|
182
|
+
return {
|
|
183
|
+
key: value[0] if isinstance(value, list) else value
|
|
184
|
+
for key, value in headers.items()
|
|
185
|
+
if key not in get_excluded_headers()
|
|
186
|
+
}
|
|
143
187
|
|
|
144
188
|
|
|
145
189
|
@dataclass
|
|
@@ -200,8 +244,8 @@ class SerializedError:
|
|
|
200
244
|
|
|
201
245
|
@classmethod
|
|
202
246
|
def from_exception(cls, exception: Exception) -> SerializedError:
|
|
203
|
-
import requests
|
|
204
247
|
import hypothesis.errors
|
|
248
|
+
import requests
|
|
205
249
|
from hypothesis import HealthCheck
|
|
206
250
|
|
|
207
251
|
title = "Runtime Error"
|
|
@@ -219,6 +263,11 @@ class SerializedError:
|
|
|
219
263
|
type_ = RuntimeErrorType.HYPOTHESIS_DEADLINE_EXCEEDED
|
|
220
264
|
message = str(exception).strip()
|
|
221
265
|
extras = []
|
|
266
|
+
elif isinstance(exception, RecursiveReferenceError):
|
|
267
|
+
type_ = RuntimeErrorType.SCHEMA_UNSUPPORTED
|
|
268
|
+
message = str(exception).strip()
|
|
269
|
+
extras = []
|
|
270
|
+
title = "Unsupported Schema"
|
|
222
271
|
elif isinstance(exception, hypothesis.errors.InvalidArgument) and str(exception).startswith("Scalar "):
|
|
223
272
|
# Comes from `hypothesis-graphql`
|
|
224
273
|
scalar_name = _scalar_name_from_error(exception)
|
|
@@ -226,8 +275,10 @@ class SerializedError:
|
|
|
226
275
|
message = f"Scalar type '{scalar_name}' is not recognized"
|
|
227
276
|
extras = []
|
|
228
277
|
title = "Unknown GraphQL Scalar"
|
|
229
|
-
elif
|
|
230
|
-
|
|
278
|
+
elif (
|
|
279
|
+
isinstance(exception, hypothesis.errors.InvalidArgument)
|
|
280
|
+
and str(exception).endswith("larger than Hypothesis is designed to handle")
|
|
281
|
+
or "can never generate an example, because min_size is larger than Hypothesis supports" in str(exception)
|
|
231
282
|
):
|
|
232
283
|
type_ = RuntimeErrorType.HYPOTHESIS_HEALTH_CHECK_LARGE_BASE_EXAMPLE
|
|
233
284
|
message = HEALTH_CHECK_MESSAGE_LARGE_BASE_EXAMPLE
|
|
@@ -238,6 +289,7 @@ class SerializedError:
|
|
|
238
289
|
message = f"{exception}. Possible reasons:"
|
|
239
290
|
extras = [
|
|
240
291
|
"- Contradictory schema constraints, such as a minimum value exceeding the maximum.",
|
|
292
|
+
"- Invalid schema definitions for headers or cookies, for example allowing for non-ASCII characters.",
|
|
241
293
|
"- Excessive schema complexity, which hinders parameter generation.",
|
|
242
294
|
]
|
|
243
295
|
title = "Schema Error"
|
|
@@ -339,9 +391,15 @@ def _scalar_name_from_error(exception: hypothesis.errors.InvalidArgument) -> str
|
|
|
339
391
|
@dataclass
|
|
340
392
|
class SerializedInteraction:
|
|
341
393
|
request: Request
|
|
342
|
-
response: Response
|
|
394
|
+
response: Response | None
|
|
343
395
|
checks: list[SerializedCheck]
|
|
344
396
|
status: Status
|
|
397
|
+
data_generation_method: DataGenerationMethod
|
|
398
|
+
phase: TestPhase | None
|
|
399
|
+
description: str | None
|
|
400
|
+
location: str | None
|
|
401
|
+
parameter: str | None
|
|
402
|
+
parameter_location: str | None
|
|
345
403
|
recorded_at: str
|
|
346
404
|
|
|
347
405
|
@classmethod
|
|
@@ -351,6 +409,12 @@ class SerializedInteraction:
|
|
|
351
409
|
response=interaction.response,
|
|
352
410
|
checks=[SerializedCheck.from_check(check) for check in interaction.checks],
|
|
353
411
|
status=interaction.status,
|
|
412
|
+
data_generation_method=interaction.data_generation_method,
|
|
413
|
+
phase=interaction.phase,
|
|
414
|
+
description=interaction.description,
|
|
415
|
+
location=interaction.location,
|
|
416
|
+
parameter=interaction.parameter,
|
|
417
|
+
parameter_location=interaction.parameter_location,
|
|
354
418
|
recorded_at=interaction.recorded_at,
|
|
355
419
|
)
|
|
356
420
|
|
|
@@ -409,3 +473,72 @@ def deduplicate_failures(checks: list[SerializedCheck]) -> list[SerializedCheck]
|
|
|
409
473
|
unique_checks.append(check)
|
|
410
474
|
seen.add(key)
|
|
411
475
|
return unique_checks
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def _serialize_case(case: SerializedCase) -> dict[str, Any]:
|
|
479
|
+
return {
|
|
480
|
+
"id": case.id,
|
|
481
|
+
"generation_time": case.generation_time,
|
|
482
|
+
"verbose_name": case.verbose_name,
|
|
483
|
+
"path_template": case.path_template,
|
|
484
|
+
"path_parameters": stringify_path_parameters(case.path_parameters),
|
|
485
|
+
"query": prepare_query(case.query),
|
|
486
|
+
"cookies": case.cookies,
|
|
487
|
+
"media_type": case.media_type,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
def _serialize_response(response: Response) -> dict[str, Any]:
|
|
492
|
+
return {
|
|
493
|
+
"status_code": response.status_code,
|
|
494
|
+
"headers": response.headers,
|
|
495
|
+
"body": response.body,
|
|
496
|
+
"encoding": response.encoding,
|
|
497
|
+
"elapsed": response.elapsed,
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def _serialize_check(check: SerializedCheck) -> dict[str, Any]:
|
|
502
|
+
return {
|
|
503
|
+
"name": check.name,
|
|
504
|
+
"value": check.value,
|
|
505
|
+
"request": {
|
|
506
|
+
"method": check.request.method,
|
|
507
|
+
"uri": check.request.uri,
|
|
508
|
+
"body": check.request.body,
|
|
509
|
+
"headers": check.request.headers,
|
|
510
|
+
},
|
|
511
|
+
"response": _serialize_response(check.response) if check.response is not None else None,
|
|
512
|
+
"example": _serialize_case(check.example),
|
|
513
|
+
"message": check.message,
|
|
514
|
+
"context": asdict(check.context) if check.context is not None else None, # type: ignore
|
|
515
|
+
"history": [
|
|
516
|
+
{"case": _serialize_case(entry.case), "response": _serialize_response(entry.response)}
|
|
517
|
+
for entry in check.history
|
|
518
|
+
],
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def stringify_path_parameters(path_parameters: dict[str, Any] | None) -> dict[str, str]:
|
|
523
|
+
"""Cast all path parameter values to strings.
|
|
524
|
+
|
|
525
|
+
Path parameter values may be of arbitrary type, but to display them properly they should be casted to strings.
|
|
526
|
+
"""
|
|
527
|
+
return {key: str(value) for key, value in (path_parameters or {}).items()}
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def prepare_query(query: dict[str, Any] | None) -> dict[str, list[str]]:
|
|
531
|
+
"""Convert all query values to list of strings.
|
|
532
|
+
|
|
533
|
+
Query parameters may be generated in different shapes, including integers, strings, list of strings, etc.
|
|
534
|
+
It can also be an object, if the schema contains an object, but `style` and `explode` combo is not applicable.
|
|
535
|
+
"""
|
|
536
|
+
|
|
537
|
+
def to_list_of_strings(value: Any) -> list[str]:
|
|
538
|
+
if isinstance(value, list):
|
|
539
|
+
return list(map(str, value))
|
|
540
|
+
if isinstance(value, str):
|
|
541
|
+
return [value]
|
|
542
|
+
return [str(value)]
|
|
543
|
+
|
|
544
|
+
return {key: to_list_of_strings(value) for key, value in (query or {}).items()}
|
schemathesis/sanitization.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
import threading
|
|
3
4
|
from collections.abc import MutableMapping, MutableSequence
|
|
4
5
|
from dataclasses import dataclass, replace
|
|
@@ -9,6 +10,7 @@ from .constants import NOT_SET
|
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
12
|
from requests import PreparedRequest
|
|
13
|
+
|
|
12
14
|
from .models import Case, CaseSource, Request
|
|
13
15
|
from .runner.serialization import SerializedCase, SerializedCheck, SerializedInteraction
|
|
14
16
|
from .transports.responses import GenericResponse
|
|
@@ -236,6 +238,7 @@ def sanitize_serialized_check(check: SerializedCheck, *, config: Config | None =
|
|
|
236
238
|
|
|
237
239
|
|
|
238
240
|
def sanitize_serialized_case(case: SerializedCase, *, config: Config | None = None) -> None:
|
|
241
|
+
case.url = sanitize_url(case.url, config=config)
|
|
239
242
|
for value in (case.path_parameters, case.headers, case.cookies, case.query, case.extra_headers):
|
|
240
243
|
if value is not None:
|
|
241
244
|
sanitize_value(value, config=config)
|
|
@@ -243,6 +246,7 @@ def sanitize_serialized_case(case: SerializedCase, *, config: Config | None = No
|
|
|
243
246
|
|
|
244
247
|
def sanitize_serialized_interaction(interaction: SerializedInteraction, *, config: Config | None = None) -> None:
|
|
245
248
|
sanitize_request(interaction.request, config=config)
|
|
246
|
-
|
|
249
|
+
if interaction.response is not None:
|
|
250
|
+
sanitize_value(interaction.response.headers, config=config)
|
|
247
251
|
for check in interaction.checks:
|
|
248
252
|
sanitize_serialized_check(check, config=config)
|