schemathesis 4.0.0a4__py3-none-any.whl → 4.0.0a6__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/cli/commands/run/__init__.py +15 -45
- schemathesis/cli/commands/run/checks.py +2 -3
- schemathesis/cli/commands/run/context.py +30 -17
- schemathesis/cli/commands/run/executor.py +1 -0
- schemathesis/cli/commands/run/handlers/output.py +168 -88
- schemathesis/cli/commands/run/hypothesis.py +7 -45
- schemathesis/core/__init__.py +7 -1
- schemathesis/engine/config.py +2 -2
- schemathesis/engine/core.py +11 -1
- schemathesis/engine/events.py +7 -0
- schemathesis/engine/phases/__init__.py +16 -4
- schemathesis/engine/phases/unit/__init__.py +77 -52
- schemathesis/engine/phases/unit/_executor.py +14 -12
- schemathesis/engine/phases/unit/_pool.py +8 -0
- schemathesis/experimental/__init__.py +0 -6
- schemathesis/generation/hypothesis/builder.py +222 -97
- schemathesis/openapi/checks.py +3 -1
- schemathesis/pytest/lazy.py +41 -2
- schemathesis/pytest/plugin.py +2 -1
- schemathesis/specs/openapi/checks.py +1 -1
- schemathesis/specs/openapi/examples.py +39 -25
- schemathesis/specs/openapi/patterns.py +39 -7
- schemathesis/specs/openapi/serialization.py +14 -0
- schemathesis/transport/requests.py +10 -1
- {schemathesis-4.0.0a4.dist-info → schemathesis-4.0.0a6.dist-info}/METADATA +47 -91
- {schemathesis-4.0.0a4.dist-info → schemathesis-4.0.0a6.dist-info}/RECORD +29 -29
- {schemathesis-4.0.0a4.dist-info → schemathesis-4.0.0a6.dist-info}/licenses/LICENSE +1 -1
- {schemathesis-4.0.0a4.dist-info → schemathesis-4.0.0a6.dist-info}/WHEEL +0 -0
- {schemathesis-4.0.0a4.dist-info → schemathesis-4.0.0a6.dist-info}/entry_points.txt +0 -0
@@ -16,6 +16,7 @@ from schemathesis.generation.case import Case
|
|
16
16
|
from schemathesis.generation.hypothesis import examples
|
17
17
|
from schemathesis.generation.meta import TestPhase
|
18
18
|
from schemathesis.schemas import APIOperation
|
19
|
+
from schemathesis.specs.openapi.serialization import get_serializers_for_operation
|
19
20
|
|
20
21
|
from ._hypothesis import get_default_format_strategies, openapi_cases
|
21
22
|
from .constants import LOCATION_TO_CONTAINER
|
@@ -50,11 +51,7 @@ def get_strategies_from_examples(
|
|
50
51
|
operation: APIOperation[OpenAPIParameter], **kwargs: Any
|
51
52
|
) -> list[SearchStrategy[Case]]:
|
52
53
|
"""Build a set of strategies that generate test cases based on explicit examples in the schema."""
|
53
|
-
maps =
|
54
|
-
for location, container in LOCATION_TO_CONTAINER.items():
|
55
|
-
serializer = operation.get_parameter_serializer(location)
|
56
|
-
if serializer is not None:
|
57
|
-
maps[container] = serializer
|
54
|
+
maps = get_serializers_for_operation(operation)
|
58
55
|
|
59
56
|
def serialize_components(case: Case) -> Case:
|
60
57
|
"""Applies special serialization rules for case components.
|
@@ -402,45 +399,62 @@ def find_matching_in_responses(examples: dict[str, list], param: str) -> Iterato
|
|
402
399
|
if not isinstance(example, dict):
|
403
400
|
continue
|
404
401
|
# Unwrapping example from `{"item": [{...}]}`
|
405
|
-
if isinstance(example, dict)
|
406
|
-
inner =
|
407
|
-
if
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
402
|
+
if isinstance(example, dict):
|
403
|
+
inner = next((value for key, value in example.items() if key.lower() == schema_name.lower()), None)
|
404
|
+
if inner is not None:
|
405
|
+
if isinstance(inner, list):
|
406
|
+
for sub_example in inner:
|
407
|
+
if isinstance(sub_example, dict):
|
408
|
+
for found in _find_matching_in_responses(
|
409
|
+
sub_example, schema_name, param, normalized, is_id_param
|
410
|
+
):
|
411
|
+
if found is not NOT_FOUND:
|
412
|
+
yield found
|
413
|
+
continue
|
414
|
+
if isinstance(inner, dict):
|
415
|
+
example = inner
|
416
|
+
for found in _find_matching_in_responses(example, schema_name, param, normalized, is_id_param):
|
417
|
+
if found is not NOT_FOUND:
|
418
|
+
yield found
|
418
419
|
|
419
420
|
|
420
421
|
def _find_matching_in_responses(
|
421
422
|
example: dict[str, Any], schema_name: str, param: str, normalized: str, is_id_param: bool
|
422
|
-
) -> Any:
|
423
|
+
) -> Iterator[Any]:
|
423
424
|
# Check for exact match
|
424
425
|
if param in example:
|
425
|
-
|
426
|
+
yield example[param]
|
427
|
+
return
|
426
428
|
if is_id_param and param[:-2] in example:
|
427
|
-
|
429
|
+
value = example[param[:-2]]
|
430
|
+
if isinstance(value, list):
|
431
|
+
for sub_example in value:
|
432
|
+
for found in _find_matching_in_responses(sub_example, schema_name, param, normalized, is_id_param):
|
433
|
+
if found is not NOT_FOUND:
|
434
|
+
yield found
|
435
|
+
return
|
436
|
+
else:
|
437
|
+
yield value
|
438
|
+
return
|
428
439
|
|
429
440
|
# Check for case-insensitive match
|
430
441
|
for key in example:
|
431
442
|
if key.lower() == normalized:
|
432
|
-
|
443
|
+
yield example[key]
|
444
|
+
return
|
433
445
|
else:
|
434
446
|
# If no match found and it's an ID parameter, try additional checks
|
435
447
|
if is_id_param:
|
436
448
|
# Check for 'id' if parameter is '{something}Id'
|
437
449
|
if "id" in example:
|
438
|
-
|
450
|
+
yield example["id"]
|
451
|
+
return
|
439
452
|
# Check for '{schemaName}Id' or '{schemaName}_id'
|
440
453
|
if normalized == "id" or normalized.startswith(schema_name.lower()):
|
441
454
|
for key in (schema_name, schema_name.lower()):
|
442
455
|
for suffix in ("_id", "Id"):
|
443
456
|
with_suffix = f"{key}{suffix}"
|
444
457
|
if with_suffix in example:
|
445
|
-
|
446
|
-
|
458
|
+
yield example[with_suffix]
|
459
|
+
return
|
460
|
+
yield NOT_FOUND
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
3
3
|
import re
|
4
4
|
from functools import lru_cache
|
5
5
|
|
6
|
+
from schemathesis.core.errors import InternalError
|
7
|
+
|
6
8
|
try: # pragma: no cover
|
7
9
|
import re._constants as sre
|
8
10
|
import re._parser as sre_parse
|
@@ -29,7 +31,15 @@ def update_quantifier(pattern: str, min_length: int | None, max_length: int | No
|
|
29
31
|
|
30
32
|
try:
|
31
33
|
parsed = sre_parse.parse(pattern)
|
32
|
-
|
34
|
+
updated = _handle_parsed_pattern(parsed, pattern, min_length, max_length)
|
35
|
+
try:
|
36
|
+
re.compile(updated)
|
37
|
+
except re.error as exc:
|
38
|
+
raise InternalError(
|
39
|
+
f"The combination of min_length={min_length} and max_length={max_length} applied to the original pattern '{pattern}' resulted in an invalid regex: '{updated}'. "
|
40
|
+
"This indicates a bug in the regex quantifier merging logic"
|
41
|
+
) from exc
|
42
|
+
return updated
|
33
43
|
except re.error:
|
34
44
|
# Invalid pattern
|
35
45
|
return pattern
|
@@ -114,6 +124,21 @@ def _handle_anchored_pattern(parsed: list, pattern: str, min_length: int | None,
|
|
114
124
|
|
115
125
|
for op, value in pattern_parts:
|
116
126
|
if op == LITERAL:
|
127
|
+
# Check if the literal comes from a bracketed expression,
|
128
|
+
# e.g. Python regex parses "[+]" as a single LITERAL token.
|
129
|
+
if pattern[current_position] == "[":
|
130
|
+
# Find the matching closing bracket.
|
131
|
+
end_idx = current_position + 1
|
132
|
+
while end_idx < len(pattern):
|
133
|
+
# Check for an unescaped closing bracket.
|
134
|
+
if pattern[end_idx] == "]" and (end_idx == current_position + 1 or pattern[end_idx - 1] != "\\"):
|
135
|
+
end_idx += 1
|
136
|
+
break
|
137
|
+
end_idx += 1
|
138
|
+
# Append the entire character set.
|
139
|
+
result += pattern[current_position:end_idx]
|
140
|
+
current_position = end_idx
|
141
|
+
continue
|
117
142
|
if pattern[current_position] == "\\":
|
118
143
|
# Escaped value
|
119
144
|
current_position += 2
|
@@ -261,13 +286,18 @@ def _handle_repeat_quantifier(
|
|
261
286
|
min_length, max_length = _build_size(min_repeat, max_repeat, min_length, max_length)
|
262
287
|
if min_length > max_length:
|
263
288
|
return pattern
|
264
|
-
|
289
|
+
inner = _strip_quantifier(pattern)
|
290
|
+
if inner.startswith("(") and inner.endswith(")"):
|
291
|
+
inner = inner[1:-1]
|
292
|
+
return f"({inner})" + _build_quantifier(min_length, max_length)
|
265
293
|
|
266
294
|
|
267
295
|
def _handle_literal_or_in_quantifier(pattern: str, min_length: int | None, max_length: int | None) -> str:
|
268
296
|
"""Handle literal or character class quantifiers."""
|
269
297
|
min_length = 1 if min_length is None else max(min_length, 1)
|
270
|
-
|
298
|
+
if pattern.startswith("(") and pattern.endswith(")"):
|
299
|
+
pattern = pattern[1:-1]
|
300
|
+
return f"({pattern})" + _build_quantifier(min_length, max_length)
|
271
301
|
|
272
302
|
|
273
303
|
def _build_quantifier(minimum: int | None, maximum: int | None) -> str:
|
@@ -294,10 +324,12 @@ def _build_size(min_repeat: int, max_repeat: int, min_length: int | None, max_le
|
|
294
324
|
def _strip_quantifier(pattern: str) -> str:
|
295
325
|
"""Remove quantifier from the pattern."""
|
296
326
|
# Lazy & posessive quantifiers
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
327
|
+
for marker in ("*?", "+?", "??", "*+", "?+", "++"):
|
328
|
+
if pattern.endswith(marker) and not pattern.endswith(rf"\{marker}"):
|
329
|
+
return pattern[:-2]
|
330
|
+
for marker in ("?", "*", "+"):
|
331
|
+
if pattern.endswith(marker) and not pattern.endswith(rf"\{marker}"):
|
332
|
+
pattern = pattern[:-1]
|
301
333
|
if pattern.endswith("}") and "{" in pattern:
|
302
334
|
# Find the start of the exact quantifier and drop everything since that index
|
303
335
|
idx = pattern.rfind("{")
|
@@ -3,12 +3,24 @@ from __future__ import annotations
|
|
3
3
|
import json
|
4
4
|
from typing import Any, Callable, Dict, Generator, List
|
5
5
|
|
6
|
+
from schemathesis.schemas import APIOperation
|
7
|
+
from schemathesis.specs.openapi.constants import LOCATION_TO_CONTAINER
|
8
|
+
|
6
9
|
Generated = Dict[str, Any]
|
7
10
|
Definition = Dict[str, Any]
|
8
11
|
DefinitionList = List[Definition]
|
9
12
|
MapFunction = Callable[[Generated], Generated]
|
10
13
|
|
11
14
|
|
15
|
+
def get_serializers_for_operation(operation: APIOperation) -> dict[str, Callable]:
|
16
|
+
serializers = {}
|
17
|
+
for location, container in LOCATION_TO_CONTAINER.items():
|
18
|
+
serializer = operation.get_parameter_serializer(location)
|
19
|
+
if serializer is not None:
|
20
|
+
serializers[container] = serializer
|
21
|
+
return serializers
|
22
|
+
|
23
|
+
|
12
24
|
def make_serializer(
|
13
25
|
func: Callable[[DefinitionList], Generator[Callable | None, None, None]],
|
14
26
|
) -> Callable[[DefinitionList], Callable | None]:
|
@@ -16,6 +28,8 @@ def make_serializer(
|
|
16
28
|
|
17
29
|
def _wrapper(definitions: DefinitionList) -> Callable | None:
|
18
30
|
functions = list(func(definitions))
|
31
|
+
if not functions:
|
32
|
+
return None
|
19
33
|
|
20
34
|
def composed(x: Any) -> Any:
|
21
35
|
result = x
|
@@ -56,12 +56,21 @@ class RequestsTransport(BaseTransport["Case", Response, "requests.Session"]):
|
|
56
56
|
for key, value in additional_headers.items():
|
57
57
|
final_headers.setdefault(key, value)
|
58
58
|
|
59
|
+
params = case.query
|
60
|
+
|
61
|
+
# Replace empty dictionaries with empty strings, so the parameters actually present in the query string
|
62
|
+
if any(value == {} for value in (params or {}).values()):
|
63
|
+
params = deepclone(params)
|
64
|
+
for key, value in params.items():
|
65
|
+
if value == {}:
|
66
|
+
params[key] = ""
|
67
|
+
|
59
68
|
data = {
|
60
69
|
"method": case.method,
|
61
70
|
"url": url,
|
62
71
|
"cookies": case.cookies,
|
63
72
|
"headers": final_headers,
|
64
|
-
"params":
|
73
|
+
"params": params,
|
65
74
|
**extra,
|
66
75
|
}
|
67
76
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: schemathesis
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.0a6
|
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
|
@@ -117,81 +117,47 @@ Description-Content-Type: text/markdown
|
|
117
117
|
|
118
118
|
## Schemathesis
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
> This branch is under active development, with substantial changes expected before stabilization. While V4 is fully functional and passing tests, some features are missing, and the documentation may be outdated.
|
123
|
-
|
124
|
-
> For the stable release, see the [V3 branch](https://github.com/schemathesis/schemathesis/tree/v3).
|
125
|
-
|
126
|
-
> 💡 Have feedback? Share your thoughts in [this discussion](https://github.com/schemathesis/schemathesis/discussions/2677)!
|
127
|
-
|
128
|
-
Schemathesis is an API testing tool that automatically finds crashes and validates spec compliance.
|
120
|
+
Schemathesis automatically generates and runs API tests from your OpenAPI or GraphQL schema to find bugs and spec violations.
|
129
121
|
|
130
122
|
<p align="center">
|
131
|
-
<img src="https://raw.githubusercontent.com/schemathesis/schemathesis/master/img/demo.gif" alt="Schemathesis
|
123
|
+
<img src="https://raw.githubusercontent.com/schemathesis/schemathesis/master/img/demo.gif" alt="Schemathesis automatically finding a server error"/>
|
124
|
+
<br>
|
125
|
+
<i>Automatically finding specification violations and server errors</i>
|
132
126
|
</p>
|
133
127
|
|
134
|
-
|
135
|
-
<i>Finding server crashes in the Demo API.</i>
|
136
|
-
</p>
|
137
|
-
|
138
|
-
### Highlights
|
139
|
-
|
140
|
-
🎯 **Catches Hard-to-Find Bugs**
|
141
|
-
|
142
|
-
- Uncover hidden crashes and edge cases that manual testing might miss
|
143
|
-
- Identify spec violations and ensure your API adheres to its contract
|
144
|
-
|
145
|
-
⚡ **Accelerates Testing Cycles**
|
146
|
-
|
147
|
-
- Automatically generate a wide range of test cases based on your API schema
|
148
|
-
- Save time by reducing the need for manual test case creation
|
128
|
+
> **Note:** This is the V4 branch under active development. While fully functional and passing tests, some features may be missing, and documentation is being updated. For the stable release, see the [V3 branch](https://github.com/schemathesis/schemathesis/tree/v3).
|
149
129
|
|
150
|
-
|
130
|
+
## Why Schemathesis?
|
151
131
|
|
152
|
-
-
|
153
|
-
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
- Tune the testing process using Python extensions.
|
158
|
-
- Adjust the testing flow to suit your needs with rich configuration options.
|
159
|
-
|
160
|
-
🐞 **Simplifies Debugging**
|
161
|
-
|
162
|
-
- Get detailed reports to identify and fix issues quickly.
|
163
|
-
- Reproduce failing test cases with cURL commands.
|
164
|
-
|
165
|
-
🔬 **Proven by Research**
|
166
|
-
|
167
|
-
- Validated through academic studies on API testing automation
|
168
|
-
- Featured in [ICSE 2022 paper](https://ieeexplore.ieee.org/document/9793781) on semantics-aware fuzzing
|
169
|
-
- Recognized in [ACM survey](https://dl.acm.org/doi/10.1145/3617175) as state-of-the-art RESTful API testing tool
|
132
|
+
- 📑 **Schema-Based Testing** - Transform API documentation into a comprehensive test suite
|
133
|
+
- 🚀 **Zero Configuration** - Begin testing immediately with a valid OpenAPI or GraphQL schema
|
134
|
+
- ⚙️ **CI-Ready** - Integrate API testing into existing pipelines without complex configuration
|
135
|
+
- 🛡️ **Effective Coverage** - Find edge cases no manual testing could uncover
|
136
|
+
- 🔬 **Research-Backed**: [Recognized](https://dl.acm.org/doi/10.1145/3617175) in [academic research](https://ieeexplore.ieee.org/document/9793781) as a state-of-the-art API testing tool
|
170
137
|
|
171
138
|
## Installation
|
172
139
|
|
173
|
-
Use Schemathesis via Docker, or install it from [PyPI](https://pypi.org/project/schemathesis/)
|
174
|
-
|
175
140
|
```console
|
176
|
-
#
|
177
|
-
$
|
141
|
+
# Using uv (recommended)
|
142
|
+
$ uv pip install schemathesis
|
178
143
|
|
179
|
-
#
|
144
|
+
# Using pip
|
180
145
|
$ pip install schemathesis
|
146
|
+
|
147
|
+
# Using Docker
|
148
|
+
$ docker pull schemathesis/schemathesis:stable
|
181
149
|
```
|
182
150
|
|
183
|
-
##
|
151
|
+
## Usage
|
184
152
|
|
185
|
-
|
153
|
+
### Command Line
|
186
154
|
|
187
155
|
```console
|
188
|
-
|
189
|
-
|
190
|
-
# Or when installed with pip
|
191
|
-
schemathesis run --checks all https://example.schemathesis.io/openapi.json
|
156
|
+
# Run tests against a schema URL
|
157
|
+
$ st run https://example.schemathesis.io/openapi.json
|
192
158
|
```
|
193
159
|
|
194
|
-
|
160
|
+
### Python Library
|
195
161
|
|
196
162
|
```python
|
197
163
|
import schemathesis
|
@@ -204,36 +170,35 @@ def test_api(case):
|
|
204
170
|
case.call_and_validate()
|
205
171
|
```
|
206
172
|
|
207
|
-
|
208
|
-
|
209
|
-
Schemathesis can be easily integrated into your CI/CD pipeline using GitHub Actions. Add this block to your GitHub Actions to run Schemathesis against your API:
|
173
|
+
### CI/CD Integration
|
210
174
|
|
211
175
|
```yaml
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
schema: "https://example.schemathesis.io/openapi.json"
|
176
|
+
# GitHub Actions example
|
177
|
+
steps:
|
178
|
+
- uses: schemathesis/action@v1
|
179
|
+
with:
|
180
|
+
schema: "https://example.schemathesis.io/openapi.json"
|
218
181
|
```
|
219
182
|
|
220
|
-
|
183
|
+
## Documentation
|
184
|
+
|
185
|
+
📚 **[Read the full documentation](https://schemathesis.readthedocs.io/)** for guides, examples, and reference material.
|
221
186
|
|
222
187
|
## Who's Using Schemathesis?
|
223
188
|
|
224
|
-
Schemathesis is used by
|
189
|
+
Schemathesis is used by companies and open-source projects including:
|
225
190
|
|
226
|
-
- Abstract Machines ([Magistrala](https://github.com/absmach/magistrala))
|
227
|
-
- Bundesstelle für Open Data ([smard-api](https://github.com/bundesAPI/smard-api))
|
228
|
-
- [CheckMK](https://github.com/Checkmk/checkmk)
|
229
|
-
- Chronosphere.io ([Calyptia](https://github.com/chronosphereio/calyptia-api))
|
230
|
-
- HXSecurity ([DongTai](https://github.com/HXSecurity/DongTai))
|
231
191
|
- Netflix ([Dispatch](https://github.com/Netflix/dispatch))
|
232
|
-
- [Pixie](https://github.com/pixie-io/pixie)
|
233
|
-
- [Qdrant](https://github.com/qdrant/qdrant)
|
234
192
|
- Spotify ([Backstage](https://github.com/backstage/backstage))
|
235
|
-
- [Weechat](https://github.com/weechat/weechat)
|
236
193
|
- WordPress ([OpenVerse](https://github.com/WordPress/openverse))
|
194
|
+
- Chronosphere.io ([Calyptia](https://github.com/chronosphereio/calyptia-api))
|
195
|
+
- [Qdrant](https://github.com/qdrant/qdrant)
|
196
|
+
- [Pixie](https://github.com/pixie-io/pixie)
|
197
|
+
- [CheckMK](https://github.com/Checkmk/checkmk)
|
198
|
+
- [Weechat](https://github.com/weechat/weechat)
|
199
|
+
- HXSecurity ([DongTai](https://github.com/HXSecurity/DongTai))
|
200
|
+
- Abstract Machines ([Magistrala](https://github.com/absmach/magistrala))
|
201
|
+
- Bundesstelle für Open Data ([smard-api](https://github.com/bundesAPI/smard-api))
|
237
202
|
|
238
203
|
## Testimonials
|
239
204
|
|
@@ -249,7 +214,7 @@ Schemathesis is used by a number of projects and companies, including direct usa
|
|
249
214
|
|
250
215
|
---
|
251
216
|
|
252
|
-
"_The tool is
|
217
|
+
"_The tool is amazing as it can test negative scenarios instead of me and much faster!_"
|
253
218
|
|
254
219
|
<div>Luděk Nový - <strong>JetBrains</strong></div>
|
255
220
|
|
@@ -269,24 +234,15 @@ Schemathesis is used by a number of projects and companies, including direct usa
|
|
269
234
|
|
270
235
|
## Contributing
|
271
236
|
|
272
|
-
We welcome contributions
|
273
|
-
|
274
|
-
### How to Contribute
|
275
|
-
|
276
|
-
1. Discuss ideas and questions through [GitHub issues](https://github.com/schemathesis/schemathesis/issues) or on our [Discord channel](https://discord.gg/R9ASRAmHnA).
|
277
|
-
2. For code contributions, see our [contributing guidelines](https://github.com/schemathesis/schemathesis/blob/master/CONTRIBUTING.rst).
|
278
|
-
3. Share your experience and thoughts using [this feedback form](https://forms.gle/kJ4hSxc1Yp6Ga96t5).
|
279
|
-
|
280
|
-
### Why Your Input Matters
|
281
|
-
|
282
|
-
- Enables us to develop useful features and fix bugs faster
|
283
|
-
- Improves our test suite and documentation
|
237
|
+
We welcome contributions! Your input directly influences Schemathesis development.
|
284
238
|
|
285
|
-
|
239
|
+
- Discuss ideas in [GitHub issues](https://github.com/schemathesis/schemathesis/issues) or our [Discord server](https://discord.gg/R9ASRAmHnA)
|
240
|
+
- See our [contributing guidelines](https://github.com/schemathesis/schemathesis/blob/master/CONTRIBUTING.rst) for code contributions
|
241
|
+
- Share your experience using [this feedback form](https://forms.gle/kJ4hSxc1Yp6Ga96t5)
|
286
242
|
|
287
243
|
## Get in Touch
|
288
244
|
|
289
|
-
|
245
|
+
Need assistance with integration or have specific questions? Contact us at <a href="mailto:support@schemathesis.io">support@schemathesis.io</a>.
|
290
246
|
|
291
247
|
## Acknowledgements
|
292
248
|
|
@@ -12,13 +12,13 @@ schemathesis/cli/constants.py,sha256=rUixnqorraUFDtOu3Nmm1x_k0qbgmW9xW96kQB_fBCQ
|
|
12
12
|
schemathesis/cli/core.py,sha256=Qm5xvpIIMwJDTeR3N3TjKhMCHV5d5Rp0UstVS2GjWgw,459
|
13
13
|
schemathesis/cli/hooks.py,sha256=vTrA8EN99whRns5K5AnExViQ6WL9cak5RGsC-ZBEiJM,1458
|
14
14
|
schemathesis/cli/commands/__init__.py,sha256=FFalEss3D7mnCRO0udtYb65onXSjQCCOv8sOSjqvTTM,1059
|
15
|
-
schemathesis/cli/commands/run/__init__.py,sha256=
|
16
|
-
schemathesis/cli/commands/run/checks.py,sha256
|
17
|
-
schemathesis/cli/commands/run/context.py,sha256=
|
15
|
+
schemathesis/cli/commands/run/__init__.py,sha256=pLuXYxgO0z1CLZH_2P_uW8xeGOy1S2VtxLnNqKXanHk,23138
|
16
|
+
schemathesis/cli/commands/run/checks.py,sha256=lLtBCt6NhhQisrWo8aC6i0M3dSXlbjGWTTlOyjzatks,3278
|
17
|
+
schemathesis/cli/commands/run/context.py,sha256=pUwSlS7UwW2cq1nJXfKZFEaWDipsQAElCO4tdv1qYJA,7739
|
18
18
|
schemathesis/cli/commands/run/events.py,sha256=Dj-xvIr-Hkms8kvh4whNwKSk1Q2Hx4NIENi_4A8nQO8,1224
|
19
|
-
schemathesis/cli/commands/run/executor.py,sha256=
|
19
|
+
schemathesis/cli/commands/run/executor.py,sha256=lKQZswH7vLsKCUNdDL8IOwJYsUicyPxRJ3vXOi1pwAk,5446
|
20
20
|
schemathesis/cli/commands/run/filters.py,sha256=MdymOZtzOolvXCNBIdfHbBbWEXVF7Se0mmDpy3sVWu4,7411
|
21
|
-
schemathesis/cli/commands/run/hypothesis.py,sha256=
|
21
|
+
schemathesis/cli/commands/run/hypothesis.py,sha256=hdEHim_Hc2HwCGxAiRTf4t2OfQf0IeCUhyjNT_btB1o,2553
|
22
22
|
schemathesis/cli/commands/run/loaders.py,sha256=VedoeIE1tgFBqVokWxOoUReAjBl-Zhx87RjCEBtCVfs,4840
|
23
23
|
schemathesis/cli/commands/run/reports.py,sha256=OjyakiV0lpNDBZb1xsb_2HmLtcqhTThPYMpJGXyNNO8,2147
|
24
24
|
schemathesis/cli/commands/run/validation.py,sha256=7fvLeDREQ9FTV8ZMJRnCdycD858j21k7j56ow4_iIcY,12789
|
@@ -26,7 +26,7 @@ schemathesis/cli/commands/run/handlers/__init__.py,sha256=TPZ3KdGi8m0fjlN0GjA31M
|
|
26
26
|
schemathesis/cli/commands/run/handlers/base.py,sha256=yDsTtCiztLksfk7cRzg8JlaAVOfS-zwK3tsJMOXAFyc,530
|
27
27
|
schemathesis/cli/commands/run/handlers/cassettes.py,sha256=SVk13xPhsQduCpgvvBwzEMDNTju-SHQCW90xTQ6iL1U,18525
|
28
28
|
schemathesis/cli/commands/run/handlers/junitxml.py,sha256=c24UiwXqRCnv2eWQWEaNXLOghMI9JtGoZ9RTJY4ao6M,2350
|
29
|
-
schemathesis/cli/commands/run/handlers/output.py,sha256=
|
29
|
+
schemathesis/cli/commands/run/handlers/output.py,sha256=n25QDGvYMXPKRPHBDckkDVwkkieY3Gq4HHSG0h3paTA,58800
|
30
30
|
schemathesis/cli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
31
|
schemathesis/cli/ext/fs.py,sha256=OA3mRzra4rq3NyDTcBvlRh0WJrh4ByN-QQ8loI04m88,408
|
32
32
|
schemathesis/cli/ext/groups.py,sha256=kQ37t6qeArcKaY2y5VxyK3_KwAkBKCVm58IYV8gewds,2720
|
@@ -34,7 +34,7 @@ schemathesis/cli/ext/options.py,sha256=gBjfYPoiSoxCymWq41x0oKcQ2frv1fQnweETVpYiI
|
|
34
34
|
schemathesis/contrib/__init__.py,sha256=wxpX86xrEGRAS3f7eugQfKVbnqV6ZfOqFBS_DmWxOok,120
|
35
35
|
schemathesis/contrib/openapi/__init__.py,sha256=-7mBZ9RQj0EGzzmC-HKiT5ZslwHcoWFqCVpRG0GHO_o,162
|
36
36
|
schemathesis/contrib/openapi/fill_missing_examples.py,sha256=BfBpuy3vCKbE_uILqPXnm7kxEDopAr5tNQwP5E9xX8A,585
|
37
|
-
schemathesis/core/__init__.py,sha256=
|
37
|
+
schemathesis/core/__init__.py,sha256=4SLVPpUZgZYABL6QPVRtanMemibKxTQEYcp4LFu4Jco,1761
|
38
38
|
schemathesis/core/compat.py,sha256=Lflo6z-nQ6S4uKZINc4Fr90pd3LTN6cIG9HJJmmaHeY,754
|
39
39
|
schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
|
40
40
|
schemathesis/core/curl.py,sha256=yuaCe_zHLGwUjEeloQi6W3tOA3cGdnHDNI17-5jia0o,1723
|
@@ -56,22 +56,22 @@ schemathesis/core/version.py,sha256=O-6yFbNocbD4RDwiBZLborxTp54htyKxBWTqpZDnPvg,
|
|
56
56
|
schemathesis/core/output/__init__.py,sha256=lhVc4OzzxCsmvEPPvg1k8x19iPf_HF-9YonTaqsxvx8,2015
|
57
57
|
schemathesis/core/output/sanitization.py,sha256=EODHJMHD8gqlIA0Yqs1OnElZ2JyNxjvQ0WWErZV1K3s,6210
|
58
58
|
schemathesis/engine/__init__.py,sha256=xncZMXY8S-v4mrfnW4CK6-RQ0S0bigfLDJScpQysblE,831
|
59
|
-
schemathesis/engine/config.py,sha256=
|
59
|
+
schemathesis/engine/config.py,sha256=92Ud_aSTj-xi4Mwf8gej_gcvzjemH_ISjHQiXGGKskA,1885
|
60
60
|
schemathesis/engine/context.py,sha256=HeLX-0aqSAbXJe_ZlkqVfg3QlhmbCrazbb9-ZPbi0h0,3723
|
61
61
|
schemathesis/engine/control.py,sha256=QKUOs5VMphe7EcAIro_DDo9ZqdOU6ZVwTU1gMNndHWw,1006
|
62
|
-
schemathesis/engine/core.py,sha256=
|
62
|
+
schemathesis/engine/core.py,sha256=DfulRMVTivmZj-wwLekIhuSzLsFnuVPtSg7j9HyWdz0,5536
|
63
63
|
schemathesis/engine/errors.py,sha256=8PHYsuq2qIEJHm2FDf_UnWa4IDc-DRFTPckLAr22yhE,16895
|
64
|
-
schemathesis/engine/events.py,sha256=
|
64
|
+
schemathesis/engine/events.py,sha256=gslRAWQKMPqBCQzLDS4wAbsKcVuONSy5SPqimJJJYT4,6250
|
65
65
|
schemathesis/engine/recorder.py,sha256=K3HfMARrT5mPWXPnYebjjcq5CcsBRhMrtZwEL9_Lvtg,8432
|
66
|
-
schemathesis/engine/phases/__init__.py,sha256=
|
66
|
+
schemathesis/engine/phases/__init__.py,sha256=3p_T3JYBFOtrwtgmMM7J-6a41QJgk83dUtm7NKcVl3o,2490
|
67
67
|
schemathesis/engine/phases/probes.py,sha256=3M9g3E7CXbDDK_8inuvkRZibCCcoO2Ce5U3lnyTeWXQ,5131
|
68
68
|
schemathesis/engine/phases/stateful/__init__.py,sha256=lWo2RLrutNblHvohTzofQqL22GORwBRA8bf6jvLuGPg,2391
|
69
69
|
schemathesis/engine/phases/stateful/_executor.py,sha256=m1ZMqFUPc4Hdql10l0gF3tpP4JOImSA-XeBd4jg3Ll8,12443
|
70
70
|
schemathesis/engine/phases/stateful/context.py,sha256=SKWsok-tlWbUDagiUmP7cLNW6DsgFDc_Afv0vQfWv6c,2964
|
71
|
-
schemathesis/engine/phases/unit/__init__.py,sha256=
|
72
|
-
schemathesis/engine/phases/unit/_executor.py,sha256=
|
73
|
-
schemathesis/engine/phases/unit/_pool.py,sha256=
|
74
|
-
schemathesis/experimental/__init__.py,sha256=
|
71
|
+
schemathesis/engine/phases/unit/__init__.py,sha256=LcBQpGNPeEFB9XPGpcHBcH-C7nF-e8bZNPop9PIfiKA,7861
|
72
|
+
schemathesis/engine/phases/unit/_executor.py,sha256=buMEr7e01SFSeNuEQNGMf4hoiLxX9_sp0JhH4LBAk9M,12928
|
73
|
+
schemathesis/engine/phases/unit/_pool.py,sha256=9OgmFd-ov1AAvcZGquK40PXkGLp7f2qCjZoPZuoZl4A,2529
|
74
|
+
schemathesis/experimental/__init__.py,sha256=jYY3Mq6okqTRTMudPzcaT0JVjzJW5IN_ZVJdGU0stBs,2011
|
75
75
|
schemathesis/generation/__init__.py,sha256=2htA0TlQee6AvQmLl1VNxEptRDqvPjksXKJLMVLAJng,1580
|
76
76
|
schemathesis/generation/case.py,sha256=Rt5MCUtPVYVQzNyjUx8magocPJpHV1svyuqQSTwUE-I,7306
|
77
77
|
schemathesis/generation/coverage.py,sha256=hyDb465tBoCWE7nI-ZJjhTUzk7f2WDufaadWdSAkdr0,39276
|
@@ -80,7 +80,7 @@ schemathesis/generation/modes.py,sha256=t_EvKr2aOXYMsEfdMu4lLF4KCGcX1LVVyvzTkcpJ
|
|
80
80
|
schemathesis/generation/overrides.py,sha256=FhqcFoliEvgW6MZyFPYemfLgzKt3Miy8Cud7OMOCb7g,3045
|
81
81
|
schemathesis/generation/targets.py,sha256=_rN2qgxTE2EfvygiN-Fy3WmDnRH0ERohdx3sKRDaYhU,2120
|
82
82
|
schemathesis/generation/hypothesis/__init__.py,sha256=Rl7QwvMBMJI7pBqTydplX6bXC420n0EGQHVm-vZgaYQ,1204
|
83
|
-
schemathesis/generation/hypothesis/builder.py,sha256=
|
83
|
+
schemathesis/generation/hypothesis/builder.py,sha256=lAxBePbfqGsp6iPjjXeDL-X8RnOgUhsgpYQpeKc1VKg,29292
|
84
84
|
schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
|
85
85
|
schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
|
86
86
|
schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
|
@@ -91,15 +91,15 @@ schemathesis/graphql/__init__.py,sha256=_eO6MAPHGgiADVGRntnwtPxmuvk666sAh-FAU4cG
|
|
91
91
|
schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzYo,3186
|
92
92
|
schemathesis/graphql/loaders.py,sha256=96R_On1jFvsNuLwqXnO3_TTpsYhdCv0LAmR5jWRXXnY,4756
|
93
93
|
schemathesis/openapi/__init__.py,sha256=-KcsSAM19uOM0N5J4s-yTnQ1BFsptYhW1E51cEf6kVM,311
|
94
|
-
schemathesis/openapi/checks.py,sha256=
|
94
|
+
schemathesis/openapi/checks.py,sha256=i26qtVqsNUb46Aqu191qWK5lVC51KK6ezbhm1rSSyr4,10781
|
95
95
|
schemathesis/openapi/loaders.py,sha256=jskoCnMgpjg_cpn17FRI4oDUpMdsMYjxfXdRPHYnPqs,6472
|
96
96
|
schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
97
97
|
schemathesis/openapi/generation/filters.py,sha256=MB2t_k6OVc2Rt6qXUrV-u-3sDg5wX6c0Mli9WgfMUF4,2001
|
98
98
|
schemathesis/pytest/__init__.py,sha256=7W0q-Thcw03IAQfXE_Mo8JPZpUdHJzfu85fjK1ZdfQM,88
|
99
99
|
schemathesis/pytest/control_flow.py,sha256=F8rAPsPeNv_sJiJgbZYtTpwKWjauZmqFUaKroY2GmQI,217
|
100
|
-
schemathesis/pytest/lazy.py,sha256=
|
100
|
+
schemathesis/pytest/lazy.py,sha256=g7DpOeQNsjXC03FCG5e1L65iz3zE48qAyaqG81HzCZY,12028
|
101
101
|
schemathesis/pytest/loaders.py,sha256=oQJ78yyuIm3Ye9X7giVjDB1vYfaW5UY5YuhaTLm_ZFU,266
|
102
|
-
schemathesis/pytest/plugin.py,sha256=
|
102
|
+
schemathesis/pytest/plugin.py,sha256=RDOuT25Uotese7W-SD3Pu-nb7zdnaPbyPOoJSkJKSoQ,12379
|
103
103
|
schemathesis/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
104
104
|
schemathesis/python/asgi.py,sha256=5PyvuTBaivvyPUEi3pwJni91K1kX5Zc0u9c6c1D8a1Q,287
|
105
105
|
schemathesis/python/wsgi.py,sha256=uShAgo_NChbfYaV1117e6UHp0MTg7jaR0Sy_to3Jmf8,219
|
@@ -113,19 +113,19 @@ schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzV
|
|
113
113
|
schemathesis/specs/openapi/__init__.py,sha256=C5HOsfuDJGq_3mv8CRBvRvb0Diy1p0BFdqyEXMS-loE,238
|
114
114
|
schemathesis/specs/openapi/_cache.py,sha256=HpglmETmZU0RCHxp3DO_sg5_B_nzi54Zuw9vGzzYCxY,4295
|
115
115
|
schemathesis/specs/openapi/_hypothesis.py,sha256=n_39iyz1rt2EdSe-Lyr-3sOIEyJIthnCVR4tGUUvH1c,21328
|
116
|
-
schemathesis/specs/openapi/checks.py,sha256=
|
116
|
+
schemathesis/specs/openapi/checks.py,sha256=m3n5N3_iZcS7inJojW47FF6dfbUQzrBH-bXwsCAOyhM,27737
|
117
117
|
schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
|
118
118
|
schemathesis/specs/openapi/converter.py,sha256=lil8IewM5j8tvt4lpA9g_KITvIwx1M96i45DNSHNjoc,3505
|
119
119
|
schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
|
120
|
-
schemathesis/specs/openapi/examples.py,sha256=
|
120
|
+
schemathesis/specs/openapi/examples.py,sha256=Xvjp60QUcLaeGsJRbi2i6XM15_4uO0ceVoClIaJehiE,21062
|
121
121
|
schemathesis/specs/openapi/formats.py,sha256=ViVF3aFeFI1ctwGQbiRDXhU3so82P0BCaF2aDDbUUm8,2816
|
122
122
|
schemathesis/specs/openapi/media_types.py,sha256=ADedOaNWjbAtAekyaKmNj9fY6zBTeqcNqBEjN0EWNhI,1014
|
123
123
|
schemathesis/specs/openapi/parameters.py,sha256=hv1reNpSjVuzFbtMpSTwWZ75zcWTOy5ZE0ah6AVEqAo,14565
|
124
|
-
schemathesis/specs/openapi/patterns.py,sha256=
|
124
|
+
schemathesis/specs/openapi/patterns.py,sha256=NLnGybcana_kYLVKVEjkEyAzdClAV0xKe4Oy4NVayMI,12834
|
125
125
|
schemathesis/specs/openapi/references.py,sha256=YjD1xMlaYS7xLt6PrrVS20R72ZWHuFZFTa8Llzf54Rg,8808
|
126
126
|
schemathesis/specs/openapi/schemas.py,sha256=VSeacEAVJJ6EKJ-llwOaX4aalzUTXyWP8s4wbxTqtWc,54720
|
127
127
|
schemathesis/specs/openapi/security.py,sha256=6UWYMhL-dPtkTineqqBFNKca1i4EuoTduw-EOLeE0aQ,7149
|
128
|
-
schemathesis/specs/openapi/serialization.py,sha256=
|
128
|
+
schemathesis/specs/openapi/serialization.py,sha256=VdDLmeHqxlWM4cxQQcCkvrU6XurivolwEEaT13ohelA,11972
|
129
129
|
schemathesis/specs/openapi/utils.py,sha256=ER4vJkdFVDIE7aKyxyYatuuHVRNutytezgE52pqZNE8,900
|
130
130
|
schemathesis/specs/openapi/expressions/__init__.py,sha256=hfuRtXD75tQFhzSo6QgDZ3zByyWeZRKevB8edszAVj4,2272
|
131
131
|
schemathesis/specs/openapi/expressions/errors.py,sha256=YLVhps-sYcslgVaahfcUYxUSHlIfWL-rQMeT5PZSMZ8,219
|
@@ -143,11 +143,11 @@ schemathesis/specs/openapi/stateful/links.py,sha256=8oHpmb-yBa3kZKoCv9ytndpOp80d
|
|
143
143
|
schemathesis/transport/__init__.py,sha256=z-mRNSOlMBKwQyaEIhpmYv0plWTmK5dJqc9UmQOry80,3949
|
144
144
|
schemathesis/transport/asgi.py,sha256=qTClt6oT_xUEWnRHokACN_uqCNNUZrRPT6YG0PjbElY,926
|
145
145
|
schemathesis/transport/prepare.py,sha256=qQ6zXBw5NN2AIM0bzLAc5Ryc3dmMb0R6xN14lnR49pU,3826
|
146
|
-
schemathesis/transport/requests.py,sha256=
|
146
|
+
schemathesis/transport/requests.py,sha256=j5wI1Uo_PnVuP1eV8l6ddsXosyxAPQ1mLSyWEZmTI9I,8747
|
147
147
|
schemathesis/transport/serialization.py,sha256=jIMra1LqRGav0OX3Hx7mvORt38ll4cd2DKit2D58FN0,10531
|
148
148
|
schemathesis/transport/wsgi.py,sha256=RWSuUXPrl91GxAy8a4jyNNozOWVMRBxKx_tljlWA_Lo,5697
|
149
|
-
schemathesis-4.0.
|
150
|
-
schemathesis-4.0.
|
151
|
-
schemathesis-4.0.
|
152
|
-
schemathesis-4.0.
|
153
|
-
schemathesis-4.0.
|
149
|
+
schemathesis-4.0.0a6.dist-info/METADATA,sha256=W8GlnQVnH1VOEqPqS-ElR_yk0RvdB9TOXTxHy_p3zTU,10427
|
150
|
+
schemathesis-4.0.0a6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
151
|
+
schemathesis-4.0.0a6.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
|
152
|
+
schemathesis-4.0.0a6.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
|
153
|
+
schemathesis-4.0.0a6.dist-info/RECORD,,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
3
|
Copyright (c) 2019 Kiwi.com
|
4
|
-
Copyright (c) 2020-
|
4
|
+
Copyright (c) 2020-2025 Dmitry Dygalo & Schemathesis.io
|
5
5
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
7
|
of this software and associated documentation files (the "Software"), to deal
|
File without changes
|
File without changes
|