schemathesis 4.0.3__py3-none-any.whl → 4.0.5__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/engine/errors.py +8 -3
- schemathesis/engine/phases/stateful/_executor.py +3 -3
- schemathesis/engine/phases/unit/_executor.py +3 -3
- schemathesis/generation/coverage.py +37 -9
- schemathesis/generation/hypothesis/builder.py +37 -10
- schemathesis/openapi/checks.py +2 -2
- schemathesis/specs/openapi/_hypothesis.py +4 -8
- schemathesis/specs/openapi/checks.py +2 -2
- {schemathesis-4.0.3.dist-info → schemathesis-4.0.5.dist-info}/METADATA +1 -1
- {schemathesis-4.0.3.dist-info → schemathesis-4.0.5.dist-info}/RECORD +13 -13
- {schemathesis-4.0.3.dist-info → schemathesis-4.0.5.dist-info}/WHEEL +0 -0
- {schemathesis-4.0.3.dist-info → schemathesis-4.0.5.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.0.3.dist-info → schemathesis-4.0.5.dist-info}/licenses/LICENSE +0 -0
schemathesis/engine/errors.py
CHANGED
@@ -421,6 +421,7 @@ def clear_hypothesis_notes(exc: Exception) -> None:
|
|
421
421
|
def is_unrecoverable_network_error(exc: Exception) -> bool:
|
422
422
|
from http.client import RemoteDisconnected
|
423
423
|
|
424
|
+
import requests
|
424
425
|
from urllib3.exceptions import ProtocolError
|
425
426
|
|
426
427
|
def has_connection_reset(inner: BaseException) -> bool:
|
@@ -433,6 +434,8 @@ def is_unrecoverable_network_error(exc: Exception) -> bool:
|
|
433
434
|
|
434
435
|
return False
|
435
436
|
|
437
|
+
if isinstance(exc, requests.Timeout):
|
438
|
+
return True
|
436
439
|
if isinstance(exc.__context__, ProtocolError):
|
437
440
|
if len(exc.__context__.args) == 2 and isinstance(exc.__context__.args[1], RemoteDisconnected):
|
438
441
|
return True
|
@@ -442,14 +445,16 @@ def is_unrecoverable_network_error(exc: Exception) -> bool:
|
|
442
445
|
return has_connection_reset(exc)
|
443
446
|
|
444
447
|
|
445
|
-
@dataclass
|
448
|
+
@dataclass
|
446
449
|
class UnrecoverableNetworkError:
|
447
|
-
error: requests.ConnectionError | ChunkedEncodingError
|
450
|
+
error: requests.ConnectionError | ChunkedEncodingError | requests.Timeout
|
448
451
|
code_sample: str
|
449
452
|
|
450
453
|
__slots__ = ("error", "code_sample")
|
451
454
|
|
452
|
-
def __init__(
|
455
|
+
def __init__(
|
456
|
+
self, error: requests.ConnectionError | ChunkedEncodingError | requests.Timeout, code_sample: str
|
457
|
+
) -> None:
|
453
458
|
self.error = error
|
454
459
|
self.code_sample = code_sample
|
455
460
|
|
@@ -133,9 +133,9 @@ def execute_state_machine_loop(
|
|
133
133
|
ctx.step_failed()
|
134
134
|
raise
|
135
135
|
except Exception as exc:
|
136
|
-
if isinstance(
|
137
|
-
exc
|
138
|
-
):
|
136
|
+
if isinstance(
|
137
|
+
exc, (requests.ConnectionError, ChunkedEncodingError, requests.Timeout)
|
138
|
+
) and is_unrecoverable_network_error(exc):
|
139
139
|
transport_kwargs = engine.get_transport_kwargs(operation=input.case.operation)
|
140
140
|
if exc.request is not None:
|
141
141
|
headers = {key: value[0] for key, value in exc.request.headers.items()}
|
@@ -327,9 +327,9 @@ def cached_test_func(f: Callable) -> Callable:
|
|
327
327
|
except (KeyboardInterrupt, Failure):
|
328
328
|
raise
|
329
329
|
except Exception as exc:
|
330
|
-
if isinstance(
|
331
|
-
exc
|
332
|
-
):
|
330
|
+
if isinstance(
|
331
|
+
exc, (requests.ConnectionError, ChunkedEncodingError, requests.Timeout)
|
332
|
+
) and is_unrecoverable_network_error(exc):
|
333
333
|
# Server likely has crashed and does not accept any connections at all
|
334
334
|
# Don't report these error - only the original crash should be reported
|
335
335
|
if exc.request is not None:
|
@@ -109,20 +109,26 @@ def cached_draw(strategy: st.SearchStrategy) -> Any:
|
|
109
109
|
class CoverageContext:
|
110
110
|
generation_modes: list[GenerationMode]
|
111
111
|
location: str
|
112
|
+
is_required: bool
|
112
113
|
path: list[str | int]
|
114
|
+
custom_formats: dict[str, st.SearchStrategy]
|
113
115
|
|
114
|
-
__slots__ = ("location", "generation_modes", "path")
|
116
|
+
__slots__ = ("location", "generation_modes", "is_required", "path", "custom_formats")
|
115
117
|
|
116
118
|
def __init__(
|
117
119
|
self,
|
118
120
|
*,
|
119
121
|
location: str,
|
120
122
|
generation_modes: list[GenerationMode] | None = None,
|
123
|
+
is_required: bool,
|
121
124
|
path: list[str | int] | None = None,
|
125
|
+
custom_formats: dict[str, st.SearchStrategy],
|
122
126
|
) -> None:
|
123
127
|
self.location = location
|
124
128
|
self.generation_modes = generation_modes if generation_modes is not None else list(GenerationMode)
|
129
|
+
self.is_required = is_required
|
125
130
|
self.path = path or []
|
131
|
+
self.custom_formats = custom_formats
|
126
132
|
|
127
133
|
@contextmanager
|
128
134
|
def at(self, key: str | int) -> Generator[None, None, None]:
|
@@ -140,14 +146,18 @@ class CoverageContext:
|
|
140
146
|
return CoverageContext(
|
141
147
|
location=self.location,
|
142
148
|
generation_modes=[GenerationMode.POSITIVE],
|
149
|
+
is_required=self.is_required,
|
143
150
|
path=self.path,
|
151
|
+
custom_formats=self.custom_formats,
|
144
152
|
)
|
145
153
|
|
146
154
|
def with_negative(self) -> CoverageContext:
|
147
155
|
return CoverageContext(
|
148
156
|
location=self.location,
|
149
157
|
generation_modes=[GenerationMode.NEGATIVE],
|
158
|
+
is_required=self.is_required,
|
150
159
|
path=self.path,
|
160
|
+
custom_formats=self.custom_formats,
|
151
161
|
)
|
152
162
|
|
153
163
|
def is_valid_for_location(self, value: Any) -> bool:
|
@@ -157,6 +167,16 @@ class CoverageContext:
|
|
157
167
|
return not is_invalid_path_parameter(value)
|
158
168
|
return True
|
159
169
|
|
170
|
+
def leads_to_negative_test_case(self, value: Any) -> bool:
|
171
|
+
if self.location == "query":
|
172
|
+
# Some values will not be serialized into the query string
|
173
|
+
if isinstance(value, list) and not self.is_required:
|
174
|
+
# Optional parameters should be present
|
175
|
+
return any(item not in [{}, []] for item in value)
|
176
|
+
if isinstance(value, dict) and not self.is_required:
|
177
|
+
return bool(value)
|
178
|
+
return True
|
179
|
+
|
160
180
|
def generate_from(self, strategy: st.SearchStrategy) -> Any:
|
161
181
|
return cached_draw(strategy)
|
162
182
|
|
@@ -219,7 +239,10 @@ class CoverageContext:
|
|
219
239
|
return cached_draw(
|
220
240
|
st.lists(
|
221
241
|
st.fixed_dictionaries(
|
222
|
-
{
|
242
|
+
{
|
243
|
+
key: from_schema(sub_schema, custom_formats=self.custom_formats)
|
244
|
+
for key, sub_schema in items["properties"].items()
|
245
|
+
}
|
223
246
|
),
|
224
247
|
min_size=min_items,
|
225
248
|
)
|
@@ -230,7 +253,7 @@ class CoverageContext:
|
|
230
253
|
if isinstance(schema, dict) and "allOf" not in schema:
|
231
254
|
return self.generate_from_schema(schema)
|
232
255
|
|
233
|
-
return self.generate_from(from_schema(schema))
|
256
|
+
return self.generate_from(from_schema(schema, custom_formats=self.custom_formats))
|
234
257
|
|
235
258
|
|
236
259
|
T = TypeVar("T")
|
@@ -955,11 +978,13 @@ def _negative_items(ctx: CoverageContext, schema: dict[str, Any] | bool) -> Gene
|
|
955
978
|
"""Arrays not matching the schema."""
|
956
979
|
nctx = ctx.with_negative()
|
957
980
|
for value in cover_schema_iter(nctx, schema):
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
981
|
+
items = [value.value]
|
982
|
+
if ctx.leads_to_negative_test_case(items):
|
983
|
+
yield NegativeValue(
|
984
|
+
items,
|
985
|
+
description=f"Array with invalid items: {value.description}",
|
986
|
+
location=nctx.current_path,
|
987
|
+
)
|
963
988
|
|
964
989
|
|
965
990
|
def _not_matching_pattern(value: str, pattern: re.Pattern) -> bool:
|
@@ -1027,6 +1052,9 @@ def _negative_format(ctx: CoverageContext, schema: dict, format: str) -> Generat
|
|
1027
1052
|
# Hypothesis-jsonschema does not canonicalise it properly right now, which leads to unsatisfiable schema
|
1028
1053
|
without_format = {k: v for k, v in schema.items() if k != "format"}
|
1029
1054
|
without_format.setdefault("type", "string")
|
1055
|
+
if ctx.location == "path":
|
1056
|
+
# Empty path parameters are invalid
|
1057
|
+
without_format["minLength"] = 1
|
1030
1058
|
strategy = from_schema(without_format)
|
1031
1059
|
if format in jsonschema.Draft202012Validator.FORMAT_CHECKER.checkers:
|
1032
1060
|
if format == "hostname":
|
@@ -1060,7 +1088,7 @@ def _negative_type(
|
|
1060
1088
|
strategies["number"] = FLOAT_STRATEGY.filter(_is_non_integer_float)
|
1061
1089
|
for strategy in strategies.values():
|
1062
1090
|
value = ctx.generate_from(strategy)
|
1063
|
-
if seen.insert(value):
|
1091
|
+
if seen.insert(value) and ctx.is_valid_for_location(value):
|
1064
1092
|
yield NegativeValue(value, description="Incorrect type", location=ctx.current_path)
|
1065
1093
|
|
1066
1094
|
|
@@ -18,7 +18,7 @@ from requests.models import CaseInsensitiveDict
|
|
18
18
|
|
19
19
|
from schemathesis import auths
|
20
20
|
from schemathesis.auths import AuthStorage, AuthStorageMark
|
21
|
-
from schemathesis.config import ProjectConfig
|
21
|
+
from schemathesis.config import GenerationConfig, ProjectConfig
|
22
22
|
from schemathesis.core import NOT_SET, NotSet, SpecificationFeature, media_types
|
23
23
|
from schemathesis.core.errors import InvalidSchema, SerializationNotPossible
|
24
24
|
from schemathesis.core.marks import Mark
|
@@ -183,6 +183,7 @@ def create_test(
|
|
183
183
|
config.as_strategy_kwargs,
|
184
184
|
generate_duplicate_query_parameters=phases_config.coverage.generate_duplicate_query_parameters,
|
185
185
|
unexpected_methods=phases_config.coverage.unexpected_methods,
|
186
|
+
generation_config=generation,
|
186
187
|
)
|
187
188
|
|
188
189
|
setattr(hypothesis_test, SETTINGS_ATTRIBUTE_NAME, settings)
|
@@ -295,7 +296,8 @@ def add_coverage(
|
|
295
296
|
auth_storage: AuthStorage | None,
|
296
297
|
as_strategy_kwargs: dict[str, Any],
|
297
298
|
generate_duplicate_query_parameters: bool,
|
298
|
-
unexpected_methods: set[str]
|
299
|
+
unexpected_methods: set[str],
|
300
|
+
generation_config: GenerationConfig,
|
299
301
|
) -> Callable:
|
300
302
|
from schemathesis.specs.openapi.constants import LOCATION_TO_CONTAINER
|
301
303
|
|
@@ -309,7 +311,11 @@ def add_coverage(
|
|
309
311
|
if container in as_strategy_kwargs
|
310
312
|
}
|
311
313
|
for case in _iter_coverage_cases(
|
312
|
-
operation,
|
314
|
+
operation=operation,
|
315
|
+
generation_modes=generation_modes,
|
316
|
+
generate_duplicate_query_parameters=generate_duplicate_query_parameters,
|
317
|
+
unexpected_methods=unexpected_methods,
|
318
|
+
generation_config=generation_config,
|
313
319
|
):
|
314
320
|
if case.media_type and operation.schema.transport.get_first_matching_media_type(case.media_type) is None:
|
315
321
|
continue
|
@@ -446,11 +452,14 @@ def _stringify_value(val: Any, container_name: str) -> Any:
|
|
446
452
|
|
447
453
|
|
448
454
|
def _iter_coverage_cases(
|
455
|
+
*,
|
449
456
|
operation: APIOperation,
|
450
457
|
generation_modes: list[GenerationMode],
|
451
458
|
generate_duplicate_query_parameters: bool,
|
452
|
-
unexpected_methods: set[str]
|
459
|
+
unexpected_methods: set[str],
|
460
|
+
generation_config: GenerationConfig,
|
453
461
|
) -> Generator[Case, None, None]:
|
462
|
+
from schemathesis.specs.openapi._hypothesis import _build_custom_formats
|
454
463
|
from schemathesis.specs.openapi.constants import LOCATION_TO_CONTAINER
|
455
464
|
from schemathesis.specs.openapi.examples import find_in_responses, find_matching_in_responses
|
456
465
|
from schemathesis.specs.openapi.serialization import get_serializers_for_operation
|
@@ -463,6 +472,7 @@ def _iter_coverage_cases(
|
|
463
472
|
responses = find_in_responses(operation)
|
464
473
|
# NOTE: The HEAD method is excluded
|
465
474
|
unexpected_methods = unexpected_methods or {"get", "put", "post", "delete", "options", "patch", "trace"}
|
475
|
+
custom_formats = _build_custom_formats(generation_config)
|
466
476
|
|
467
477
|
seen_negative = coverage.HashSet()
|
468
478
|
seen_positive = coverage.HashSet()
|
@@ -474,7 +484,13 @@ def _iter_coverage_cases(
|
|
474
484
|
for value in find_matching_in_responses(responses, parameter.name):
|
475
485
|
schema.setdefault("examples", []).append(value)
|
476
486
|
gen = coverage.cover_schema_iter(
|
477
|
-
coverage.CoverageContext(
|
487
|
+
coverage.CoverageContext(
|
488
|
+
location=location,
|
489
|
+
generation_modes=generation_modes,
|
490
|
+
is_required=parameter.is_required,
|
491
|
+
custom_formats=custom_formats,
|
492
|
+
),
|
493
|
+
schema,
|
478
494
|
)
|
479
495
|
value = next(gen, NOT_SET)
|
480
496
|
if isinstance(value, NotSet):
|
@@ -492,7 +508,13 @@ def _iter_coverage_cases(
|
|
492
508
|
if examples:
|
493
509
|
schema.setdefault("examples", []).extend(examples)
|
494
510
|
gen = coverage.cover_schema_iter(
|
495
|
-
coverage.CoverageContext(
|
511
|
+
coverage.CoverageContext(
|
512
|
+
location="body",
|
513
|
+
generation_modes=generation_modes,
|
514
|
+
is_required=body.is_required,
|
515
|
+
custom_formats=custom_formats,
|
516
|
+
),
|
517
|
+
schema,
|
496
518
|
)
|
497
519
|
value = next(gen, NOT_SET)
|
498
520
|
if isinstance(value, NotSet):
|
@@ -712,11 +734,16 @@ def _iter_coverage_cases(
|
|
712
734
|
}
|
713
735
|
|
714
736
|
def _yield_negative(
|
715
|
-
subschema: dict[str, Any], _location: str, _container_name: str
|
737
|
+
subschema: dict[str, Any], _location: str, _container_name: str, is_required: bool
|
716
738
|
) -> Generator[Case, None, None]:
|
717
739
|
iterator = iter(
|
718
740
|
coverage.cover_schema_iter(
|
719
|
-
coverage.CoverageContext(
|
741
|
+
coverage.CoverageContext(
|
742
|
+
location=_location,
|
743
|
+
generation_modes=[GenerationMode.NEGATIVE],
|
744
|
+
is_required=is_required,
|
745
|
+
custom_formats=custom_formats,
|
746
|
+
),
|
720
747
|
subschema,
|
721
748
|
)
|
722
749
|
)
|
@@ -751,7 +778,7 @@ def _iter_coverage_cases(
|
|
751
778
|
)
|
752
779
|
if GenerationMode.NEGATIVE in generation_modes:
|
753
780
|
subschema = _combination_schema(only_required, required, parameter_set)
|
754
|
-
for case in _yield_negative(subschema, location, container_name):
|
781
|
+
for case in _yield_negative(subschema, location, container_name, is_required=bool(required)):
|
755
782
|
kwargs = _case_to_kwargs(case)
|
756
783
|
if not seen_negative.insert(kwargs):
|
757
784
|
continue
|
@@ -778,7 +805,7 @@ def _iter_coverage_cases(
|
|
778
805
|
)
|
779
806
|
if GenerationMode.NEGATIVE in generation_modes:
|
780
807
|
subschema = _combination_schema(combo, required, parameter_set)
|
781
|
-
for case in _yield_negative(subschema, location, container_name):
|
808
|
+
for case in _yield_negative(subschema, location, container_name, is_required=bool(required)):
|
782
809
|
assert case.meta is not None
|
783
810
|
assert isinstance(case.meta.phase.data, CoveragePhaseData)
|
784
811
|
# Already generated in one of the blocks above
|
schemathesis/openapi/checks.py
CHANGED
@@ -330,7 +330,7 @@ class AcceptedNegativeData(Failure):
|
|
330
330
|
message: str,
|
331
331
|
status_code: int,
|
332
332
|
expected_statuses: list[str],
|
333
|
-
title: str = "
|
333
|
+
title: str = "API accepted schema-violating request",
|
334
334
|
case_id: str | None = None,
|
335
335
|
) -> None:
|
336
336
|
self.operation = operation
|
@@ -358,7 +358,7 @@ class RejectedPositiveData(Failure):
|
|
358
358
|
message: str,
|
359
359
|
status_code: int,
|
360
360
|
allowed_statuses: list[str],
|
361
|
-
title: str = "
|
361
|
+
title: str = "API rejected schema-compliant request",
|
362
362
|
case_id: str | None = None,
|
363
363
|
) -> None:
|
364
364
|
self.operation = operation
|
@@ -423,10 +423,8 @@ def jsonify_python_specific_types(value: dict[str, Any]) -> dict[str, Any]:
|
|
423
423
|
return value
|
424
424
|
|
425
425
|
|
426
|
-
def _build_custom_formats(
|
427
|
-
custom_formats
|
428
|
-
) -> dict[str, st.SearchStrategy]:
|
429
|
-
custom_formats = {**get_default_format_strategies(), **STRING_FORMATS, **(custom_formats or {})}
|
426
|
+
def _build_custom_formats(generation_config: GenerationConfig) -> dict[str, st.SearchStrategy]:
|
427
|
+
custom_formats = {**get_default_format_strategies(), **STRING_FORMATS}
|
430
428
|
if generation_config.exclude_header_characters is not None:
|
431
429
|
custom_formats[HEADER_FORMAT] = header_values(exclude_characters=generation_config.exclude_header_characters)
|
432
430
|
elif not generation_config.allow_x00:
|
@@ -441,7 +439,6 @@ def make_positive_strategy(
|
|
441
439
|
media_type: str | None,
|
442
440
|
generation_config: GenerationConfig,
|
443
441
|
validator_cls: type[jsonschema.protocols.Validator],
|
444
|
-
custom_formats: dict[str, st.SearchStrategy] | None = None,
|
445
442
|
) -> st.SearchStrategy:
|
446
443
|
"""Strategy for generating values that fit the schema."""
|
447
444
|
if is_header_location(location):
|
@@ -451,7 +448,7 @@ def make_positive_strategy(
|
|
451
448
|
for sub_schema in schema.get("properties", {}).values():
|
452
449
|
if list(sub_schema) == ["type"] and sub_schema["type"] == "string":
|
453
450
|
sub_schema.setdefault("format", HEADER_FORMAT)
|
454
|
-
custom_formats = _build_custom_formats(
|
451
|
+
custom_formats = _build_custom_formats(generation_config)
|
455
452
|
return from_schema(
|
456
453
|
schema,
|
457
454
|
custom_formats=custom_formats,
|
@@ -472,9 +469,8 @@ def make_negative_strategy(
|
|
472
469
|
media_type: str | None,
|
473
470
|
generation_config: GenerationConfig,
|
474
471
|
validator_cls: type[jsonschema.protocols.Validator],
|
475
|
-
custom_formats: dict[str, st.SearchStrategy] | None = None,
|
476
472
|
) -> st.SearchStrategy:
|
477
|
-
custom_formats = _build_custom_formats(
|
473
|
+
custom_formats = _build_custom_formats(generation_config)
|
478
474
|
return negative_schema(
|
479
475
|
schema,
|
480
476
|
operation_name=operation_name,
|
@@ -240,7 +240,7 @@ def negative_data_rejection(ctx: CheckContext, response: Response, case: Case) -
|
|
240
240
|
):
|
241
241
|
raise AcceptedNegativeData(
|
242
242
|
operation=case.operation.label,
|
243
|
-
message=f"
|
243
|
+
message=f"Invalid data should have been rejected\nExpected: {', '.join(config.expected_statuses)}",
|
244
244
|
status_code=response.status_code,
|
245
245
|
expected_statuses=config.expected_statuses,
|
246
246
|
)
|
@@ -264,7 +264,7 @@ def positive_data_acceptance(ctx: CheckContext, response: Response, case: Case)
|
|
264
264
|
if case.meta.generation.mode.is_positive and response.status_code not in allowed_statuses:
|
265
265
|
raise RejectedPositiveData(
|
266
266
|
operation=case.operation.label,
|
267
|
-
message=f"
|
267
|
+
message=f"Valid data should have been accepted\nExpected: {', '.join(config.expected_statuses)}",
|
268
268
|
status_code=response.status_code,
|
269
269
|
allowed_statuses=config.expected_statuses,
|
270
270
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: schemathesis
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.5
|
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
|
@@ -72,26 +72,26 @@ schemathesis/engine/__init__.py,sha256=QaFE-FinaTAaarteADo2RRMJ-Sz6hZB9TzD5KjMin
|
|
72
72
|
schemathesis/engine/context.py,sha256=x-I9KX6rO6hdCvvN8FEdzIZBqIcNaxdNYHgQjcXbZhM,3931
|
73
73
|
schemathesis/engine/control.py,sha256=FXzP8dxL47j1Giqpy2-Bsr_MdMw9YiATSK_UfpFwDtk,1348
|
74
74
|
schemathesis/engine/core.py,sha256=5jfAqFH0XSD7NVgoSXuUPW-dooItscneAzUNq1RBh1E,5712
|
75
|
-
schemathesis/engine/errors.py,sha256=
|
75
|
+
schemathesis/engine/errors.py,sha256=HRtFFg-TQ68VmGAM3p6VLOimTU7VaFnv6iKD9-ucjaw,18932
|
76
76
|
schemathesis/engine/events.py,sha256=VV6epicFIJnX4c87fVNSd0ibDccX3gryDv52OUGa3FI,6370
|
77
77
|
schemathesis/engine/recorder.py,sha256=K3HfMARrT5mPWXPnYebjjcq5CcsBRhMrtZwEL9_Lvtg,8432
|
78
78
|
schemathesis/engine/phases/__init__.py,sha256=jUIfb_9QoUo4zmJEVU0z70PgXPYjt8CIqp4qP_HlYHg,3146
|
79
79
|
schemathesis/engine/phases/probes.py,sha256=SEtWKPdkLfRTKV0_tbiNHTK3sJsUUPZ0jZQ9Nv4qUi8,5678
|
80
80
|
schemathesis/engine/phases/stateful/__init__.py,sha256=Lz1rgNqCfUSIz173XqCGsiMuUI5bh4L-RIFexU1-c_Q,2461
|
81
|
-
schemathesis/engine/phases/stateful/_executor.py,sha256=
|
81
|
+
schemathesis/engine/phases/stateful/_executor.py,sha256=_303Yqflx1iFNTQI2EfjSp_2T21YvzJJgMSazhpv5JQ,15200
|
82
82
|
schemathesis/engine/phases/stateful/context.py,sha256=A7X1SLDOWFpCvFN9IiIeNVZM0emjqatmJL_k9UsO7vM,2946
|
83
83
|
schemathesis/engine/phases/unit/__init__.py,sha256=BvZh39LZmXg90Cy_Tn0cQY5y7eWzYvAEmJ43fGKFAt8,8715
|
84
|
-
schemathesis/engine/phases/unit/_executor.py,sha256=
|
84
|
+
schemathesis/engine/phases/unit/_executor.py,sha256=9MmZoKSBVSPk0LWwN3PZ3iaO9nzpT1Z70yzdEE48YYw,16489
|
85
85
|
schemathesis/engine/phases/unit/_pool.py,sha256=iU0hdHDmohPnEv7_S1emcabuzbTf-Cznqwn0pGQ5wNQ,2480
|
86
86
|
schemathesis/generation/__init__.py,sha256=tvNO2FLiY8z3fZ_kL_QJhSgzXfnT4UqwSXMHCwfLI0g,645
|
87
87
|
schemathesis/generation/case.py,sha256=MuqnKsJBpGm2gaqDFdJi1yGSWgBhqJUwtYaX97kfXgo,11820
|
88
|
-
schemathesis/generation/coverage.py,sha256=
|
88
|
+
schemathesis/generation/coverage.py,sha256=gf3kBAQAM5SoUS2k5e4UYIw-w6yvBtm_9KmdQyrhiss,49253
|
89
89
|
schemathesis/generation/meta.py,sha256=adkoMuCfzSjHJ9ZDocQn0GnVldSCkLL3eVR5A_jafwM,2552
|
90
90
|
schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
|
91
91
|
schemathesis/generation/modes.py,sha256=Q1fhjWr3zxabU5qdtLvKfpMFZJAwlW9pnxgenjeXTyU,481
|
92
92
|
schemathesis/generation/overrides.py,sha256=OBWqDQPreiliaf2M-oyXppVKHoJkCRzxtwSJx1b6AFw,3759
|
93
93
|
schemathesis/generation/hypothesis/__init__.py,sha256=SVwM-rx07jPZzms0idWYACgUtWAxh49HRuTnaQ__zf0,1549
|
94
|
-
schemathesis/generation/hypothesis/builder.py,sha256=
|
94
|
+
schemathesis/generation/hypothesis/builder.py,sha256=CURcKG1JamDNwMgZysMaqL5Mrbj0Hx3dgAxJHaB1ZAg,34102
|
95
95
|
schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
|
96
96
|
schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
|
97
97
|
schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
|
@@ -102,7 +102,7 @@ schemathesis/graphql/__init__.py,sha256=_eO6MAPHGgiADVGRntnwtPxmuvk666sAh-FAU4cG
|
|
102
102
|
schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzYo,3186
|
103
103
|
schemathesis/graphql/loaders.py,sha256=KarhFo2lDiC_1GcC2UGHl_MRDWAMMMWtE7sKrdbaJvo,9348
|
104
104
|
schemathesis/openapi/__init__.py,sha256=-KcsSAM19uOM0N5J4s-yTnQ1BFsptYhW1E51cEf6kVM,311
|
105
|
-
schemathesis/openapi/checks.py,sha256=
|
105
|
+
schemathesis/openapi/checks.py,sha256=VaQRxko6KwZL6saIzc4uUgJa_fj086O7Y6QFK8Zg-7A,12419
|
106
106
|
schemathesis/openapi/loaders.py,sha256=1jh4Me2dngWalBmX5xjfln90tfbH-afxmjsiY1BuUTE,10645
|
107
107
|
schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
108
108
|
schemathesis/openapi/generation/filters.py,sha256=pY9cUZdL_kQK80Z2aylTOqqa12zmaYUlYC5BfYgeQMk,2395
|
@@ -123,8 +123,8 @@ schemathesis/specs/graphql/schemas.py,sha256=ezkqgMwx37tMWlhy_I0ahDF1Q44emDSJkyj
|
|
123
123
|
schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzVfHxtdLkCPKM,1422
|
124
124
|
schemathesis/specs/openapi/__init__.py,sha256=C5HOsfuDJGq_3mv8CRBvRvb0Diy1p0BFdqyEXMS-loE,238
|
125
125
|
schemathesis/specs/openapi/_cache.py,sha256=HpglmETmZU0RCHxp3DO_sg5_B_nzi54Zuw9vGzzYCxY,4295
|
126
|
-
schemathesis/specs/openapi/_hypothesis.py,sha256=
|
127
|
-
schemathesis/specs/openapi/checks.py,sha256=
|
126
|
+
schemathesis/specs/openapi/_hypothesis.py,sha256=usufzl_VyBLgI6riTZ-pGqKnSLndw89GRIuCgCH9QiY,22366
|
127
|
+
schemathesis/specs/openapi/checks.py,sha256=0YiMoUy_wsnPvbOrsbnQ2iDxLloNe2-dc5-hnsst0ss,29863
|
128
128
|
schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
|
129
129
|
schemathesis/specs/openapi/converter.py,sha256=lil8IewM5j8tvt4lpA9g_KITvIwx1M96i45DNSHNjoc,3505
|
130
130
|
schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
|
@@ -157,8 +157,8 @@ schemathesis/transport/prepare.py,sha256=iiB8KTAqnnuqjWzblIPiGVdkGIF7Yr1SAEz-KZz
|
|
157
157
|
schemathesis/transport/requests.py,sha256=rziZTrZCVMAqgy6ldB8iTwhkpAsnjKSgK8hj5Sq3ThE,10656
|
158
158
|
schemathesis/transport/serialization.py,sha256=igUXKZ_VJ9gV7P0TUc5PDQBJXl_s0kK9T3ljGWWvo6E,10339
|
159
159
|
schemathesis/transport/wsgi.py,sha256=KoAfvu6RJtzyj24VGB8e-Iaa9smpgXJ3VsM8EgAz2tc,6152
|
160
|
-
schemathesis-4.0.
|
161
|
-
schemathesis-4.0.
|
162
|
-
schemathesis-4.0.
|
163
|
-
schemathesis-4.0.
|
164
|
-
schemathesis-4.0.
|
160
|
+
schemathesis-4.0.5.dist-info/METADATA,sha256=cIno0cKRp1ZT1ttNzK70yTrErPrGv7479Pc7dRTtDxI,8471
|
161
|
+
schemathesis-4.0.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
162
|
+
schemathesis-4.0.5.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
|
163
|
+
schemathesis-4.0.5.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
|
164
|
+
schemathesis-4.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|