schemathesis 4.2.2__py3-none-any.whl → 4.3.1__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/config/__init__.py +8 -1
- schemathesis/config/_phases.py +14 -3
- schemathesis/config/schema.json +2 -1
- schemathesis/core/jsonschema/bundler.py +3 -2
- schemathesis/core/transforms.py +14 -6
- schemathesis/engine/context.py +35 -2
- schemathesis/generation/hypothesis/__init__.py +3 -1
- schemathesis/generation/hypothesis/builder.py +10 -2
- schemathesis/openapi/checks.py +13 -1
- schemathesis/specs/openapi/adapter/parameters.py +3 -3
- schemathesis/specs/openapi/adapter/protocol.py +2 -0
- schemathesis/specs/openapi/adapter/responses.py +29 -7
- schemathesis/specs/openapi/adapter/v2.py +2 -0
- schemathesis/specs/openapi/adapter/v3_0.py +2 -0
- schemathesis/specs/openapi/adapter/v3_1.py +2 -0
- schemathesis/specs/openapi/stateful/dependencies/__init__.py +88 -0
- schemathesis/specs/openapi/stateful/dependencies/inputs.py +182 -0
- schemathesis/specs/openapi/stateful/dependencies/models.py +270 -0
- schemathesis/specs/openapi/stateful/dependencies/naming.py +345 -0
- schemathesis/specs/openapi/stateful/dependencies/outputs.py +34 -0
- schemathesis/specs/openapi/stateful/dependencies/resources.py +282 -0
- schemathesis/specs/openapi/stateful/dependencies/schemas.py +420 -0
- schemathesis/specs/openapi/stateful/inference.py +2 -1
- {schemathesis-4.2.2.dist-info → schemathesis-4.3.1.dist-info}/METADATA +1 -1
- {schemathesis-4.2.2.dist-info → schemathesis-4.3.1.dist-info}/RECORD +28 -21
- {schemathesis-4.2.2.dist-info → schemathesis-4.3.1.dist-info}/WHEEL +0 -0
- {schemathesis-4.2.2.dist-info → schemathesis-4.3.1.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.2.2.dist-info → schemathesis-4.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,420 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Mapping
|
5
|
+
|
6
|
+
from hypothesis_jsonschema._canonicalise import (
|
7
|
+
SCHEMA_KEYS as SCHEMA_KEYS_TUPLE,
|
8
|
+
)
|
9
|
+
from hypothesis_jsonschema._canonicalise import (
|
10
|
+
SCHEMA_OBJECT_KEYS as SCHEMA_OBJECT_KEYS_TUPLE,
|
11
|
+
)
|
12
|
+
from hypothesis_jsonschema._canonicalise import canonicalish, merged
|
13
|
+
|
14
|
+
from schemathesis.core.jsonschema import ALL_KEYWORDS
|
15
|
+
from schemathesis.core.jsonschema.bundler import BUNDLE_STORAGE_KEY, bundle
|
16
|
+
from schemathesis.core.jsonschema.types import JsonSchema, JsonSchemaObject
|
17
|
+
from schemathesis.core.transforms import encode_pointer
|
18
|
+
from schemathesis.specs.openapi.adapter.parameters import resource_name_from_ref
|
19
|
+
from schemathesis.specs.openapi.adapter.references import maybe_resolve
|
20
|
+
from schemathesis.specs.openapi.stateful.dependencies import naming
|
21
|
+
|
22
|
+
if TYPE_CHECKING:
|
23
|
+
from schemathesis.core.compat import RefResolver
|
24
|
+
|
25
|
+
ROOT_POINTER = "/"
|
26
|
+
SCHEMA_KEYS = frozenset(SCHEMA_KEYS_TUPLE)
|
27
|
+
SCHEMA_OBJECT_KEYS = frozenset(SCHEMA_OBJECT_KEYS_TUPLE)
|
28
|
+
|
29
|
+
|
30
|
+
def resolve_all_refs(schema: JsonSchemaObject) -> dict[str, Any]:
|
31
|
+
if not schema:
|
32
|
+
return schema
|
33
|
+
bundled = schema.get(BUNDLE_STORAGE_KEY, {})
|
34
|
+
|
35
|
+
resolved_cache: dict[str, dict[str, Any]] = {}
|
36
|
+
|
37
|
+
def resolve(ref: str) -> dict[str, Any]:
|
38
|
+
# All references here are bundled, therefore it is safe to avoid full reference resolving
|
39
|
+
if ref in resolved_cache:
|
40
|
+
return resolved_cache[ref]
|
41
|
+
key = ref.split("/")[-1]
|
42
|
+
# No clone needed, as it will be cloned inside `merged`
|
43
|
+
result = resolve_all_refs_inner(bundled[key], resolve=resolve)
|
44
|
+
resolved_cache[ref] = result
|
45
|
+
return result
|
46
|
+
|
47
|
+
return resolve_all_refs_inner(schema, resolve=resolve)
|
48
|
+
|
49
|
+
|
50
|
+
def resolve_all_refs_inner(schema: JsonSchema, *, resolve: Callable[[str], dict[str, Any]]) -> dict[str, Any]:
|
51
|
+
if schema is True:
|
52
|
+
return {}
|
53
|
+
if schema is False:
|
54
|
+
return {"not": {}}
|
55
|
+
if not schema:
|
56
|
+
return schema
|
57
|
+
|
58
|
+
reference = schema.get("$ref")
|
59
|
+
if reference is not None:
|
60
|
+
resolved = resolve(reference)
|
61
|
+
if len(schema) == 1 or (len(schema) == 2 and BUNDLE_STORAGE_KEY in schema):
|
62
|
+
return resolved
|
63
|
+
del schema["$ref"]
|
64
|
+
schema.pop(BUNDLE_STORAGE_KEY, None)
|
65
|
+
schema.pop("example", None)
|
66
|
+
return merged([resolve_all_refs_inner(schema, resolve=resolve), resolved]) # type: ignore
|
67
|
+
|
68
|
+
for key, value in schema.items():
|
69
|
+
if key in SCHEMA_KEYS:
|
70
|
+
if isinstance(value, list):
|
71
|
+
schema[key] = [resolve_all_refs_inner(v, resolve=resolve) if isinstance(v, dict) else v for v in value]
|
72
|
+
elif isinstance(value, dict):
|
73
|
+
schema[key] = resolve_all_refs_inner(value, resolve=resolve)
|
74
|
+
if key in SCHEMA_OBJECT_KEYS:
|
75
|
+
schema[key] = {
|
76
|
+
k: resolve_all_refs_inner(v, resolve=resolve) if isinstance(v, dict) else v for k, v in value.items()
|
77
|
+
}
|
78
|
+
return schema
|
79
|
+
|
80
|
+
|
81
|
+
def canonicalize(schema: dict[str, Any], resolver: RefResolver) -> Mapping[str, Any]:
|
82
|
+
"""Transform the input schema into its canonical-ish form."""
|
83
|
+
# Canonicalisation in `hypothesis_jsonschema` requires all references to be resovable and non-recursive
|
84
|
+
# On the Schemathesis side bundling solves this problem
|
85
|
+
bundled = bundle(schema, resolver, inline_recursive=True)
|
86
|
+
canonicalized = canonicalish(bundled)
|
87
|
+
resolved = resolve_all_refs(canonicalized)
|
88
|
+
resolved.pop(BUNDLE_STORAGE_KEY, None)
|
89
|
+
if "allOf" in resolved or "anyOf" in resolved or "oneOf" in resolved:
|
90
|
+
return canonicalish(resolved)
|
91
|
+
return resolved
|
92
|
+
|
93
|
+
|
94
|
+
def try_unwrap_composition(schema: Mapping[str, Any], resolver: RefResolver) -> Mapping[str, Any]:
|
95
|
+
"""Unwrap oneOf/anyOf if we can safely extract a single schema."""
|
96
|
+
keys = ("anyOf", "oneOf")
|
97
|
+
composition_key = None
|
98
|
+
for key in keys:
|
99
|
+
if key in schema:
|
100
|
+
composition_key = key
|
101
|
+
break
|
102
|
+
|
103
|
+
if composition_key is None:
|
104
|
+
return schema
|
105
|
+
|
106
|
+
alternatives = schema[composition_key]
|
107
|
+
|
108
|
+
if not isinstance(alternatives, list):
|
109
|
+
return schema
|
110
|
+
|
111
|
+
# Filter to interesting alternatives
|
112
|
+
interesting = _filter_composition_alternatives(alternatives, resolver)
|
113
|
+
|
114
|
+
# If no interesting alternatives, return original
|
115
|
+
if not interesting:
|
116
|
+
return schema
|
117
|
+
|
118
|
+
# If exactly one interesting alternative, unwrap it
|
119
|
+
if len(interesting) == 1:
|
120
|
+
return interesting[0]
|
121
|
+
|
122
|
+
# Pick the first one
|
123
|
+
# TODO: Support multiple alternatives
|
124
|
+
return interesting[0]
|
125
|
+
|
126
|
+
|
127
|
+
def try_unwrap_all_of(schema: Mapping[str, Any]) -> Mapping[str, Any]:
|
128
|
+
alternatives = schema.get("allOf")
|
129
|
+
if not isinstance(alternatives, list):
|
130
|
+
return schema
|
131
|
+
|
132
|
+
interesting = []
|
133
|
+
|
134
|
+
for subschema in alternatives:
|
135
|
+
if isinstance(subschema, dict) and _is_interesting_schema(subschema):
|
136
|
+
interesting.append(subschema)
|
137
|
+
|
138
|
+
if len(interesting) == 1:
|
139
|
+
return interesting[0]
|
140
|
+
return schema
|
141
|
+
|
142
|
+
|
143
|
+
def _filter_composition_alternatives(alternatives: list[dict], resolver: RefResolver) -> list[dict]:
|
144
|
+
"""Filter oneOf/anyOf alternatives to keep only interesting schemas."""
|
145
|
+
interesting = []
|
146
|
+
|
147
|
+
for alt_schema in alternatives:
|
148
|
+
_, resolved = maybe_resolve(alt_schema, resolver, "")
|
149
|
+
|
150
|
+
if _is_interesting_schema(resolved):
|
151
|
+
# Keep original (with $ref)
|
152
|
+
interesting.append(alt_schema)
|
153
|
+
|
154
|
+
return interesting
|
155
|
+
|
156
|
+
|
157
|
+
def _is_interesting_schema(schema: Mapping[str, Any]) -> bool:
|
158
|
+
"""Check if a schema represents interesting structured data."""
|
159
|
+
# Has $ref - definitely interesting (references a named schema)
|
160
|
+
if "$ref" in schema:
|
161
|
+
return True
|
162
|
+
|
163
|
+
ty = schema.get("type")
|
164
|
+
|
165
|
+
# Primitives are not interesting
|
166
|
+
if ty in {"string", "number", "integer", "boolean", "null"}:
|
167
|
+
return False
|
168
|
+
|
169
|
+
# Arrays - check items
|
170
|
+
if ty == "array":
|
171
|
+
items = schema.get("items")
|
172
|
+
if not isinstance(items, dict):
|
173
|
+
return False
|
174
|
+
# Recursively check if items are interesting
|
175
|
+
return _is_interesting_schema(items)
|
176
|
+
|
177
|
+
# allOf/anyOf/oneOf - interesting (composition)
|
178
|
+
if any(key in schema for key in ["allOf", "anyOf", "oneOf"]):
|
179
|
+
return True
|
180
|
+
|
181
|
+
# Objects (or untyped) - check if they have any keywords
|
182
|
+
return bool(set(schema).intersection(ALL_KEYWORDS))
|
183
|
+
|
184
|
+
|
185
|
+
@dataclass
|
186
|
+
class UnwrappedSchema:
|
187
|
+
"""Result of wrapper pattern detection."""
|
188
|
+
|
189
|
+
pointer: str
|
190
|
+
schema: Mapping[str, Any]
|
191
|
+
ref: str | None
|
192
|
+
|
193
|
+
__slots__ = ("pointer", "schema", "ref")
|
194
|
+
|
195
|
+
|
196
|
+
def unwrap_schema(
|
197
|
+
schema: Mapping[str, Any], path: str, parent_ref: str | None, resolver: RefResolver
|
198
|
+
) -> UnwrappedSchema:
|
199
|
+
# Array at root
|
200
|
+
if schema.get("type") == "array":
|
201
|
+
return UnwrappedSchema(pointer="/", schema=schema, ref=None)
|
202
|
+
|
203
|
+
properties = schema.get("properties", {})
|
204
|
+
|
205
|
+
# HAL _embedded (Spring-specific)
|
206
|
+
hal_field = _detect_hal_embedded(schema)
|
207
|
+
if hal_field:
|
208
|
+
embedded_schema = properties["_embedded"]
|
209
|
+
_, resolved_embedded = maybe_resolve(embedded_schema, resolver, "")
|
210
|
+
resource_schema = resolved_embedded.get("properties", {}).get(hal_field, {})
|
211
|
+
_, resolved_resource = maybe_resolve(resource_schema, resolver, "")
|
212
|
+
|
213
|
+
return UnwrappedSchema(
|
214
|
+
pointer=f"/_embedded/{encode_pointer(hal_field)}", schema=resolved_resource, ref=resource_schema.get("$ref")
|
215
|
+
)
|
216
|
+
|
217
|
+
# Pagination wrapper
|
218
|
+
array_field = _is_pagination_wrapper(schema=schema, path=path, parent_ref=parent_ref, resolver=resolver)
|
219
|
+
if array_field:
|
220
|
+
array_schema = properties[array_field]
|
221
|
+
_, resolved = maybe_resolve(array_schema, resolver, "")
|
222
|
+
pointer = f"/{encode_pointer(array_field)}"
|
223
|
+
|
224
|
+
# Try to unwrap one more time
|
225
|
+
if resolved.get("type") == "array" or "items" in resolved:
|
226
|
+
nested_items = resolved.get("items")
|
227
|
+
if isinstance(nested_items, dict):
|
228
|
+
_, resolved_items = maybe_resolve(nested_items, resolver, "")
|
229
|
+
external_tag = _detect_externally_tagged_pattern(resolved_items, path)
|
230
|
+
if external_tag:
|
231
|
+
nested_properties = resolved_items["properties"][external_tag]
|
232
|
+
_, resolved = maybe_resolve(nested_properties, resolver, "")
|
233
|
+
pointer += f"/{encode_pointer(external_tag)}"
|
234
|
+
|
235
|
+
return UnwrappedSchema(pointer=pointer, schema=resolved, ref=array_schema.get("$ref"))
|
236
|
+
|
237
|
+
# External tag
|
238
|
+
external_tag = _detect_externally_tagged_pattern(schema, path)
|
239
|
+
if external_tag:
|
240
|
+
tagged_schema = properties[external_tag]
|
241
|
+
_, resolved_tagged = maybe_resolve(tagged_schema, resolver, "")
|
242
|
+
|
243
|
+
resolved = try_unwrap_all_of(resolved_tagged)
|
244
|
+
ref = resolved.get("$ref") or resolved_tagged.get("$ref") or tagged_schema.get("$ref")
|
245
|
+
|
246
|
+
_, resolved = maybe_resolve(resolved, resolver, "")
|
247
|
+
return UnwrappedSchema(pointer=f"/{encode_pointer(external_tag)}", schema=resolved, ref=ref)
|
248
|
+
|
249
|
+
# No wrapper - single object at root
|
250
|
+
return UnwrappedSchema(pointer="/", schema=schema, ref=schema.get("$ref"))
|
251
|
+
|
252
|
+
|
253
|
+
def _detect_hal_embedded(schema: Mapping[str, Any]) -> str | None:
|
254
|
+
"""Detect HAL _embedded pattern.
|
255
|
+
|
256
|
+
Spring Data REST uses: {_embedded: {users: [...]}}
|
257
|
+
"""
|
258
|
+
properties = schema.get("properties", {})
|
259
|
+
embedded = properties.get("_embedded")
|
260
|
+
|
261
|
+
if not isinstance(embedded, dict):
|
262
|
+
return None
|
263
|
+
|
264
|
+
embedded_properties = embedded.get("properties", {})
|
265
|
+
|
266
|
+
# Find array properties in _embedded
|
267
|
+
for name, subschema in embedded_properties.items():
|
268
|
+
if isinstance(subschema, dict) and subschema.get("type") == "array":
|
269
|
+
# Found array in _embedded
|
270
|
+
return name
|
271
|
+
|
272
|
+
return None
|
273
|
+
|
274
|
+
|
275
|
+
def _is_pagination_wrapper(
|
276
|
+
schema: Mapping[str, Any], path: str, parent_ref: str | None, resolver: RefResolver
|
277
|
+
) -> str | None:
|
278
|
+
"""Detect if schema is a pagination wrapper."""
|
279
|
+
properties = schema.get("properties", {})
|
280
|
+
|
281
|
+
if not properties:
|
282
|
+
return None
|
283
|
+
|
284
|
+
metadata_fields = frozenset(["links", "errors"])
|
285
|
+
|
286
|
+
# Find array properties
|
287
|
+
arrays = []
|
288
|
+
for name, subschema in properties.items():
|
289
|
+
if name in metadata_fields:
|
290
|
+
continue
|
291
|
+
if isinstance(subschema, dict):
|
292
|
+
_, subschema = maybe_resolve(subschema, resolver, "")
|
293
|
+
if subschema.get("type") == "array":
|
294
|
+
arrays.append(name)
|
295
|
+
|
296
|
+
# Must have exactly one array property
|
297
|
+
if len(arrays) != 1:
|
298
|
+
return None
|
299
|
+
|
300
|
+
array_field = arrays[0]
|
301
|
+
|
302
|
+
# Check if array field name matches common patterns
|
303
|
+
common_data_fields = {"data", "items", "results", "value", "content", "elements", "records", "list"}
|
304
|
+
|
305
|
+
if parent_ref:
|
306
|
+
resource_name = resource_name_from_ref(parent_ref)
|
307
|
+
resource_name = naming.strip_affixes(resource_name, ["get", "create", "list", "delete"], ["response"])
|
308
|
+
common_data_fields.add(resource_name.lower())
|
309
|
+
|
310
|
+
if array_field.lower() not in common_data_fields:
|
311
|
+
# Check if field name matches resource-specific pattern
|
312
|
+
# Example: path="/items/runner-groups" -> resource="RunnerGroup" -> "runner_groups"
|
313
|
+
resource_name_from_path = naming.from_path(path)
|
314
|
+
if resource_name_from_path is None:
|
315
|
+
return None
|
316
|
+
|
317
|
+
candidate = naming.to_plural(naming.to_snake_case(resource_name_from_path))
|
318
|
+
if array_field.lower() != candidate:
|
319
|
+
# Field name doesn't match resource pattern
|
320
|
+
return None
|
321
|
+
|
322
|
+
# Check for pagination metadata indicators
|
323
|
+
others = [p for p in properties if p != array_field]
|
324
|
+
|
325
|
+
pagination_indicators = {
|
326
|
+
"count",
|
327
|
+
"total",
|
328
|
+
"totalcount",
|
329
|
+
"total_count",
|
330
|
+
"totalelements",
|
331
|
+
"total_elements",
|
332
|
+
"page",
|
333
|
+
"pagenumber",
|
334
|
+
"page_number",
|
335
|
+
"currentpage",
|
336
|
+
"current_page",
|
337
|
+
"next",
|
338
|
+
"previous",
|
339
|
+
"prev",
|
340
|
+
"nextpage",
|
341
|
+
"prevpage",
|
342
|
+
"nextpageurl",
|
343
|
+
"prevpageurl",
|
344
|
+
"next_page_url",
|
345
|
+
"prev_page_url",
|
346
|
+
"next_page_token",
|
347
|
+
"nextpagetoken",
|
348
|
+
"cursor",
|
349
|
+
"nextcursor",
|
350
|
+
"next_cursor",
|
351
|
+
"nextlink",
|
352
|
+
"next_link",
|
353
|
+
"endcursor",
|
354
|
+
"hasmore",
|
355
|
+
"has_more",
|
356
|
+
"hasnextpage",
|
357
|
+
"haspreviouspage",
|
358
|
+
"pagesize",
|
359
|
+
"page_size",
|
360
|
+
"perpage",
|
361
|
+
"per_page",
|
362
|
+
"limit",
|
363
|
+
"size",
|
364
|
+
"pageinfo",
|
365
|
+
"page_info",
|
366
|
+
"pagination",
|
367
|
+
"links",
|
368
|
+
"meta",
|
369
|
+
}
|
370
|
+
|
371
|
+
# Check if any other property looks like pagination metadata
|
372
|
+
has_pagination_metadata = any(
|
373
|
+
prop.lower().replace("_", "").replace("-", "") in pagination_indicators for prop in others
|
374
|
+
)
|
375
|
+
|
376
|
+
# Either there is pagination metadata or the wrapper has just items + some other field which is likely an unrecognized metadata
|
377
|
+
if has_pagination_metadata or len(properties) <= 2:
|
378
|
+
return array_field
|
379
|
+
|
380
|
+
return None
|
381
|
+
|
382
|
+
|
383
|
+
def _detect_externally_tagged_pattern(schema: Mapping[str, Any], path: str) -> str | None:
|
384
|
+
"""Detect externally tagged resource pattern.
|
385
|
+
|
386
|
+
Pattern: {ResourceName: [...]} or {resourceName: [...]}
|
387
|
+
|
388
|
+
Examples:
|
389
|
+
- GET /merchants -> {"Merchants": [...]}
|
390
|
+
- GET /users -> {"Users": [...]} or {"users": [...]}
|
391
|
+
|
392
|
+
"""
|
393
|
+
properties = schema.get("properties", {})
|
394
|
+
|
395
|
+
if not properties:
|
396
|
+
return None
|
397
|
+
|
398
|
+
resource_name = naming.from_path(path)
|
399
|
+
|
400
|
+
if not resource_name:
|
401
|
+
return None
|
402
|
+
|
403
|
+
# For example, for `DataRequest`:
|
404
|
+
possible_names = {
|
405
|
+
# `datarequest`
|
406
|
+
resource_name.lower(),
|
407
|
+
# `datarequests`
|
408
|
+
naming.to_plural(resource_name.lower()),
|
409
|
+
# `data_request`
|
410
|
+
naming.to_snake_case(resource_name),
|
411
|
+
}
|
412
|
+
|
413
|
+
for name, subschema in properties.items():
|
414
|
+
if name.lower() not in possible_names:
|
415
|
+
continue
|
416
|
+
|
417
|
+
if isinstance(subschema, dict):
|
418
|
+
return name
|
419
|
+
|
420
|
+
return None
|
@@ -21,6 +21,7 @@ from werkzeug.exceptions import MethodNotAllowed, NotFound
|
|
21
21
|
from werkzeug.routing import Map, MapAdapter, Rule
|
22
22
|
|
23
23
|
from schemathesis.core.adapter import ResponsesContainer
|
24
|
+
from schemathesis.core.transforms import encode_pointer
|
24
25
|
|
25
26
|
if TYPE_CHECKING:
|
26
27
|
from schemathesis.engine.observations import LocationHeaderEntry
|
@@ -95,7 +96,7 @@ class LinkInferencer:
|
|
95
96
|
if operation_id:
|
96
97
|
operation = OperationById(operation_id, method=method, path=path)
|
97
98
|
else:
|
98
|
-
encoded_path = path
|
99
|
+
encoded_path = encode_pointer(path)
|
99
100
|
operation = OperationByRef(f"#/paths/{encoded_path}/{method}", method=method, path=path)
|
100
101
|
|
101
102
|
operations.append(operation)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: schemathesis
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.3.1
|
4
4
|
Summary: Property-based testing framework for Open API and GraphQL based apps
|
5
5
|
Project-URL: Documentation, https://schemathesis.readthedocs.io/en/stable/
|
6
6
|
Project-URL: Changelog, https://github.com/schemathesis/schemathesis/blob/master/CHANGELOG.md
|
@@ -28,7 +28,7 @@ schemathesis/cli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
|
|
28
28
|
schemathesis/cli/ext/fs.py,sha256=dHQYBjQozQmuSSfXVp-2KWFK0ESOb_w-lV2SptfMfco,461
|
29
29
|
schemathesis/cli/ext/groups.py,sha256=kQ37t6qeArcKaY2y5VxyK3_KwAkBKCVm58IYV8gewds,2720
|
30
30
|
schemathesis/cli/ext/options.py,sha256=6yYwZNJL__FCEEL7kI3r5MbVmbp3ZeQjm7DrZ6J_h7s,3347
|
31
|
-
schemathesis/config/__init__.py,sha256=
|
31
|
+
schemathesis/config/__init__.py,sha256=fXE_NxvAxhyGag0_gC3xJwUrUkxZz4OKANQ1nYuGFQk,6311
|
32
32
|
schemathesis/config/_auth.py,sha256=83RLVPm97W2thbn-yi01Rt94YwOxLG_a5VoxhEfjUjs,1528
|
33
33
|
schemathesis/config/_checks.py,sha256=F0r16eSSiICvoiTUkNNOE2PH73EGd8bikoeZdME_3Yw,10763
|
34
34
|
schemathesis/config/_diff_base.py,sha256=U7wuE4480EjP3K16mfC528TP5q7Q5IwAZwZLqRIrS1E,4300
|
@@ -39,13 +39,13 @@ schemathesis/config/_health_check.py,sha256=zC9inla5ibMBlEy5WyM4_TME7ju_KH3Bwfo2
|
|
39
39
|
schemathesis/config/_operations.py,sha256=JvfMkieYBkbEmZRb4cTvQLfvHQLhmsxa3GXzgjOtmFc,12383
|
40
40
|
schemathesis/config/_output.py,sha256=3G9SOi-4oNcQPHeNRG3HggFCwvcKOW1kF28a9m0H-pU,4434
|
41
41
|
schemathesis/config/_parameters.py,sha256=i76Hwaf834fBAMmtKfKTl1SFCicJ-Y-5tZt5QNGW2fA,618
|
42
|
-
schemathesis/config/_phases.py,sha256=
|
42
|
+
schemathesis/config/_phases.py,sha256=0D6eTo_jOVOyMevlpYAo-hcdgi4ocPpibsDpleMzSJ8,8741
|
43
43
|
schemathesis/config/_projects.py,sha256=MpXFBIkNAWAzE_NWQISI9R8dlbCVId2eXGdIqZBgK98,20468
|
44
44
|
schemathesis/config/_rate_limit.py,sha256=ekEW-jP_Ichk_O6hYpj-h2TTTKfp7Fm0nyFUbvlWcbA,456
|
45
45
|
schemathesis/config/_report.py,sha256=ZECDpaCY4WWHD5UbjvgZoSjLz-rlTvfd5Ivzdgzqf2I,3891
|
46
46
|
schemathesis/config/_validator.py,sha256=IcE8geFZ0ZwR18rkIRs25i7pTl7Z84XbjYGUB-mqReU,258
|
47
47
|
schemathesis/config/_warnings.py,sha256=sI0VZcTj3dOnphhBwYwU_KTagxr89HGWTtQ99HcY84k,772
|
48
|
-
schemathesis/config/schema.json,sha256=
|
48
|
+
schemathesis/config/schema.json,sha256=MWWV2W9ozqBBGtzrtTiYQkdyCdTFSx_fDlYLKrXRs0Q,19887
|
49
49
|
schemathesis/core/__init__.py,sha256=h4gmDePIPvPiVuYxnjrpPKytSZPi6fZeVdTG6c822E4,1973
|
50
50
|
schemathesis/core/adapter.py,sha256=zwJ0vNhalrF9sYXN8_0pMSkJ71GPDnUBKqBCVsnuVIY,951
|
51
51
|
schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1058
|
@@ -64,19 +64,19 @@ schemathesis/core/parameters.py,sha256=20pd4DLW1uXs61YuESKG1Fx9QJJQN3JY7CKnOJMgD
|
|
64
64
|
schemathesis/core/rate_limit.py,sha256=7tg9Znk11erTfw8-ANutjEmu7hbfUHZx_iEdkoaP174,1757
|
65
65
|
schemathesis/core/registries.py,sha256=T4jZB4y3zBHdeSgQc0pRbgSeMblvO-6z4I3zmzIfTi0,811
|
66
66
|
schemathesis/core/result.py,sha256=d449YvyONjqjDs-A5DAPgtAI96iT753K8sU6_1HLo2Q,461
|
67
|
-
schemathesis/core/transforms.py,sha256=
|
67
|
+
schemathesis/core/transforms.py,sha256=n_inn8Vb-CFiDUd9Z8E7JIp2kn2eAnxO8DD3OSwOTiM,4310
|
68
68
|
schemathesis/core/transport.py,sha256=LQcamAkFqJ0HuXQzepevAq2MCJW-uq5Nm-HE9yc7HMI,7503
|
69
69
|
schemathesis/core/validation.py,sha256=b0USkKzkWvdz3jOW1JXYc_TfYshfKZeP7xAUnMqcNoc,2303
|
70
70
|
schemathesis/core/version.py,sha256=dOBUWrY3-uA2NQXJp9z7EtZgkR6jYeLg8sMhQCL1mcI,205
|
71
71
|
schemathesis/core/jsonschema/__init__.py,sha256=gBZGsXIpK2EFfcp8x0b69dqzWAm2OeZHepKImkkLvoE,320
|
72
|
-
schemathesis/core/jsonschema/bundler.py,sha256=
|
72
|
+
schemathesis/core/jsonschema/bundler.py,sha256=7Cc-1ccBNEdyMMypPyqTEbwcXmnkkjFPDxTZidgzIpU,7804
|
73
73
|
schemathesis/core/jsonschema/keywords.py,sha256=pjseXTfH9OItNs_Qq6ubkhNWQOrxTnwHmrP_jxrHeJU,631
|
74
74
|
schemathesis/core/jsonschema/references.py,sha256=c2Q4IKWUbwENNtkbFaqf8r3LLZu6GFE5YLnYQlg5tPg,6069
|
75
75
|
schemathesis/core/jsonschema/types.py,sha256=C7f9g8yKFuoxC5_0YNIh8QAyGU0-tj8pzTMfMDjjjVM,1248
|
76
76
|
schemathesis/core/output/__init__.py,sha256=SiHqONFskXl73AtP5dV29L14nZoKo7B-IeG52KZB32M,1446
|
77
77
|
schemathesis/core/output/sanitization.py,sha256=Ev3tae8dVwsYd7yVb2_1VBFYs92WFsQ4Eu1fGaymItE,2013
|
78
78
|
schemathesis/engine/__init__.py,sha256=QaFE-FinaTAaarteADo2RRMJ-Sz6hZB9TzD5KjMinIA,706
|
79
|
-
schemathesis/engine/context.py,sha256=
|
79
|
+
schemathesis/engine/context.py,sha256=iMyyum60AmZlX1reghxzCW6A_dDA43RA3NXJZqruHv8,6821
|
80
80
|
schemathesis/engine/control.py,sha256=FXzP8dxL47j1Giqpy2-Bsr_MdMw9YiATSK_UfpFwDtk,1348
|
81
81
|
schemathesis/engine/core.py,sha256=qlPHnZVq2RrUe93fOciXd1hC3E1gVyF2BIWMPMeLIj8,6655
|
82
82
|
schemathesis/engine/errors.py,sha256=FlpEk44WRLzRkdK9m37z93EQuY3kbeMIQRGwU5e3Qm4,19005
|
@@ -98,8 +98,8 @@ schemathesis/generation/meta.py,sha256=tXhUZBEdpQMn68uMx1SW8Vv59Uf6Wl6yzs-VB9lu_
|
|
98
98
|
schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
|
99
99
|
schemathesis/generation/modes.py,sha256=Q1fhjWr3zxabU5qdtLvKfpMFZJAwlW9pnxgenjeXTyU,481
|
100
100
|
schemathesis/generation/overrides.py,sha256=xI2djHsa42fzP32xpxgxO52INixKagf5DjDAWJYswM8,3890
|
101
|
-
schemathesis/generation/hypothesis/__init__.py,sha256=
|
102
|
-
schemathesis/generation/hypothesis/builder.py,sha256=
|
101
|
+
schemathesis/generation/hypothesis/__init__.py,sha256=68BHULoXQC1WjFfw03ga5lvDGZ-c-J7H_fNEuUzFWRw,4976
|
102
|
+
schemathesis/generation/hypothesis/builder.py,sha256=tnDN_0MNT48mAO421JmcI3E0U2zeeTX-mjF3KXmpc7A,38629
|
103
103
|
schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
|
104
104
|
schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
|
105
105
|
schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
|
@@ -110,7 +110,7 @@ schemathesis/graphql/__init__.py,sha256=_eO6MAPHGgiADVGRntnwtPxmuvk666sAh-FAU4cG
|
|
110
110
|
schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzYo,3186
|
111
111
|
schemathesis/graphql/loaders.py,sha256=2tgG4HIvFmjHLr_KexVXnT8hSBM-dKG_fuXTZgE97So,9445
|
112
112
|
schemathesis/openapi/__init__.py,sha256=-KcsSAM19uOM0N5J4s-yTnQ1BFsptYhW1E51cEf6kVM,311
|
113
|
-
schemathesis/openapi/checks.py,sha256=
|
113
|
+
schemathesis/openapi/checks.py,sha256=nrkkagRqg-HOsDCAMbJqCnHyBZEA2PpRV_AB8lI_I9c,13080
|
114
114
|
schemathesis/openapi/loaders.py,sha256=-DSFWcvD_PmekTyy0qZrJ1YYODh9C1KuAJJIytEnS1s,10733
|
115
115
|
schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
116
116
|
schemathesis/openapi/generation/filters.py,sha256=pY9cUZdL_kQK80Z2aylTOqqa12zmaYUlYC5BfYgeQMk,2395
|
@@ -142,14 +142,14 @@ schemathesis/specs/openapi/schemas.py,sha256=vwBgw7kznPlQJIufgJ48oRxCzDFkUWKfb4u
|
|
142
142
|
schemathesis/specs/openapi/serialization.py,sha256=RPNdadne5wdhsGmjSvgKLRF58wpzpRx3wura8PsHM3o,12152
|
143
143
|
schemathesis/specs/openapi/utils.py,sha256=XkOJT8qD-6uhq-Tmwxk_xYku1Gy5F9pKL3ldNg_DRZw,522
|
144
144
|
schemathesis/specs/openapi/adapter/__init__.py,sha256=YEovBgLjnXd3WGPMJXq0KbSGHezkRlEv4dNRO7_evfk,249
|
145
|
-
schemathesis/specs/openapi/adapter/parameters.py,sha256=
|
146
|
-
schemathesis/specs/openapi/adapter/protocol.py,sha256=
|
145
|
+
schemathesis/specs/openapi/adapter/parameters.py,sha256=MYEQUxhtv23e1uhoDq5bDHMUT3Q64bW7aZloJuz13QY,18626
|
146
|
+
schemathesis/specs/openapi/adapter/protocol.py,sha256=VDF6COcilHEUnmw76YBVur8bFiTFQHsNvaO9pR_i_KM,2709
|
147
147
|
schemathesis/specs/openapi/adapter/references.py,sha256=6M59pJy_U_sLh3Xzgu6-izWXtz3bjXnqJYSD65wRHtk,549
|
148
|
-
schemathesis/specs/openapi/adapter/responses.py,sha256=
|
148
|
+
schemathesis/specs/openapi/adapter/responses.py,sha256=Zv9uNgyr591-ZUcBCYMGot9ZccJgrxEOd9KI8wDfDTY,13253
|
149
149
|
schemathesis/specs/openapi/adapter/security.py,sha256=W3cqlbs80NxF9SAavOi7BhtNGzdxHO476lYxiWN0D08,4945
|
150
|
-
schemathesis/specs/openapi/adapter/v2.py,sha256=
|
151
|
-
schemathesis/specs/openapi/adapter/v3_0.py,sha256=
|
152
|
-
schemathesis/specs/openapi/adapter/v3_1.py,sha256=
|
150
|
+
schemathesis/specs/openapi/adapter/v2.py,sha256=2Rd1cTv7_I5QrBPLVfa2yD80NAErxV3tdeACjtEfXAA,1280
|
151
|
+
schemathesis/specs/openapi/adapter/v3_0.py,sha256=8bOE9WUDrvPivGs0w-S1PP2TXgWuaoTzMdg2_WWbi-E,1272
|
152
|
+
schemathesis/specs/openapi/adapter/v3_1.py,sha256=Hi4iMQdLDAeqSVYjafXbRb5yolWuqMz9A954tE2SCQY,1282
|
153
153
|
schemathesis/specs/openapi/expressions/__init__.py,sha256=hfuRtXD75tQFhzSo6QgDZ3zByyWeZRKevB8edszAVj4,2272
|
154
154
|
schemathesis/specs/openapi/expressions/errors.py,sha256=YLVhps-sYcslgVaahfcUYxUSHlIfWL-rQMeT5PZSMZ8,219
|
155
155
|
schemathesis/specs/openapi/expressions/extractors.py,sha256=IvOrgq_1IWNnirOSV_wLi0UcWOTiL-mLvBLFzLwRpVA,498
|
@@ -162,8 +162,15 @@ schemathesis/specs/openapi/negative/types.py,sha256=a7buCcVxNBG6ILBM3A7oNTAX0lyD
|
|
162
162
|
schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrrkuNdXX0SDnLoGYA,168
|
163
163
|
schemathesis/specs/openapi/stateful/__init__.py,sha256=nD5f9pP2Rx2DKIeXtbc_KqUukC4Nf2834cHeOp52byM,16247
|
164
164
|
schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8n5ePqSKB00XFxp-MA,3695
|
165
|
-
schemathesis/specs/openapi/stateful/inference.py,sha256=
|
165
|
+
schemathesis/specs/openapi/stateful/inference.py,sha256=9o9V-UUpphW7u_Kqz5MCp1_JXS2H_rcAZwz0bwJnmbI,9637
|
166
166
|
schemathesis/specs/openapi/stateful/links.py,sha256=G6vqW6JFOdhF044ZjG6PsSwAHU1yP4E3FolcNFE55NM,7918
|
167
|
+
schemathesis/specs/openapi/stateful/dependencies/__init__.py,sha256=epBYtVw7q9mkV-UtlJNbfJQgwAs9d5jkOJYkyEeUMvE,3348
|
168
|
+
schemathesis/specs/openapi/stateful/dependencies/inputs.py,sha256=5niLSz7-wl-sP9cJdnYBItwEeLuzJr3nw4XIMT3yt98,6764
|
169
|
+
schemathesis/specs/openapi/stateful/dependencies/models.py,sha256=4MXJzCat1bU-tmwAM7OH2dFBys_YHCJw9wTgd9Hib3c,9728
|
170
|
+
schemathesis/specs/openapi/stateful/dependencies/naming.py,sha256=1aaa8vc56tsyOAKAvD8oPk55S-qbzrCBYe1kCk3Y9VY,9052
|
171
|
+
schemathesis/specs/openapi/stateful/dependencies/outputs.py,sha256=zvVUfQWNIuhMkKDpz5hsVGkkvkefLt1EswpJAnHajOw,1186
|
172
|
+
schemathesis/specs/openapi/stateful/dependencies/resources.py,sha256=7E2Z6LvomSRrp_0vCD_adzoux0wBLEjKi_EiSqiN43U,9664
|
173
|
+
schemathesis/specs/openapi/stateful/dependencies/schemas.py,sha256=pNV2GibNW8042KrdfUQBdJEkGj_dd84bTHbqunba48k,13976
|
167
174
|
schemathesis/specs/openapi/types/__init__.py,sha256=VPsWtLJle__Kodw_QqtQ3OuvBzBcCIKsTOrXy3eA7OU,66
|
168
175
|
schemathesis/specs/openapi/types/v3.py,sha256=Vondr9Amk6JKCIM6i6RGcmTUjFfPgOOqzBXqerccLpo,1468
|
169
176
|
schemathesis/transport/__init__.py,sha256=6yg_RfV_9L0cpA6qpbH-SL9_3ggtHQji9CZrpIkbA6s,5321
|
@@ -172,8 +179,8 @@ schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEz
|
|
172
179
|
schemathesis/transport/requests.py,sha256=wriRI9fprTplE_qEZLEz1TerX6GwkE3pwr6ZnU2o6vQ,10648
|
173
180
|
schemathesis/transport/serialization.py,sha256=GwO6OAVTmL1JyKw7HiZ256tjV4CbrRbhQN0ep1uaZwI,11157
|
174
181
|
schemathesis/transport/wsgi.py,sha256=kQtasFre6pjdJWRKwLA_Qb-RyQHCFNpaey9ubzlFWKI,5907
|
175
|
-
schemathesis-4.
|
176
|
-
schemathesis-4.
|
177
|
-
schemathesis-4.
|
178
|
-
schemathesis-4.
|
179
|
-
schemathesis-4.
|
182
|
+
schemathesis-4.3.1.dist-info/METADATA,sha256=cJcbDVPtmrVZIVWanF1tJxF1Vbhel76KAhpzJLj_KHs,8540
|
183
|
+
schemathesis-4.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
184
|
+
schemathesis-4.3.1.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
|
185
|
+
schemathesis-4.3.1.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
|
186
|
+
schemathesis-4.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|