schemathesis 3.25.5__py3-none-any.whl → 4.0.0a1__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 +27 -65
- schemathesis/auths.py +102 -82
- schemathesis/checks.py +126 -46
- schemathesis/cli/__init__.py +11 -1766
- schemathesis/cli/__main__.py +4 -0
- schemathesis/cli/commands/__init__.py +37 -0
- schemathesis/cli/commands/run/__init__.py +662 -0
- schemathesis/cli/commands/run/checks.py +80 -0
- schemathesis/cli/commands/run/context.py +117 -0
- schemathesis/cli/commands/run/events.py +35 -0
- schemathesis/cli/commands/run/executor.py +138 -0
- schemathesis/cli/commands/run/filters.py +194 -0
- schemathesis/cli/commands/run/handlers/__init__.py +46 -0
- schemathesis/cli/commands/run/handlers/base.py +18 -0
- schemathesis/cli/commands/run/handlers/cassettes.py +494 -0
- schemathesis/cli/commands/run/handlers/junitxml.py +54 -0
- schemathesis/cli/commands/run/handlers/output.py +746 -0
- schemathesis/cli/commands/run/hypothesis.py +105 -0
- schemathesis/cli/commands/run/loaders.py +129 -0
- schemathesis/cli/{callbacks.py → commands/run/validation.py} +103 -174
- schemathesis/cli/constants.py +5 -52
- schemathesis/cli/core.py +17 -0
- schemathesis/cli/ext/fs.py +14 -0
- schemathesis/cli/ext/groups.py +55 -0
- schemathesis/cli/{options.py → ext/options.py} +39 -10
- schemathesis/cli/hooks.py +36 -0
- schemathesis/contrib/__init__.py +1 -3
- schemathesis/contrib/openapi/__init__.py +1 -3
- schemathesis/contrib/openapi/fill_missing_examples.py +3 -5
- schemathesis/core/__init__.py +58 -0
- schemathesis/core/compat.py +25 -0
- schemathesis/core/control.py +2 -0
- schemathesis/core/curl.py +58 -0
- schemathesis/core/deserialization.py +65 -0
- schemathesis/core/errors.py +370 -0
- schemathesis/core/failures.py +285 -0
- schemathesis/core/fs.py +19 -0
- schemathesis/{_lazy_import.py → core/lazy_import.py} +1 -0
- schemathesis/core/loaders.py +104 -0
- schemathesis/core/marks.py +66 -0
- schemathesis/{transports/content_types.py → core/media_types.py} +17 -13
- schemathesis/core/output/__init__.py +69 -0
- schemathesis/core/output/sanitization.py +197 -0
- schemathesis/core/rate_limit.py +60 -0
- schemathesis/core/registries.py +31 -0
- schemathesis/{internal → core}/result.py +1 -1
- schemathesis/core/transforms.py +113 -0
- schemathesis/core/transport.py +108 -0
- schemathesis/core/validation.py +38 -0
- schemathesis/core/version.py +7 -0
- schemathesis/engine/__init__.py +30 -0
- schemathesis/engine/config.py +59 -0
- schemathesis/engine/context.py +119 -0
- schemathesis/engine/control.py +36 -0
- schemathesis/engine/core.py +157 -0
- schemathesis/engine/errors.py +394 -0
- schemathesis/engine/events.py +337 -0
- schemathesis/engine/phases/__init__.py +66 -0
- schemathesis/{cli → engine/phases}/probes.py +63 -70
- schemathesis/engine/phases/stateful/__init__.py +65 -0
- schemathesis/engine/phases/stateful/_executor.py +326 -0
- schemathesis/engine/phases/stateful/context.py +85 -0
- schemathesis/engine/phases/unit/__init__.py +174 -0
- schemathesis/engine/phases/unit/_executor.py +321 -0
- schemathesis/engine/phases/unit/_pool.py +74 -0
- schemathesis/engine/recorder.py +241 -0
- schemathesis/errors.py +31 -0
- schemathesis/experimental/__init__.py +18 -14
- schemathesis/filters.py +103 -14
- schemathesis/generation/__init__.py +21 -37
- schemathesis/generation/case.py +190 -0
- schemathesis/generation/coverage.py +931 -0
- schemathesis/generation/hypothesis/__init__.py +30 -0
- schemathesis/generation/hypothesis/builder.py +585 -0
- schemathesis/generation/hypothesis/examples.py +50 -0
- schemathesis/generation/hypothesis/given.py +66 -0
- schemathesis/generation/hypothesis/reporting.py +14 -0
- schemathesis/generation/hypothesis/strategies.py +16 -0
- schemathesis/generation/meta.py +115 -0
- schemathesis/generation/modes.py +28 -0
- schemathesis/generation/overrides.py +96 -0
- schemathesis/generation/stateful/__init__.py +20 -0
- schemathesis/{stateful → generation/stateful}/state_machine.py +68 -81
- schemathesis/generation/targets.py +69 -0
- schemathesis/graphql/__init__.py +15 -0
- schemathesis/graphql/checks.py +115 -0
- schemathesis/graphql/loaders.py +131 -0
- schemathesis/hooks.py +99 -67
- schemathesis/openapi/__init__.py +13 -0
- schemathesis/openapi/checks.py +412 -0
- schemathesis/openapi/generation/__init__.py +0 -0
- schemathesis/openapi/generation/filters.py +63 -0
- schemathesis/openapi/loaders.py +178 -0
- schemathesis/pytest/__init__.py +5 -0
- schemathesis/pytest/control_flow.py +7 -0
- schemathesis/pytest/lazy.py +273 -0
- schemathesis/pytest/loaders.py +12 -0
- schemathesis/{extra/pytest_plugin.py → pytest/plugin.py} +106 -127
- schemathesis/python/__init__.py +0 -0
- schemathesis/python/asgi.py +12 -0
- schemathesis/python/wsgi.py +12 -0
- schemathesis/schemas.py +537 -261
- schemathesis/specs/graphql/__init__.py +0 -1
- schemathesis/specs/graphql/_cache.py +25 -0
- schemathesis/specs/graphql/nodes.py +1 -0
- schemathesis/specs/graphql/scalars.py +7 -5
- schemathesis/specs/graphql/schemas.py +215 -187
- schemathesis/specs/graphql/validation.py +11 -18
- schemathesis/specs/openapi/__init__.py +7 -1
- schemathesis/specs/openapi/_cache.py +122 -0
- schemathesis/specs/openapi/_hypothesis.py +146 -165
- schemathesis/specs/openapi/checks.py +565 -67
- schemathesis/specs/openapi/converter.py +33 -6
- schemathesis/specs/openapi/definitions.py +11 -18
- schemathesis/specs/openapi/examples.py +153 -39
- schemathesis/specs/openapi/expressions/__init__.py +37 -2
- schemathesis/specs/openapi/expressions/context.py +4 -6
- schemathesis/specs/openapi/expressions/extractors.py +23 -0
- schemathesis/specs/openapi/expressions/lexer.py +20 -18
- schemathesis/specs/openapi/expressions/nodes.py +38 -14
- schemathesis/specs/openapi/expressions/parser.py +26 -5
- schemathesis/specs/openapi/formats.py +45 -0
- schemathesis/specs/openapi/links.py +65 -165
- schemathesis/specs/openapi/media_types.py +32 -0
- schemathesis/specs/openapi/negative/__init__.py +7 -3
- schemathesis/specs/openapi/negative/mutations.py +24 -8
- schemathesis/specs/openapi/parameters.py +46 -30
- schemathesis/specs/openapi/patterns.py +137 -0
- schemathesis/specs/openapi/references.py +47 -57
- schemathesis/specs/openapi/schemas.py +483 -367
- schemathesis/specs/openapi/security.py +25 -7
- schemathesis/specs/openapi/serialization.py +11 -6
- schemathesis/specs/openapi/stateful/__init__.py +185 -73
- schemathesis/specs/openapi/utils.py +6 -1
- schemathesis/transport/__init__.py +104 -0
- schemathesis/transport/asgi.py +26 -0
- schemathesis/transport/prepare.py +99 -0
- schemathesis/transport/requests.py +221 -0
- schemathesis/{_xml.py → transport/serialization.py} +143 -28
- schemathesis/transport/wsgi.py +165 -0
- schemathesis-4.0.0a1.dist-info/METADATA +297 -0
- schemathesis-4.0.0a1.dist-info/RECORD +152 -0
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/WHEEL +1 -1
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/entry_points.txt +1 -1
- schemathesis/_compat.py +0 -74
- schemathesis/_dependency_versions.py +0 -17
- schemathesis/_hypothesis.py +0 -246
- schemathesis/_override.py +0 -49
- schemathesis/cli/cassettes.py +0 -375
- schemathesis/cli/context.py +0 -55
- schemathesis/cli/debug.py +0 -26
- schemathesis/cli/handlers.py +0 -16
- schemathesis/cli/junitxml.py +0 -43
- schemathesis/cli/output/__init__.py +0 -1
- schemathesis/cli/output/default.py +0 -765
- schemathesis/cli/output/short.py +0 -40
- schemathesis/cli/sanitization.py +0 -20
- schemathesis/code_samples.py +0 -149
- schemathesis/constants.py +0 -55
- schemathesis/contrib/openapi/formats/__init__.py +0 -9
- schemathesis/contrib/openapi/formats/uuid.py +0 -15
- schemathesis/contrib/unique_data.py +0 -41
- schemathesis/exceptions.py +0 -560
- schemathesis/extra/_aiohttp.py +0 -27
- schemathesis/extra/_flask.py +0 -10
- schemathesis/extra/_server.py +0 -17
- schemathesis/failures.py +0 -209
- schemathesis/fixups/__init__.py +0 -36
- schemathesis/fixups/fast_api.py +0 -41
- schemathesis/fixups/utf8_bom.py +0 -29
- schemathesis/graphql.py +0 -4
- schemathesis/internal/__init__.py +0 -7
- schemathesis/internal/copy.py +0 -13
- schemathesis/internal/datetime.py +0 -5
- schemathesis/internal/deprecation.py +0 -34
- schemathesis/internal/jsonschema.py +0 -35
- schemathesis/internal/transformation.py +0 -15
- schemathesis/internal/validation.py +0 -34
- schemathesis/lazy.py +0 -361
- schemathesis/loaders.py +0 -120
- schemathesis/models.py +0 -1231
- schemathesis/parameters.py +0 -86
- schemathesis/runner/__init__.py +0 -555
- schemathesis/runner/events.py +0 -309
- schemathesis/runner/impl/__init__.py +0 -3
- schemathesis/runner/impl/core.py +0 -986
- schemathesis/runner/impl/solo.py +0 -90
- schemathesis/runner/impl/threadpool.py +0 -400
- schemathesis/runner/serialization.py +0 -411
- schemathesis/sanitization.py +0 -248
- schemathesis/serializers.py +0 -315
- schemathesis/service/__init__.py +0 -18
- schemathesis/service/auth.py +0 -11
- schemathesis/service/ci.py +0 -201
- schemathesis/service/client.py +0 -100
- schemathesis/service/constants.py +0 -38
- schemathesis/service/events.py +0 -57
- schemathesis/service/hosts.py +0 -107
- schemathesis/service/metadata.py +0 -46
- schemathesis/service/models.py +0 -49
- schemathesis/service/report.py +0 -255
- schemathesis/service/serialization.py +0 -184
- schemathesis/service/usage.py +0 -65
- schemathesis/specs/graphql/loaders.py +0 -344
- schemathesis/specs/openapi/filters.py +0 -49
- schemathesis/specs/openapi/loaders.py +0 -667
- schemathesis/specs/openapi/stateful/links.py +0 -92
- schemathesis/specs/openapi/validation.py +0 -25
- schemathesis/stateful/__init__.py +0 -133
- schemathesis/targets.py +0 -45
- schemathesis/throttling.py +0 -41
- schemathesis/transports/__init__.py +0 -5
- schemathesis/transports/auth.py +0 -15
- schemathesis/transports/headers.py +0 -35
- schemathesis/transports/responses.py +0 -52
- schemathesis/types.py +0 -35
- schemathesis/utils.py +0 -169
- schemathesis-3.25.5.dist-info/METADATA +0 -356
- schemathesis-3.25.5.dist-info/RECORD +0 -134
- /schemathesis/{extra → cli/ext}/__init__.py +0 -0
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/licenses/LICENSE +0 -0
schemathesis/failures.py
DELETED
@@ -1,209 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
import textwrap
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from json import JSONDecodeError
|
5
|
-
from typing import Any, TYPE_CHECKING
|
6
|
-
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from graphql.error import GraphQLFormattedError
|
9
|
-
from jsonschema import ValidationError
|
10
|
-
|
11
|
-
|
12
|
-
class FailureContext:
|
13
|
-
"""Additional data specific to certain failure kind."""
|
14
|
-
|
15
|
-
# Short description of what happened
|
16
|
-
title: str
|
17
|
-
# A longer one
|
18
|
-
message: str
|
19
|
-
type: str
|
20
|
-
|
21
|
-
def unique_by_key(self, check_message: str | None) -> tuple[str, ...]:
|
22
|
-
"""A key to distinguish different failure contexts."""
|
23
|
-
return (check_message or self.message,)
|
24
|
-
|
25
|
-
|
26
|
-
@dataclass(repr=False)
|
27
|
-
class ValidationErrorContext(FailureContext):
|
28
|
-
"""Additional information about JSON Schema validation errors."""
|
29
|
-
|
30
|
-
validation_message: str
|
31
|
-
schema_path: list[str | int]
|
32
|
-
schema: dict[str, Any] | bool
|
33
|
-
instance_path: list[str | int]
|
34
|
-
instance: None | bool | float | str | list | dict[str, Any]
|
35
|
-
message: str
|
36
|
-
title: str = "Response violates schema"
|
37
|
-
type: str = "json_schema"
|
38
|
-
|
39
|
-
def unique_by_key(self, check_message: str | None) -> tuple[str, ...]:
|
40
|
-
# Deduplicate by JSON Schema path. All errors that happened on this sub-schema will be deduplicated
|
41
|
-
return ("/".join(map(str, self.schema_path)),)
|
42
|
-
|
43
|
-
@classmethod
|
44
|
-
def from_exception(cls, exc: ValidationError) -> ValidationErrorContext:
|
45
|
-
from .exceptions import truncated_json
|
46
|
-
|
47
|
-
schema = textwrap.indent(truncated_json(exc.schema, max_lines=20), prefix=" ")
|
48
|
-
value = textwrap.indent(truncated_json(exc.instance, max_lines=20), prefix=" ")
|
49
|
-
message = f"{exc.message}\n\nSchema:\n\n{schema}\n\nValue:\n\n{value}"
|
50
|
-
return cls(
|
51
|
-
message=message,
|
52
|
-
validation_message=exc.message,
|
53
|
-
schema_path=list(exc.absolute_schema_path),
|
54
|
-
schema=exc.schema,
|
55
|
-
instance_path=list(exc.absolute_path),
|
56
|
-
instance=exc.instance,
|
57
|
-
)
|
58
|
-
|
59
|
-
|
60
|
-
@dataclass(repr=False)
|
61
|
-
class JSONDecodeErrorContext(FailureContext):
|
62
|
-
"""Failed to decode JSON."""
|
63
|
-
|
64
|
-
validation_message: str
|
65
|
-
document: str
|
66
|
-
position: int
|
67
|
-
lineno: int
|
68
|
-
colno: int
|
69
|
-
message: str
|
70
|
-
title: str = "JSON deserialization error"
|
71
|
-
type: str = "json_decode"
|
72
|
-
|
73
|
-
def unique_by_key(self, check_message: str | None) -> tuple[str, ...]:
|
74
|
-
# Treat different JSON decoding failures as the same issue
|
75
|
-
# Payloads often contain dynamic data and distinguishing it by the error location still would not be sufficient
|
76
|
-
# as it may be different on different dynamic payloads
|
77
|
-
return (self.title,)
|
78
|
-
|
79
|
-
@classmethod
|
80
|
-
def from_exception(cls, exc: JSONDecodeError) -> JSONDecodeErrorContext:
|
81
|
-
return cls(
|
82
|
-
message=str(exc),
|
83
|
-
validation_message=exc.msg,
|
84
|
-
document=exc.doc,
|
85
|
-
position=exc.pos,
|
86
|
-
lineno=exc.lineno,
|
87
|
-
colno=exc.colno,
|
88
|
-
)
|
89
|
-
|
90
|
-
|
91
|
-
@dataclass(repr=False)
|
92
|
-
class ServerError(FailureContext):
|
93
|
-
status_code: int
|
94
|
-
title: str = "Server error"
|
95
|
-
message: str = ""
|
96
|
-
type: str = "server_error"
|
97
|
-
|
98
|
-
|
99
|
-
@dataclass(repr=False)
|
100
|
-
class MissingContentType(FailureContext):
|
101
|
-
"""Content type header is missing."""
|
102
|
-
|
103
|
-
media_types: list[str]
|
104
|
-
message: str
|
105
|
-
title: str = "Missing Content-Type header"
|
106
|
-
type: str = "missing_content_type"
|
107
|
-
|
108
|
-
|
109
|
-
@dataclass(repr=False)
|
110
|
-
class UndefinedContentType(FailureContext):
|
111
|
-
"""Response has Content-Type that is not documented in the schema."""
|
112
|
-
|
113
|
-
content_type: str
|
114
|
-
defined_content_types: list[str]
|
115
|
-
message: str
|
116
|
-
title: str = "Undocumented Content-Type"
|
117
|
-
type: str = "undefined_content_type"
|
118
|
-
|
119
|
-
|
120
|
-
@dataclass(repr=False)
|
121
|
-
class UndefinedStatusCode(FailureContext):
|
122
|
-
"""Response has a status code that is not defined in the schema."""
|
123
|
-
|
124
|
-
# Response's status code
|
125
|
-
status_code: int
|
126
|
-
# Status codes as defined in schema
|
127
|
-
defined_status_codes: list[str]
|
128
|
-
# Defined status code with expanded wildcards
|
129
|
-
allowed_status_codes: list[int]
|
130
|
-
message: str
|
131
|
-
title: str = "Undocumented HTTP status code"
|
132
|
-
type: str = "undefined_status_code"
|
133
|
-
|
134
|
-
|
135
|
-
@dataclass(repr=False)
|
136
|
-
class MissingHeaders(FailureContext):
|
137
|
-
"""Some required headers are missing."""
|
138
|
-
|
139
|
-
missing_headers: list[str]
|
140
|
-
message: str
|
141
|
-
title: str = "Missing required headers"
|
142
|
-
type: str = "missing_headers"
|
143
|
-
|
144
|
-
|
145
|
-
@dataclass(repr=False)
|
146
|
-
class MalformedMediaType(FailureContext):
|
147
|
-
"""Media type name is malformed.
|
148
|
-
|
149
|
-
Example: `application-json` instead of `application/json`
|
150
|
-
"""
|
151
|
-
|
152
|
-
actual: str
|
153
|
-
defined: str
|
154
|
-
message: str
|
155
|
-
title: str = "Malformed media type"
|
156
|
-
type: str = "malformed_media_type"
|
157
|
-
|
158
|
-
|
159
|
-
@dataclass(repr=False)
|
160
|
-
class ResponseTimeExceeded(FailureContext):
|
161
|
-
"""Response took longer than expected."""
|
162
|
-
|
163
|
-
elapsed: float
|
164
|
-
deadline: int
|
165
|
-
message: str
|
166
|
-
title: str = "Response time limit exceeded"
|
167
|
-
type: str = "response_time_exceeded"
|
168
|
-
|
169
|
-
def unique_by_key(self, check_message: str | None) -> tuple[str, ...]:
|
170
|
-
return (self.title,)
|
171
|
-
|
172
|
-
|
173
|
-
@dataclass(repr=False)
|
174
|
-
class RequestTimeout(FailureContext):
|
175
|
-
"""Request took longer than timeout."""
|
176
|
-
|
177
|
-
timeout: int
|
178
|
-
message: str
|
179
|
-
title: str = "Response timeout"
|
180
|
-
type: str = "request_timeout"
|
181
|
-
|
182
|
-
|
183
|
-
@dataclass(repr=False)
|
184
|
-
class UnexpectedGraphQLResponse(FailureContext):
|
185
|
-
"""GraphQL response is not a JSON object."""
|
186
|
-
|
187
|
-
message: str
|
188
|
-
title: str = "Unexpected GraphQL Response"
|
189
|
-
type: str = "graphql_unexpected_response"
|
190
|
-
|
191
|
-
|
192
|
-
@dataclass(repr=False)
|
193
|
-
class GraphQLClientError(FailureContext):
|
194
|
-
"""GraphQL query has not been executed."""
|
195
|
-
|
196
|
-
message: str
|
197
|
-
errors: list[GraphQLFormattedError]
|
198
|
-
title: str = "GraphQL client error"
|
199
|
-
type: str = "graphql_client_error"
|
200
|
-
|
201
|
-
|
202
|
-
@dataclass(repr=False)
|
203
|
-
class GraphQLServerError(FailureContext):
|
204
|
-
"""GraphQL response indicates at least one server error."""
|
205
|
-
|
206
|
-
message: str
|
207
|
-
errors: list[GraphQLFormattedError]
|
208
|
-
title: str = "GraphQL server error"
|
209
|
-
type: str = "graphql_server_error"
|
schemathesis/fixups/__init__.py
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from typing import Iterable
|
3
|
-
|
4
|
-
from . import fast_api, utf8_bom
|
5
|
-
|
6
|
-
ALL_FIXUPS = {"fast_api": fast_api, "utf8_bom": utf8_bom}
|
7
|
-
ALL_FIXUP_NAMES = list(ALL_FIXUPS.keys())
|
8
|
-
|
9
|
-
|
10
|
-
def install(fixups: Iterable[str] | None = None) -> None:
|
11
|
-
"""Install fixups.
|
12
|
-
|
13
|
-
Without the first argument installs all available fixups.
|
14
|
-
|
15
|
-
:param fixups: Names of fixups to install.
|
16
|
-
"""
|
17
|
-
fixups = fixups or ALL_FIXUP_NAMES
|
18
|
-
for name in fixups:
|
19
|
-
ALL_FIXUPS[name].install() # type: ignore
|
20
|
-
|
21
|
-
|
22
|
-
def uninstall(fixups: Iterable[str] | None = None) -> None:
|
23
|
-
"""Uninstall fixups.
|
24
|
-
|
25
|
-
Without the first argument uninstalls all available fixups.
|
26
|
-
|
27
|
-
:param fixups: Names of fixups to uninstall.
|
28
|
-
"""
|
29
|
-
fixups = fixups or ALL_FIXUP_NAMES
|
30
|
-
for name in fixups:
|
31
|
-
ALL_FIXUPS[name].uninstall() # type: ignore
|
32
|
-
|
33
|
-
|
34
|
-
def is_installed(name: str) -> bool:
|
35
|
-
"""Check whether fixup is installed."""
|
36
|
-
return ALL_FIXUPS[name].is_installed()
|
schemathesis/fixups/fast_api.py
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from typing import Any
|
3
|
-
|
4
|
-
from ..hooks import HookContext
|
5
|
-
from ..hooks import is_installed as global_is_installed
|
6
|
-
from ..hooks import register, unregister
|
7
|
-
from ..internal.jsonschema import traverse_schema
|
8
|
-
|
9
|
-
|
10
|
-
def install() -> None:
|
11
|
-
register(before_load_schema)
|
12
|
-
|
13
|
-
|
14
|
-
def uninstall() -> None:
|
15
|
-
unregister(before_load_schema)
|
16
|
-
|
17
|
-
|
18
|
-
def is_installed() -> bool:
|
19
|
-
return global_is_installed("before_load_schema", before_load_schema)
|
20
|
-
|
21
|
-
|
22
|
-
def before_load_schema(context: HookContext, schema: dict[str, Any]) -> None:
|
23
|
-
adjust_schema(schema)
|
24
|
-
|
25
|
-
|
26
|
-
def adjust_schema(schema: dict[str, Any]) -> None:
|
27
|
-
traverse_schema(schema, _handle_boundaries)
|
28
|
-
|
29
|
-
|
30
|
-
def _handle_boundaries(schema: dict[str, Any]) -> dict[str, Any]:
|
31
|
-
"""Convert Draft 7 keywords to Draft 4 compatible versions.
|
32
|
-
|
33
|
-
FastAPI uses ``pydantic``, which generates Draft 7 compatible schemas.
|
34
|
-
"""
|
35
|
-
for boundary_name, boundary_exclusive_name in (("maximum", "exclusiveMaximum"), ("minimum", "exclusiveMinimum")):
|
36
|
-
value = schema.get(boundary_exclusive_name)
|
37
|
-
# `bool` check is needed, since in Python `True` is an instance of `int`
|
38
|
-
if isinstance(value, (int, float)) and not isinstance(value, bool):
|
39
|
-
schema[boundary_exclusive_name] = True
|
40
|
-
schema[boundary_name] = value
|
41
|
-
return schema
|
schemathesis/fixups/utf8_bom.py
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
from typing import TYPE_CHECKING
|
2
|
-
|
3
|
-
from ..constants import BOM_MARK
|
4
|
-
from ..hooks import HookContext
|
5
|
-
from ..hooks import is_installed as global_is_installed
|
6
|
-
from ..hooks import register, unregister
|
7
|
-
|
8
|
-
if TYPE_CHECKING:
|
9
|
-
from ..models import Case
|
10
|
-
from ..transports.responses import GenericResponse
|
11
|
-
|
12
|
-
|
13
|
-
def install() -> None:
|
14
|
-
register(after_call)
|
15
|
-
|
16
|
-
|
17
|
-
def uninstall() -> None:
|
18
|
-
unregister(after_call)
|
19
|
-
|
20
|
-
|
21
|
-
def is_installed() -> bool:
|
22
|
-
return global_is_installed("after_call", after_call)
|
23
|
-
|
24
|
-
|
25
|
-
def after_call(context: HookContext, case: "Case", response: "GenericResponse") -> None:
|
26
|
-
from requests import Response
|
27
|
-
|
28
|
-
if isinstance(response, Response) and response.encoding == "utf-8" and response.text[0:1] == BOM_MARK:
|
29
|
-
response.encoding = "utf-8-sig"
|
schemathesis/graphql.py
DELETED
schemathesis/internal/copy.py
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
from typing import Any
|
2
|
-
|
3
|
-
|
4
|
-
def fast_deepcopy(value: Any) -> Any:
|
5
|
-
"""A specialized version of `deepcopy` that copies only `dict` and `list`.
|
6
|
-
|
7
|
-
It is on average 3x faster than `deepcopy` and given the amount of calls, it is an important optimization.
|
8
|
-
"""
|
9
|
-
if isinstance(value, dict):
|
10
|
-
return {key: fast_deepcopy(v) for key, v in value.items()}
|
11
|
-
if isinstance(value, list):
|
12
|
-
return [fast_deepcopy(v) for v in value]
|
13
|
-
return value
|
@@ -1,34 +0,0 @@
|
|
1
|
-
import warnings
|
2
|
-
from typing import Callable, Any
|
3
|
-
|
4
|
-
|
5
|
-
def _warn_deprecation(*, kind: str, thing: str, removed_in: str, replacement: str) -> None:
|
6
|
-
warnings.warn(
|
7
|
-
f"{kind} `{thing}` is deprecated and will be removed in Schemathesis {removed_in}. "
|
8
|
-
f"Use `{replacement}` instead.",
|
9
|
-
DeprecationWarning,
|
10
|
-
stacklevel=1,
|
11
|
-
)
|
12
|
-
|
13
|
-
|
14
|
-
def deprecated_property(*, removed_in: str, replacement: str) -> Callable:
|
15
|
-
def wrapper(prop: Callable) -> Callable:
|
16
|
-
@property # type: ignore
|
17
|
-
def inner(self: Any) -> Any:
|
18
|
-
_warn_deprecation(kind="Property", thing=prop.__name__, removed_in=removed_in, replacement=replacement)
|
19
|
-
return prop(self)
|
20
|
-
|
21
|
-
return inner
|
22
|
-
|
23
|
-
return wrapper
|
24
|
-
|
25
|
-
|
26
|
-
def deprecated_function(*, removed_in: str, replacement: str) -> Callable:
|
27
|
-
def wrapper(func: Callable) -> Callable:
|
28
|
-
def inner(*args: Any, **kwargs: Any) -> Any:
|
29
|
-
_warn_deprecation(kind="Function", thing=func.__name__, removed_in=removed_in, replacement=replacement)
|
30
|
-
return func(*args, **kwargs)
|
31
|
-
|
32
|
-
return inner
|
33
|
-
|
34
|
-
return wrapper
|
@@ -1,35 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from typing import overload, Dict, Union, Any, List, Callable
|
3
|
-
|
4
|
-
JsonValue = Union[Dict[str, Any], List, str, float, int]
|
5
|
-
|
6
|
-
|
7
|
-
@overload
|
8
|
-
def traverse_schema(schema: dict[str, Any], callback: Callable, *args: Any, **kwargs: Any) -> dict[str, Any]:
|
9
|
-
pass
|
10
|
-
|
11
|
-
|
12
|
-
@overload
|
13
|
-
def traverse_schema(schema: list, callback: Callable, *args: Any, **kwargs: Any) -> list:
|
14
|
-
pass
|
15
|
-
|
16
|
-
|
17
|
-
@overload
|
18
|
-
def traverse_schema(schema: str, callback: Callable, *args: Any, **kwargs: Any) -> str:
|
19
|
-
pass
|
20
|
-
|
21
|
-
|
22
|
-
@overload
|
23
|
-
def traverse_schema(schema: float, callback: Callable, *args: Any, **kwargs: Any) -> float:
|
24
|
-
pass
|
25
|
-
|
26
|
-
|
27
|
-
def traverse_schema(schema: JsonValue, callback: Callable[..., dict[str, Any]], *args: Any, **kwargs: Any) -> JsonValue:
|
28
|
-
"""Apply callback recursively to the given schema."""
|
29
|
-
if isinstance(schema, dict):
|
30
|
-
schema = callback(schema, *args, **kwargs)
|
31
|
-
for key, sub_item in schema.items():
|
32
|
-
schema[key] = traverse_schema(sub_item, callback, *args, **kwargs)
|
33
|
-
elif isinstance(schema, list):
|
34
|
-
schema = [traverse_schema(sub_item, callback, *args, **kwargs) for sub_item in schema]
|
35
|
-
return schema
|
@@ -1,15 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
from typing import Any
|
3
|
-
|
4
|
-
|
5
|
-
def merge_recursively(a: dict[str, Any], b: dict[str, Any]) -> dict[str, Any]:
|
6
|
-
"""Merge two dictionaries recursively."""
|
7
|
-
for key in b:
|
8
|
-
if key in a:
|
9
|
-
if isinstance(a[key], dict) and isinstance(b[key], dict):
|
10
|
-
merge_recursively(a[key], b[key])
|
11
|
-
else:
|
12
|
-
a[key] = b[key]
|
13
|
-
else:
|
14
|
-
a[key] = b[key]
|
15
|
-
return a
|
@@ -1,34 +0,0 @@
|
|
1
|
-
import pathlib
|
2
|
-
import re
|
3
|
-
from typing import Any
|
4
|
-
|
5
|
-
|
6
|
-
def require_relative_url(url: str) -> None:
|
7
|
-
"""Raise an error if the URL is not relative."""
|
8
|
-
from yarl import URL
|
9
|
-
|
10
|
-
if URL(url).is_absolute():
|
11
|
-
raise ValueError("Schema path should be relative for WSGI/ASGI loaders")
|
12
|
-
|
13
|
-
|
14
|
-
def file_exists(path: str) -> bool:
|
15
|
-
try:
|
16
|
-
return pathlib.Path(path).is_file()
|
17
|
-
except OSError:
|
18
|
-
# For example, path could be too long
|
19
|
-
return False
|
20
|
-
|
21
|
-
|
22
|
-
def is_filename(value: str) -> bool:
|
23
|
-
"""Detect if the input string is a filename by checking its extension."""
|
24
|
-
return bool(pathlib.Path(value).suffix)
|
25
|
-
|
26
|
-
|
27
|
-
SURROGATE_PAIR_RE = re.compile(r"[\ud800-\udfff]")
|
28
|
-
has_surrogate_pair = SURROGATE_PAIR_RE.search
|
29
|
-
|
30
|
-
|
31
|
-
def is_illegal_surrogate(item: Any) -> bool:
|
32
|
-
if isinstance(item, list):
|
33
|
-
return any(isinstance(item_, str) and bool(has_surrogate_pair(item_)) for item_ in item)
|
34
|
-
return isinstance(item, str) and bool(has_surrogate_pair(item))
|