schemathesis 3.38.5__py3-none-any.whl → 3.38.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/_hypothesis.py +81 -15
- schemathesis/generation/coverage.py +32 -14
- schemathesis/models.py +2 -1
- schemathesis/specs/openapi/checks.py +2 -2
- schemathesis/specs/openapi/patterns.py +25 -8
- {schemathesis-3.38.5.dist-info → schemathesis-3.38.7.dist-info}/METADATA +2 -3
- {schemathesis-3.38.5.dist-info → schemathesis-3.38.7.dist-info}/RECORD +10 -10
- {schemathesis-3.38.5.dist-info → schemathesis-3.38.7.dist-info}/WHEEL +1 -1
- {schemathesis-3.38.5.dist-info → schemathesis-3.38.7.dist-info}/entry_points.txt +0 -0
- {schemathesis-3.38.5.dist-info → schemathesis-3.38.7.dist-info}/licenses/LICENSE +0 -0
schemathesis/_hypothesis.py
CHANGED
|
@@ -224,6 +224,15 @@ def _iter_coverage_cases(
|
|
|
224
224
|
from .specs.openapi.constants import LOCATION_TO_CONTAINER
|
|
225
225
|
from .specs.openapi.examples import find_in_responses, find_matching_in_responses
|
|
226
226
|
|
|
227
|
+
def _stringify_value(val: Any, location: str) -> str | list[str]:
|
|
228
|
+
if isinstance(val, list):
|
|
229
|
+
if location == "query":
|
|
230
|
+
# Having a list here ensures there will be multiple query parameters wit the same name
|
|
231
|
+
return [json.dumps(item) for item in val]
|
|
232
|
+
# use comma-separated values style for arrays
|
|
233
|
+
return ",".join(json.dumps(sub) for sub in val)
|
|
234
|
+
return json.dumps(val)
|
|
235
|
+
|
|
227
236
|
generators: dict[tuple[str, str], Generator[coverage.GeneratedValue, None, None]] = {}
|
|
228
237
|
template: dict[str, Any] = {}
|
|
229
238
|
responses = find_in_responses(operation)
|
|
@@ -240,8 +249,8 @@ def _iter_coverage_cases(
|
|
|
240
249
|
location = parameter.location
|
|
241
250
|
name = parameter.name
|
|
242
251
|
container = template.setdefault(LOCATION_TO_CONTAINER[location], {})
|
|
243
|
-
if location in ("header", "cookie") and not isinstance(value.value, str):
|
|
244
|
-
container[name] =
|
|
252
|
+
if location in ("header", "cookie", "path", "query") and not isinstance(value.value, str):
|
|
253
|
+
container[name] = _stringify_value(value.value, location)
|
|
245
254
|
else:
|
|
246
255
|
container[name] = value.value
|
|
247
256
|
generators[(location, name)] = gen
|
|
@@ -286,12 +295,13 @@ def _iter_coverage_cases(
|
|
|
286
295
|
case.data_generation_method = DataGenerationMethod.positive
|
|
287
296
|
case.meta = _make_meta(description="Default positive test case")
|
|
288
297
|
yield case
|
|
298
|
+
|
|
289
299
|
for (location, name), gen in generators.items():
|
|
290
300
|
container_name = LOCATION_TO_CONTAINER[location]
|
|
291
301
|
container = template[container_name]
|
|
292
302
|
for value in gen:
|
|
293
|
-
if location in ("header", "cookie") and not isinstance(value.value, str):
|
|
294
|
-
generated =
|
|
303
|
+
if location in ("header", "cookie", "path", "query") and not isinstance(value.value, str):
|
|
304
|
+
generated = _stringify_value(value.value, location)
|
|
295
305
|
else:
|
|
296
306
|
generated = value.value
|
|
297
307
|
case = operation.make_case(**{**template, container_name: {**container, name: generated}})
|
|
@@ -303,8 +313,32 @@ def _iter_coverage_cases(
|
|
|
303
313
|
parameter_location=location,
|
|
304
314
|
)
|
|
305
315
|
yield case
|
|
306
|
-
# Generate missing required parameters
|
|
307
316
|
if DataGenerationMethod.negative in data_generation_methods:
|
|
317
|
+
# Generate HTTP methods that are not specified in the spec
|
|
318
|
+
methods = {"get", "put", "post", "delete", "options", "head", "patch", "trace"} - set(
|
|
319
|
+
operation.schema[operation.path]
|
|
320
|
+
)
|
|
321
|
+
for method in methods:
|
|
322
|
+
case = operation.make_case(**template)
|
|
323
|
+
case._explicit_method = method
|
|
324
|
+
case.data_generation_method = DataGenerationMethod.negative
|
|
325
|
+
case.meta = _make_meta(description=f"Unspecified HTTP method: {method}")
|
|
326
|
+
yield case
|
|
327
|
+
# Generate duplicate query parameters
|
|
328
|
+
if operation.query:
|
|
329
|
+
container = template["query"]
|
|
330
|
+
for parameter in operation.query:
|
|
331
|
+
value = container[parameter.name]
|
|
332
|
+
case = operation.make_case(**{**template, "query": {**container, parameter.name: [value, value]}})
|
|
333
|
+
case.data_generation_method = DataGenerationMethod.negative
|
|
334
|
+
case.meta = _make_meta(
|
|
335
|
+
description=f"Duplicate `{parameter.name}` query parameter",
|
|
336
|
+
location=None,
|
|
337
|
+
parameter=parameter.name,
|
|
338
|
+
parameter_location="query",
|
|
339
|
+
)
|
|
340
|
+
yield case
|
|
341
|
+
# Generate missing required parameters
|
|
308
342
|
for parameter in operation.iter_parameters():
|
|
309
343
|
if parameter.is_required and parameter.location != "path":
|
|
310
344
|
name = parameter.name
|
|
@@ -317,7 +351,7 @@ def _iter_coverage_cases(
|
|
|
317
351
|
case.data_generation_method = DataGenerationMethod.negative
|
|
318
352
|
case.meta = _make_meta(
|
|
319
353
|
description=f"Missing `{name}` at {location}",
|
|
320
|
-
location=
|
|
354
|
+
location=None,
|
|
321
355
|
parameter=name,
|
|
322
356
|
parameter_location=location,
|
|
323
357
|
)
|
|
@@ -340,19 +374,28 @@ def _iter_coverage_cases(
|
|
|
340
374
|
optional = sorted(all_params - required)
|
|
341
375
|
|
|
342
376
|
# Helper function to create and yield a case
|
|
343
|
-
def make_case(
|
|
344
|
-
|
|
377
|
+
def make_case(
|
|
378
|
+
container_values: dict,
|
|
379
|
+
description: str,
|
|
380
|
+
_location: str,
|
|
381
|
+
_container_name: str,
|
|
382
|
+
_parameter: str | None,
|
|
383
|
+
_data_generation_method: DataGenerationMethod,
|
|
384
|
+
) -> Case:
|
|
385
|
+
if _location in ("header", "cookie", "path", "query"):
|
|
345
386
|
container = {
|
|
346
|
-
name:
|
|
387
|
+
name: _stringify_value(val, _location) if not isinstance(val, str) else val
|
|
388
|
+
for name, val in container_values.items()
|
|
347
389
|
}
|
|
348
390
|
else:
|
|
349
391
|
container = container_values
|
|
350
392
|
|
|
351
393
|
case = operation.make_case(**{**template, _container_name: container})
|
|
352
|
-
case.data_generation_method =
|
|
394
|
+
case.data_generation_method = _data_generation_method
|
|
353
395
|
case.meta = _make_meta(
|
|
354
396
|
description=description,
|
|
355
|
-
location=
|
|
397
|
+
location=None,
|
|
398
|
+
parameter=_parameter,
|
|
356
399
|
parameter_location=_location,
|
|
357
400
|
)
|
|
358
401
|
return case
|
|
@@ -377,12 +420,21 @@ def _iter_coverage_cases(
|
|
|
377
420
|
coverage.CoverageContext(data_generation_methods=[DataGenerationMethod.negative]),
|
|
378
421
|
subschema,
|
|
379
422
|
):
|
|
380
|
-
yield make_case(
|
|
423
|
+
yield make_case(
|
|
424
|
+
more.value,
|
|
425
|
+
more.description,
|
|
426
|
+
_location,
|
|
427
|
+
_container_name,
|
|
428
|
+
more.parameter,
|
|
429
|
+
DataGenerationMethod.negative,
|
|
430
|
+
)
|
|
381
431
|
|
|
382
432
|
# 1. Generate only required properties
|
|
383
433
|
if required and all_params != required:
|
|
384
434
|
only_required = {k: v for k, v in base_container.items() if k in required}
|
|
385
|
-
yield make_case(
|
|
435
|
+
yield make_case(
|
|
436
|
+
only_required, "Only required properties", location, container_name, None, DataGenerationMethod.positive
|
|
437
|
+
)
|
|
386
438
|
if DataGenerationMethod.negative in data_generation_methods:
|
|
387
439
|
subschema = _combination_schema(only_required, required, parameter_set)
|
|
388
440
|
yield from _yield_negative(subschema, location, container_name)
|
|
@@ -391,7 +443,14 @@ def _iter_coverage_cases(
|
|
|
391
443
|
for opt_param in optional:
|
|
392
444
|
combo = {k: v for k, v in base_container.items() if k in required or k == opt_param}
|
|
393
445
|
if combo != base_container:
|
|
394
|
-
yield make_case(
|
|
446
|
+
yield make_case(
|
|
447
|
+
combo,
|
|
448
|
+
f"All required properties and optional '{opt_param}'",
|
|
449
|
+
location,
|
|
450
|
+
container_name,
|
|
451
|
+
None,
|
|
452
|
+
DataGenerationMethod.positive,
|
|
453
|
+
)
|
|
395
454
|
if DataGenerationMethod.negative in data_generation_methods:
|
|
396
455
|
subschema = _combination_schema(combo, required, parameter_set)
|
|
397
456
|
yield from _yield_negative(subschema, location, container_name)
|
|
@@ -402,7 +461,14 @@ def _iter_coverage_cases(
|
|
|
402
461
|
for combination in combinations(optional, size):
|
|
403
462
|
combo = {k: v for k, v in base_container.items() if k in required or k in combination}
|
|
404
463
|
if combo != base_container:
|
|
405
|
-
yield make_case(
|
|
464
|
+
yield make_case(
|
|
465
|
+
combo,
|
|
466
|
+
f"All required and {size} optional properties",
|
|
467
|
+
location,
|
|
468
|
+
container_name,
|
|
469
|
+
None,
|
|
470
|
+
DataGenerationMethod.positive,
|
|
471
|
+
)
|
|
406
472
|
|
|
407
473
|
|
|
408
474
|
def _make_meta(
|
|
@@ -39,7 +39,7 @@ NUMERIC_STRATEGY: st.SearchStrategy = st.integers() | FLOAT_STRATEGY
|
|
|
39
39
|
JSON_STRATEGY: st.SearchStrategy = st.recursive(
|
|
40
40
|
st.none() | st.booleans() | NUMERIC_STRATEGY | st.text(), json_recursive_strategy
|
|
41
41
|
)
|
|
42
|
-
ARRAY_STRATEGY: st.SearchStrategy = st.lists(JSON_STRATEGY)
|
|
42
|
+
ARRAY_STRATEGY: st.SearchStrategy = st.lists(JSON_STRATEGY, min_size=2)
|
|
43
43
|
OBJECT_STRATEGY: st.SearchStrategy = st.dictionaries(st.text(), JSON_STRATEGY)
|
|
44
44
|
|
|
45
45
|
|
|
@@ -63,23 +63,31 @@ class GeneratedValue:
|
|
|
63
63
|
value: Any
|
|
64
64
|
data_generation_method: DataGenerationMethod
|
|
65
65
|
description: str
|
|
66
|
+
parameter: str | None
|
|
66
67
|
location: str | None
|
|
67
68
|
|
|
68
|
-
__slots__ = ("value", "data_generation_method", "description", "location")
|
|
69
|
+
__slots__ = ("value", "data_generation_method", "description", "parameter", "location")
|
|
69
70
|
|
|
70
71
|
@classmethod
|
|
71
72
|
def with_positive(cls, value: Any, *, description: str) -> GeneratedValue:
|
|
72
73
|
return cls(
|
|
73
|
-
value=value,
|
|
74
|
+
value=value,
|
|
75
|
+
data_generation_method=DataGenerationMethod.positive,
|
|
76
|
+
description=description,
|
|
77
|
+
location=None,
|
|
78
|
+
parameter=None,
|
|
74
79
|
)
|
|
75
80
|
|
|
76
81
|
@classmethod
|
|
77
|
-
def with_negative(
|
|
82
|
+
def with_negative(
|
|
83
|
+
cls, value: Any, *, description: str, location: str, parameter: str | None = None
|
|
84
|
+
) -> GeneratedValue:
|
|
78
85
|
return cls(
|
|
79
86
|
value=value,
|
|
80
87
|
data_generation_method=DataGenerationMethod.negative,
|
|
81
88
|
description=description,
|
|
82
89
|
location=location,
|
|
90
|
+
parameter=parameter,
|
|
83
91
|
)
|
|
84
92
|
|
|
85
93
|
|
|
@@ -218,11 +226,11 @@ def _encode(o: Any) -> str:
|
|
|
218
226
|
return "".join(_iterencode(o, 0))
|
|
219
227
|
|
|
220
228
|
|
|
221
|
-
def _to_hashable_key(value: T, _encode: Callable = _encode) ->
|
|
229
|
+
def _to_hashable_key(value: T, _encode: Callable = _encode) -> tuple[type, str | T]:
|
|
222
230
|
if isinstance(value, (dict, list)):
|
|
223
231
|
serialized = _encode(value)
|
|
224
232
|
return (type(value), serialized)
|
|
225
|
-
return value
|
|
233
|
+
return (type(value), value)
|
|
226
234
|
|
|
227
235
|
|
|
228
236
|
def _cover_positive_for_type(
|
|
@@ -316,9 +324,9 @@ def cover_schema_iter(
|
|
|
316
324
|
for key, value in schema.items():
|
|
317
325
|
with _ignore_unfixable(), ctx.location(key):
|
|
318
326
|
if key == "enum":
|
|
319
|
-
yield from _negative_enum(ctx, value)
|
|
327
|
+
yield from _negative_enum(ctx, value, seen)
|
|
320
328
|
elif key == "const":
|
|
321
|
-
for value_ in _negative_enum(ctx, [value]):
|
|
329
|
+
for value_ in _negative_enum(ctx, [value], seen):
|
|
322
330
|
k = _to_hashable_key(value_.value)
|
|
323
331
|
if k not in seen:
|
|
324
332
|
yield value_
|
|
@@ -425,7 +433,8 @@ def cover_schema_iter(
|
|
|
425
433
|
elif key == "allOf":
|
|
426
434
|
nctx = ctx.with_negative()
|
|
427
435
|
if len(value) == 1:
|
|
428
|
-
|
|
436
|
+
with nctx.location(0):
|
|
437
|
+
yield from cover_schema_iter(nctx, value[0], seen)
|
|
429
438
|
else:
|
|
430
439
|
with _ignore_unfixable():
|
|
431
440
|
canonical = canonicalish(schema)
|
|
@@ -735,13 +744,20 @@ def select_combinations(optional: list[str]) -> Iterator[tuple[str, ...]]:
|
|
|
735
744
|
yield next(combinations(optional, size))
|
|
736
745
|
|
|
737
746
|
|
|
738
|
-
def _negative_enum(
|
|
747
|
+
def _negative_enum(
|
|
748
|
+
ctx: CoverageContext, value: list, seen: set[Any | tuple[type, str]]
|
|
749
|
+
) -> Generator[GeneratedValue, None, None]:
|
|
739
750
|
def is_not_in_value(x: Any) -> bool:
|
|
740
|
-
|
|
751
|
+
if x in value:
|
|
752
|
+
return False
|
|
753
|
+
_hashed = _to_hashable_key(x)
|
|
754
|
+
return _hashed not in seen
|
|
741
755
|
|
|
742
|
-
strategy =
|
|
743
|
-
|
|
744
|
-
yield NegativeValue(
|
|
756
|
+
strategy = (st.none() | st.booleans() | NUMERIC_STRATEGY | st.text()).filter(is_not_in_value)
|
|
757
|
+
value = ctx.generate_from(strategy)
|
|
758
|
+
yield NegativeValue(value, description="Invalid enum value", location=ctx.current_location)
|
|
759
|
+
hashed = _to_hashable_key(value)
|
|
760
|
+
seen.add(hashed)
|
|
745
761
|
|
|
746
762
|
|
|
747
763
|
def _negative_properties(
|
|
@@ -755,6 +771,7 @@ def _negative_properties(
|
|
|
755
771
|
{**template, key: value.value},
|
|
756
772
|
description=f"Object with invalid '{key}' value: {value.description}",
|
|
757
773
|
location=nctx.current_location,
|
|
774
|
+
parameter=key,
|
|
758
775
|
)
|
|
759
776
|
|
|
760
777
|
|
|
@@ -836,6 +853,7 @@ def _negative_required(
|
|
|
836
853
|
{k: v for k, v in template.items() if k != key},
|
|
837
854
|
description=f"Missing required property: {key}",
|
|
838
855
|
location=ctx.current_location,
|
|
856
|
+
parameter=key,
|
|
839
857
|
)
|
|
840
858
|
|
|
841
859
|
|
schemathesis/models.py
CHANGED
|
@@ -203,6 +203,7 @@ class Case:
|
|
|
203
203
|
data_generation_method: DataGenerationMethod | None = None
|
|
204
204
|
_auth: requests.auth.AuthBase | None = None
|
|
205
205
|
_has_explicit_auth: bool = False
|
|
206
|
+
_explicit_method: str | None = None
|
|
206
207
|
|
|
207
208
|
def __post_init__(self) -> None:
|
|
208
209
|
self._original_path_parameters = self.path_parameters.copy() if self.path_parameters else None
|
|
@@ -265,7 +266,7 @@ class Case:
|
|
|
265
266
|
|
|
266
267
|
@property
|
|
267
268
|
def method(self) -> str:
|
|
268
|
-
return self.operation.method.upper()
|
|
269
|
+
return self._explicit_method.upper() if self._explicit_method else self.operation.method.upper()
|
|
269
270
|
|
|
270
271
|
@property
|
|
271
272
|
def base_url(self) -> str | None:
|
|
@@ -391,14 +391,14 @@ def ignored_auth(ctx: CheckContext, response: GenericResponse, case: Case) -> bo
|
|
|
391
391
|
# Check if invalid auth will give an error
|
|
392
392
|
_remove_auth_from_case(case, security_parameters)
|
|
393
393
|
new_response = case.operation.schema.transport.send(case)
|
|
394
|
-
if
|
|
394
|
+
if new_response.status_code != 401:
|
|
395
395
|
_update_response(response, new_response)
|
|
396
396
|
_raise_no_auth_error(new_response, case.operation.verbose_name, "that requires authentication")
|
|
397
397
|
# Try to set invalid auth and check if it succeeds
|
|
398
398
|
for parameter in security_parameters:
|
|
399
399
|
_set_auth_for_case(case, parameter)
|
|
400
400
|
new_response = case.operation.schema.transport.send(case)
|
|
401
|
-
if
|
|
401
|
+
if new_response.status_code != 401:
|
|
402
402
|
_update_response(response, new_response)
|
|
403
403
|
_raise_no_auth_error(new_response, case.operation.verbose_name, "with any auth")
|
|
404
404
|
_remove_auth_from_case(case, security_parameters)
|
|
@@ -44,21 +44,38 @@ def _handle_parsed_pattern(parsed: list, pattern: str, min_length: int | None, m
|
|
|
44
44
|
if parsed[0][0] == ANCHOR:
|
|
45
45
|
# Starts with an anchor
|
|
46
46
|
op, value = parsed[1]
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
anchor_length = _get_anchor_length(parsed[0][1])
|
|
48
|
+
leading_anchor = pattern[:anchor_length]
|
|
49
|
+
return leading_anchor + _update_quantifier(op, value, pattern[anchor_length:], min_length, max_length)
|
|
49
50
|
if parsed[1][0] == ANCHOR:
|
|
50
51
|
# Ends with an anchor
|
|
51
52
|
op, value = parsed[0]
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
anchor_length = _get_anchor_length(parsed[1][1])
|
|
54
|
+
trailing_anchor = pattern[-anchor_length:]
|
|
55
|
+
return _update_quantifier(op, value, pattern[:-anchor_length], min_length, max_length) + trailing_anchor
|
|
54
56
|
elif len(parsed) == 3 and parsed[0][0] == ANCHOR and parsed[2][0] == ANCHOR:
|
|
55
57
|
op, value = parsed[1]
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
leading_anchor_length = _get_anchor_length(parsed[0][1])
|
|
59
|
+
trailing_anchor_length = _get_anchor_length(parsed[2][1])
|
|
60
|
+
leading_anchor = pattern[:leading_anchor_length]
|
|
61
|
+
trailing_anchor = pattern[-trailing_anchor_length:]
|
|
62
|
+
return (
|
|
63
|
+
leading_anchor
|
|
64
|
+
+ _update_quantifier(
|
|
65
|
+
op, value, pattern[leading_anchor_length:-trailing_anchor_length], min_length, max_length
|
|
66
|
+
)
|
|
67
|
+
+ trailing_anchor
|
|
68
|
+
)
|
|
59
69
|
return pattern
|
|
60
70
|
|
|
61
71
|
|
|
72
|
+
def _get_anchor_length(node_type: int) -> int:
|
|
73
|
+
"""Determine the length of the anchor based on its type."""
|
|
74
|
+
if node_type in {sre.AT_BEGINNING_STRING, sre.AT_END_STRING, sre.AT_BOUNDARY, sre.AT_NON_BOUNDARY}:
|
|
75
|
+
return 2 # \A, \Z, \b, or \B
|
|
76
|
+
return 1 # ^ or $ or their multiline/locale/unicode variants
|
|
77
|
+
|
|
78
|
+
|
|
62
79
|
def _update_quantifier(op: int, value: tuple, pattern: str, min_length: int | None, max_length: int | None) -> str:
|
|
63
80
|
"""Update the quantifier based on the operation type and given constraints."""
|
|
64
81
|
if op in REPEATS:
|
|
@@ -113,7 +130,7 @@ def _strip_quantifier(pattern: str) -> str:
|
|
|
113
130
|
return pattern[:-2]
|
|
114
131
|
if pattern.endswith(("?", "*", "+")):
|
|
115
132
|
pattern = pattern[:-1]
|
|
116
|
-
if pattern.endswith("}"):
|
|
133
|
+
if pattern.endswith("}") and "{" in pattern:
|
|
117
134
|
# Find the start of the exact quantifier and drop everything since that index
|
|
118
135
|
idx = pattern.rfind("{")
|
|
119
136
|
pattern = pattern[:idx]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: schemathesis
|
|
3
|
-
Version: 3.38.
|
|
3
|
+
Version: 3.38.7
|
|
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://schemathesis.readthedocs.io/en/stable/changelog.html
|
|
@@ -9,8 +9,7 @@ Project-URL: Funding, https://github.com/sponsors/Stranger6667
|
|
|
9
9
|
Project-URL: Source Code, https://github.com/schemathesis/schemathesis
|
|
10
10
|
Author-email: Dmitry Dygalo <dmitry@dygalo.dev>
|
|
11
11
|
Maintainer-email: Dmitry Dygalo <dmitry@dygalo.dev>
|
|
12
|
-
License
|
|
13
|
-
License-File: LICENSE
|
|
12
|
+
License: MIT
|
|
14
13
|
Keywords: graphql,hypothesis,openapi,pytest,testing
|
|
15
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
16
15
|
Classifier: Environment :: Console
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
schemathesis/__init__.py,sha256=UW2Bq8hDDkcBeAAA7PzpBFXkOOxkmHox-mfQwzHDjL0,1914
|
|
2
2
|
schemathesis/_compat.py,sha256=y4RZd59i2NCnZ91VQhnKeMn_8t3SgvLOk2Xm8nymUHY,1837
|
|
3
3
|
schemathesis/_dependency_versions.py,sha256=pjEkkGAfOQJYNb-9UOo84V8nj_lKHr_TGDVdFwY2UU0,816
|
|
4
|
-
schemathesis/_hypothesis.py,sha256=
|
|
4
|
+
schemathesis/_hypothesis.py,sha256=7hQItl5JqtctCiN7gL4DhWmj8A0Ku6t1_pkxEqkID1g,23463
|
|
5
5
|
schemathesis/_lazy_import.py,sha256=aMhWYgbU2JOltyWBb32vnWBb6kykOghucEzI_F70yVE,470
|
|
6
6
|
schemathesis/_override.py,sha256=TAjYB3eJQmlw9K_xiR9ptt9Wj7if4U7UFlUhGjpBAoM,1625
|
|
7
7
|
schemathesis/_patches.py,sha256=Hsbpn4UVeXUQD2Kllrbq01CSWsTYENWa0VJTyhX5C2k,895
|
|
@@ -18,7 +18,7 @@ schemathesis/graphql.py,sha256=XiuKcfoOB92iLFC8zpz2msLkM0_V0TLdxPNBqrrGZ8w,216
|
|
|
18
18
|
schemathesis/hooks.py,sha256=p5AXgjVGtka0jn9MOeyBaRUtNbqZTs4iaJqytYTacHc,14856
|
|
19
19
|
schemathesis/lazy.py,sha256=Ddhkk7Tpc_VcRGYkCtKDmP2gpjxVmEZ3b01ZTNjbm8I,19004
|
|
20
20
|
schemathesis/loaders.py,sha256=MoEhcdOEBJxNRn5X-ZNhWB9jZDHQQNpkNfEdQjf_NDw,4590
|
|
21
|
-
schemathesis/models.py,sha256=
|
|
21
|
+
schemathesis/models.py,sha256=Xn1rEF0_g3HNqJaJB9sC8N3gJ9suFPPlgc8ho01VyF0,49769
|
|
22
22
|
schemathesis/parameters.py,sha256=izlu4MFYT1RWrC4RBxrV6weeCal-ODbdLQLMb0PYCZY,2327
|
|
23
23
|
schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
schemathesis/sanitization.py,sha256=Lycn1VVfula9B6XpzkxTHja7CZ7RHqbUh9kBic0Yi4M,9056
|
|
@@ -61,7 +61,7 @@ schemathesis/fixups/utf8_bom.py,sha256=lWT9RNmJG8i-l5AXIpaCT3qCPUwRgzXPW3eoOjmZE
|
|
|
61
61
|
schemathesis/generation/__init__.py,sha256=29Zys_tD6kfngaC4zHeC6TOBZQcmo7CWm7KDSYsHStQ,1581
|
|
62
62
|
schemathesis/generation/_hypothesis.py,sha256=74fzLPHugZgMQXerWYFAMqCAjtAXz5E4gek7Gnkhli4,1756
|
|
63
63
|
schemathesis/generation/_methods.py,sha256=r8oVlJ71_gXcnEhU-byw2E0R2RswQQFm8U7yGErSqbw,1204
|
|
64
|
-
schemathesis/generation/coverage.py,sha256=
|
|
64
|
+
schemathesis/generation/coverage.py,sha256=Y-eKsEDe6INu-2SjlzGpuzayRXF_wdDwTBLsW4pGlrc,38843
|
|
65
65
|
schemathesis/internal/__init__.py,sha256=93HcdG3LF0BbQKbCteOsFMa1w6nXl8yTmx87QLNJOik,161
|
|
66
66
|
schemathesis/internal/checks.py,sha256=SBx2gesB-XzgVSMX_u7Mb416jSxJ68eQKtcdkWlkyOo,2441
|
|
67
67
|
schemathesis/internal/copy.py,sha256=DcL56z-d69kKR_5u8mlHvjSL1UTyUKNMAwexrwHFY1s,1031
|
|
@@ -107,7 +107,7 @@ schemathesis/specs/graphql/validation.py,sha256=uINIOt-2E7ZuQV2CxKzwez-7L9tDtqzM
|
|
|
107
107
|
schemathesis/specs/openapi/__init__.py,sha256=HDcx3bqpa6qWPpyMrxAbM3uTo0Lqpg-BUNZhDJSJKnw,279
|
|
108
108
|
schemathesis/specs/openapi/_cache.py,sha256=PAiAu4X_a2PQgD2lG5H3iisXdyg4SaHpU46bRZvfNkM,4320
|
|
109
109
|
schemathesis/specs/openapi/_hypothesis.py,sha256=nU8UDn1PzGCre4IVmwIuO9-CZv1KJe1fYY0d2BojhSo,22981
|
|
110
|
-
schemathesis/specs/openapi/checks.py,sha256=
|
|
110
|
+
schemathesis/specs/openapi/checks.py,sha256=NZwcqmLnINq3rUUUmdof0GGB0AjaqSF5dOQy08nsJPg,23902
|
|
111
111
|
schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
|
|
112
112
|
schemathesis/specs/openapi/converter.py,sha256=Yxw9lS_JKEyi-oJuACT07fm04bqQDlAu-iHwzkeDvE4,3546
|
|
113
113
|
schemathesis/specs/openapi/definitions.py,sha256=WTkWwCgTc3OMxfKsqh6YDoGfZMTThSYrHGp8h0vLAK0,93935
|
|
@@ -117,7 +117,7 @@ schemathesis/specs/openapi/links.py,sha256=C4Uir2P_EcpqME8ee_a1vdUM8Tm3ZcKNn2YsG
|
|
|
117
117
|
schemathesis/specs/openapi/loaders.py,sha256=5B1cgYEBj3h2psPQxzrQ5Xq5owLVGw-u9HsCQIx7yFE,25705
|
|
118
118
|
schemathesis/specs/openapi/media_types.py,sha256=dNTxpRQbY3SubdVjh4Cjb38R6Bc9MF9BsRQwPD87x0g,1017
|
|
119
119
|
schemathesis/specs/openapi/parameters.py,sha256=LUahlWKCDSlp94v2IA1Q90pyeECgO6FmrqbzCU-9Z0Y,14658
|
|
120
|
-
schemathesis/specs/openapi/patterns.py,sha256=
|
|
120
|
+
schemathesis/specs/openapi/patterns.py,sha256=aEOiJeqI_qcE9bE2Viz6TUA8UppiTHm6QFxrLJryag8,5520
|
|
121
121
|
schemathesis/specs/openapi/references.py,sha256=euxM02kQGMHh4Ss1jWjOY_gyw_HazafKITIsvOEiAvI,9831
|
|
122
122
|
schemathesis/specs/openapi/schemas.py,sha256=MLU2h9DrQNCDkk74MFFSj-8BsKjkJsf9lJQHPxLFVps,53845
|
|
123
123
|
schemathesis/specs/openapi/security.py,sha256=Z-6pk2Ga1PTUtBe298KunjVHsNh5A-teegeso7zcPIE,7138
|
|
@@ -153,8 +153,8 @@ schemathesis/transports/auth.py,sha256=urSTO9zgFO1qU69xvnKHPFQV0SlJL3d7_Ojl0tLnZ
|
|
|
153
153
|
schemathesis/transports/content_types.py,sha256=MiKOm-Hy5i75hrROPdpiBZPOTDzOwlCdnthJD12AJzI,2187
|
|
154
154
|
schemathesis/transports/headers.py,sha256=hr_AIDOfUxsJxpHfemIZ_uNG3_vzS_ZeMEKmZjbYiBE,990
|
|
155
155
|
schemathesis/transports/responses.py,sha256=OFD4ZLqwEFpo7F9vaP_SVgjhxAqatxIj38FS4XVq8Qs,1680
|
|
156
|
-
schemathesis-3.38.
|
|
157
|
-
schemathesis-3.38.
|
|
158
|
-
schemathesis-3.38.
|
|
159
|
-
schemathesis-3.38.
|
|
160
|
-
schemathesis-3.38.
|
|
156
|
+
schemathesis-3.38.7.dist-info/METADATA,sha256=iBsAbz1uaJxY_GUPTnjdD2uMxS3HCk6lX_4IVj_s2yY,12923
|
|
157
|
+
schemathesis-3.38.7.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
|
158
|
+
schemathesis-3.38.7.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
|
|
159
|
+
schemathesis-3.38.7.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
|
|
160
|
+
schemathesis-3.38.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|