schemathesis 4.0.26__py3-none-any.whl → 4.1.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.
Files changed (37) hide show
  1. schemathesis/cli/commands/run/__init__.py +8 -0
  2. schemathesis/cli/commands/run/handlers/cassettes.py +1 -0
  3. schemathesis/cli/commands/run/handlers/output.py +27 -17
  4. schemathesis/config/_operations.py +5 -0
  5. schemathesis/config/_phases.py +43 -5
  6. schemathesis/config/_projects.py +18 -0
  7. schemathesis/config/schema.json +31 -0
  8. schemathesis/core/__init__.py +1 -0
  9. schemathesis/core/failures.py +2 -1
  10. schemathesis/engine/context.py +39 -4
  11. schemathesis/engine/core.py +30 -9
  12. schemathesis/engine/events.py +12 -2
  13. schemathesis/engine/observations.py +42 -0
  14. schemathesis/engine/phases/__init__.py +5 -0
  15. schemathesis/engine/phases/probes.py +9 -3
  16. schemathesis/engine/phases/stateful/_executor.py +9 -1
  17. schemathesis/engine/phases/unit/__init__.py +1 -0
  18. schemathesis/engine/phases/unit/_executor.py +13 -0
  19. schemathesis/filters.py +4 -0
  20. schemathesis/generation/case.py +1 -1
  21. schemathesis/generation/coverage.py +16 -2
  22. schemathesis/generation/hypothesis/builder.py +14 -1
  23. schemathesis/hooks.py +40 -14
  24. schemathesis/openapi/loaders.py +1 -1
  25. schemathesis/pytest/plugin.py +6 -0
  26. schemathesis/schemas.py +9 -1
  27. schemathesis/specs/openapi/_hypothesis.py +16 -3
  28. schemathesis/specs/openapi/checks.py +4 -1
  29. schemathesis/specs/openapi/formats.py +15 -2
  30. schemathesis/specs/openapi/schemas.py +26 -6
  31. schemathesis/specs/openapi/stateful/inference.py +250 -0
  32. schemathesis/transport/requests.py +3 -0
  33. {schemathesis-4.0.26.dist-info → schemathesis-4.1.1.dist-info}/METADATA +3 -2
  34. {schemathesis-4.0.26.dist-info → schemathesis-4.1.1.dist-info}/RECORD +37 -35
  35. {schemathesis-4.0.26.dist-info → schemathesis-4.1.1.dist-info}/WHEEL +0 -0
  36. {schemathesis-4.0.26.dist-info → schemathesis-4.1.1.dist-info}/entry_points.txt +0 -0
  37. {schemathesis-4.0.26.dist-info → schemathesis-4.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,250 @@
1
+ """Inferencing connections between API operations.
2
+
3
+ The current implementation extracts information from the `Location` header and
4
+ generates OpenAPI links for exact and prefix matches.
5
+
6
+ When a `Location` header points to `/users/123`, the inference:
7
+
8
+ 1. Finds the exact match: `GET /users/{userId}`
9
+ 2. Finds prefix matches: `GET /users/{userId}/posts`, `GET /users/{userId}/posts/{postId}`
10
+ 3. Generates OpenAPI links with regex parameter extractors
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import re
16
+ from dataclasses import dataclass
17
+ from typing import TYPE_CHECKING, Any, Mapping, Union
18
+ from urllib.parse import urlsplit
19
+
20
+ from werkzeug.exceptions import MethodNotAllowed, NotFound
21
+ from werkzeug.routing import Map, MapAdapter, Rule
22
+
23
+ if TYPE_CHECKING:
24
+ from schemathesis.engine.observations import LocationHeaderEntry
25
+ from schemathesis.specs.openapi.schemas import BaseOpenAPISchema
26
+
27
+
28
+ @dataclass(unsafe_hash=True)
29
+ class OperationById:
30
+ """API operation identified by operationId."""
31
+
32
+ value: str
33
+ method: str
34
+ path: str
35
+
36
+ __slots__ = ("value", "method", "path")
37
+
38
+ def to_link_base(self) -> dict[str, Any]:
39
+ return {"operationId": self.value, "x-inferred": True}
40
+
41
+
42
+ @dataclass(unsafe_hash=True)
43
+ class OperationByRef:
44
+ """API operation identified by JSON reference path."""
45
+
46
+ value: str
47
+ method: str
48
+ path: str
49
+
50
+ __slots__ = ("value", "method", "path")
51
+
52
+ def to_link_base(self) -> dict[str, Any]:
53
+ return {"operationRef": self.value, "x-inferred": True}
54
+
55
+
56
+ OperationReference = Union[OperationById, OperationByRef]
57
+ # Method, path, response code, sorted path parameter names
58
+ SeenLinkKey = tuple[str, str, int, tuple[str, ...]]
59
+
60
+
61
+ @dataclass
62
+ class MatchList:
63
+ """Results of matching a location path against API operation."""
64
+
65
+ exact: OperationReference
66
+ inexact: list[OperationReference]
67
+ parameters: Mapping[str, Any]
68
+
69
+ __slots__ = ("exact", "inexact", "parameters")
70
+
71
+
72
+ @dataclass
73
+ class LinkInferencer:
74
+ """Infer OpenAPI links from Location headers for stateful testing."""
75
+
76
+ _adapter: MapAdapter
77
+ # All API operations for prefix matching
78
+ _operations: list[OperationReference]
79
+ _base_url: str | None
80
+ _base_path: str
81
+ _links_field_name: str
82
+
83
+ __slots__ = ("_adapter", "_operations", "_base_url", "_base_path", "_links_field_name")
84
+
85
+ @classmethod
86
+ def from_schema(cls, schema: BaseOpenAPISchema) -> LinkInferencer:
87
+ # NOTE: Use `matchit` for routing in the future
88
+ rules = []
89
+ operations = []
90
+ for method, path, definition in schema._operation_iter():
91
+ operation_id = definition.get("operationId")
92
+ operation: OperationById | OperationByRef
93
+ if operation_id:
94
+ operation = OperationById(operation_id, method=method, path=path)
95
+ else:
96
+ encoded_path = path.replace("~", "~0").replace("/", "~1")
97
+ operation = OperationByRef(f"#/paths/{encoded_path}/{method}", method=method, path=path)
98
+
99
+ operations.append(operation)
100
+
101
+ # Replace `{parameter}` with `<parameter>` as angle brackets are used for parameters in werkzeug
102
+ path = re.sub(r"\{([^}]+)\}", r"<\1>", path)
103
+ rules.append(Rule(path, endpoint=operation, methods=[method.upper()]))
104
+
105
+ return cls(
106
+ _adapter=Map(rules).bind("", ""),
107
+ _operations=operations,
108
+ _base_url=schema.config.base_url,
109
+ _base_path=schema.base_path,
110
+ _links_field_name=schema.links_field,
111
+ )
112
+
113
+ def match(self, path: str) -> tuple[OperationReference, Mapping[str, str]] | None:
114
+ """Match path to API operation and extract path parameters."""
115
+ try:
116
+ return self._adapter.match(path)
117
+ except (NotFound, MethodNotAllowed):
118
+ return None
119
+
120
+ def _build_links_from_matches(self, matches: MatchList) -> list[dict]:
121
+ """Build links from already-found matches."""
122
+ exact = self._build_link_from_match(matches.exact, matches.parameters)
123
+ parameters = exact["parameters"]
124
+ links = [exact]
125
+ for inexact in matches.inexact:
126
+ link = inexact.to_link_base()
127
+ # Parameter extraction is the same, only operations are different
128
+ link["parameters"] = parameters
129
+ links.append(link)
130
+ return links
131
+
132
+ def _find_matches_from_normalized_location(self, normalized_location: str) -> MatchList | None:
133
+ """Find matches from an already-normalized location."""
134
+ match = self.match(normalized_location)
135
+ if not match:
136
+ # It may happen that there is no match, but it is unlikely as the API assumed to return a valid Location
137
+ # that points to an existing API operation. In such cases, if they appear in practice the logic here could be extended
138
+ # to support partial matches
139
+ return None
140
+ exact, parameters = match
141
+ if not parameters:
142
+ # Links without parameters don't make sense
143
+ return None
144
+ matches = MatchList(exact=exact, inexact=[], parameters=parameters)
145
+
146
+ # Find prefix matches, excluding the exact match
147
+ # For example:
148
+ #
149
+ # Location: /users/123 -> /users/{user_id} (exact match)
150
+ # /users/{user_id}/posts , /users/{user_id}/posts/{post_id} (partial matches)
151
+ #
152
+ for candidate in self._operations:
153
+ if candidate == exact:
154
+ continue
155
+ if candidate.path.startswith(exact.path):
156
+ matches.inexact.append(candidate)
157
+
158
+ return matches
159
+
160
+ def _build_link_from_match(
161
+ self, operation: OperationById | OperationByRef, path_parameters: Mapping[str, Any]
162
+ ) -> dict:
163
+ link = operation.to_link_base()
164
+
165
+ # Build regex expressions to extract path parameters
166
+ parameters = {}
167
+ for name in path_parameters:
168
+ # Replace the target parameter with capture group and others with non-slash matcher
169
+ pattern = operation.path
170
+ for candidate in path_parameters:
171
+ if candidate == name:
172
+ pattern = pattern.replace(f"{{{candidate}}}", "(.+)")
173
+ else:
174
+ pattern = pattern.replace(f"{{{candidate}}}", "[^/]+")
175
+
176
+ parameters[name] = f"$response.header.Location#regex:{pattern}"
177
+
178
+ link["parameters"] = parameters
179
+
180
+ return link
181
+
182
+ def _normalize_location(self, location: str) -> str | None:
183
+ """Normalize location header, handling both relative and absolute URLs."""
184
+ location = location.strip()
185
+ if not location:
186
+ return None
187
+
188
+ # Check if it's an absolute URL
189
+ if location.startswith(("http://", "https://")):
190
+ if not self._base_url:
191
+ # Can't validate absolute URLs without base_url
192
+ return None
193
+
194
+ parsed = urlsplit(location)
195
+ base_parsed = urlsplit(self._base_url)
196
+
197
+ # Must match scheme, netloc, and start with the base path
198
+ if parsed.scheme != base_parsed.scheme or parsed.netloc != base_parsed.netloc:
199
+ return None
200
+
201
+ return self._strip_base_path_from_location(parsed.path)
202
+
203
+ # Relative URL - strip base path if present, otherwise use as-is
204
+ stripped = self._strip_base_path_from_location(location)
205
+ return stripped if stripped is not None else location
206
+
207
+ def _strip_base_path_from_location(self, path: str) -> str | None:
208
+ """Strip base path from location path if it starts with base path."""
209
+ base_path = self._base_path.rstrip("/")
210
+ if not path.startswith(base_path):
211
+ return None
212
+
213
+ # Strip the base path to get relative path
214
+ relative_path = path[len(base_path) :]
215
+ return relative_path if relative_path.startswith("/") else "/" + relative_path
216
+
217
+ def inject_links(self, operation: dict[str, Any], entries: list[LocationHeaderEntry]) -> int:
218
+ from schemathesis.specs.openapi.schemas import _get_response_definition_by_status
219
+
220
+ responses = operation.setdefault("responses", {})
221
+ # To avoid unnecessary work, we need to skip entries that we know will produce already inferred links
222
+ seen: set[SeenLinkKey] = set()
223
+ injected = 0
224
+
225
+ for entry in entries:
226
+ location = self._normalize_location(entry.value)
227
+ if location is None:
228
+ # Skip invalid/empty locations or absolute URLs that don't match base_url
229
+ continue
230
+
231
+ matches = self._find_matches_from_normalized_location(location)
232
+ if matches is None:
233
+ # Skip locations that don't match any API apiration
234
+ continue
235
+
236
+ key = (matches.exact.method, matches.exact.path, entry.status_code, tuple(sorted(matches.parameters)))
237
+ if key in seen:
238
+ # Skip duplicate link generation for same operation/status/parameters combination
239
+ continue
240
+ seen.add(key)
241
+ # Find the right bucket for the response status or create a new one
242
+ definition = _get_response_definition_by_status(entry.status_code, responses)
243
+ if definition is None:
244
+ definition = responses.setdefault(str(entry.status_code), {})
245
+ links = definition.setdefault(self._links_field_name, {})
246
+
247
+ for idx, link in enumerate(self._build_links_from_matches(matches)):
248
+ links[f"X-Inferred-Link-{idx}"] = link
249
+ injected += 1
250
+ return injected
@@ -91,6 +91,7 @@ class RequestsTransport(BaseTransport["requests.Session"]):
91
91
 
92
92
  config = case.operation.schema.config
93
93
 
94
+ max_redirects = kwargs.pop("max_redirects", None) or config.max_redirects_for(operation=case.operation)
94
95
  timeout = config.request_timeout_for(operation=case.operation)
95
96
  verify = config.tls_verify_for(operation=case.operation)
96
97
  cert = config.request_cert_for(operation=case.operation)
@@ -131,6 +132,8 @@ class RequestsTransport(BaseTransport["requests.Session"]):
131
132
  current_session_auth = session.auth
132
133
  session.auth = None
133
134
  close_session = False
135
+ if max_redirects is not None:
136
+ session.max_redirects = max_redirects
134
137
  session.headers = {}
135
138
 
136
139
  verify = data.get("verify", True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.0.26
3
+ Version: 4.1.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
@@ -26,12 +26,13 @@ Classifier: Programming Language :: Python :: 3.11
26
26
  Classifier: Programming Language :: Python :: 3.12
27
27
  Classifier: Programming Language :: Python :: 3.13
28
28
  Classifier: Programming Language :: Python :: Implementation :: CPython
29
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
29
30
  Classifier: Topic :: Software Development :: Testing
30
31
  Requires-Python: >=3.9
31
32
  Requires-Dist: backoff<3.0,>=2.1.2
32
33
  Requires-Dist: click<9,>=8.0
33
34
  Requires-Dist: colorama<1.0,>=0.4
34
- Requires-Dist: harfile<1.0,>=0.3.0
35
+ Requires-Dist: harfile<1.0,>=0.3.1
35
36
  Requires-Dist: httpx<1.0,>=0.22.0
36
37
  Requires-Dist: hypothesis-graphql<1,>=0.11.1
37
38
  Requires-Dist: hypothesis-jsonschema<0.24,>=0.23.1
@@ -2,17 +2,17 @@ schemathesis/__init__.py,sha256=QqVUCBQr-RDEstgCZLsxzIa9HJslVSeijrm9gES4b_0,1423
2
2
  schemathesis/auths.py,sha256=JdEwPRS9WKmPcxzGXYYz9pjlIUMQYCfif7ZJU0Kde-I,16400
3
3
  schemathesis/checks.py,sha256=GTdejjXDooAOuq66nvCK3i-AMPBuU-_-aNeSeL9JIlc,6561
4
4
  schemathesis/errors.py,sha256=T8nobEi5tQX_SkwaYb8JFoIlF9F_vOQVprZ8EVPAhjA,931
5
- schemathesis/filters.py,sha256=OEub50Ob5sf0Tn3iTeuIaxSMtepF7KVoiEM9wtt5GGA,13433
6
- schemathesis/hooks.py,sha256=OEnZw5lKSweNdycBRIOsn085rTB-L-iJAjj4ClldkU4,13932
5
+ schemathesis/filters.py,sha256=Nk1Z6_L0fJBIzFGwjUhx9oDHJiGn-kVxbAXWeN9gRcQ,13525
6
+ schemathesis/hooks.py,sha256=q2wqYNgpMCO8ImSBkbrWDSwN0BSELelqJMgAAgGvv2M,14836
7
7
  schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- schemathesis/schemas.py,sha256=thyBKI50sJsj7PE52GvLy9_ktPMDP-fbLM8ZwvdHuD0,28618
8
+ schemathesis/schemas.py,sha256=i0L6jYulGGASD1RiQsA6sOTNt1v812KHSZKIhnuX34s,28965
9
9
  schemathesis/cli/__init__.py,sha256=U9gjzWWpiFhaqevPjZbwyTNjABdpvXETI4HgwdGKnvs,877
10
10
  schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
11
11
  schemathesis/cli/constants.py,sha256=CVcQNHEiX-joAQmyuEVKWPOSxDHsOw_EXXZsEclzLuY,341
12
12
  schemathesis/cli/core.py,sha256=ue7YUdVo3YvuzGL4s6i62NL6YqNDeVPBSnQ1znrvG2w,480
13
13
  schemathesis/cli/commands/__init__.py,sha256=DNzKEnXu7GjGSVe0244ZErmygUBA3nGSyVY6JP3ixD0,3740
14
14
  schemathesis/cli/commands/data.py,sha256=_ALywjIeCZjuaoDQFy-Kj8RZkEGqXd-Y95O47h8Jszs,171
15
- schemathesis/cli/commands/run/__init__.py,sha256=F8KgDQwWRqbJxnAL9nHREphcgGW-Ghn-kbe4yAquadw,18686
15
+ schemathesis/cli/commands/run/__init__.py,sha256=_ApiSVh9q-TsJQ_-IiVBNnLCtTCDMTnOLwuJhOvbCp4,18925
16
16
  schemathesis/cli/commands/run/context.py,sha256=taegOHWc_B-HDwiU1R9Oi4q57mdfLXc-B954QUj8t7A,7984
17
17
  schemathesis/cli/commands/run/events.py,sha256=ew0TQOc9T2YBZynYWv95k9yfAk8-hGuZDLMxjT8EhvY,1595
18
18
  schemathesis/cli/commands/run/executor.py,sha256=kFbZw583SZ-jqjv8goTp2yEJOpZ_bzecyTeZvdc6qTE,5327
@@ -21,9 +21,9 @@ schemathesis/cli/commands/run/loaders.py,sha256=6j0ez7wduAUYbUT28ELKxMf-dYEWr_67
21
21
  schemathesis/cli/commands/run/validation.py,sha256=DQaMiBLN2tYT9hONvv8xnyPvNXZH768UlOdUxTd5kZs,9193
22
22
  schemathesis/cli/commands/run/handlers/__init__.py,sha256=TPZ3KdGi8m0fjlN0GjA31MAXXn1qI7uU4FtiDwroXZI,1915
23
23
  schemathesis/cli/commands/run/handlers/base.py,sha256=yDsTtCiztLksfk7cRzg8JlaAVOfS-zwK3tsJMOXAFyc,530
24
- schemathesis/cli/commands/run/handlers/cassettes.py,sha256=rRD4byjp4HXCkJS-zx3jSIFOJsPq77ejPpYeyCtsEZs,19461
24
+ schemathesis/cli/commands/run/handlers/cassettes.py,sha256=_PBynFlQ5wSg7hEG316hOX4gbVrv6CpYHdFrcG1qeiA,19477
25
25
  schemathesis/cli/commands/run/handlers/junitxml.py,sha256=ydk6Ofj-Uti6H8EucT4Snp85cmTA5W7uVpKkoHrIDKE,2586
26
- schemathesis/cli/commands/run/handlers/output.py,sha256=oS3HP4idz99IxpZcjsqADtEOkuu8wruTcri5c1YIph0,62986
26
+ schemathesis/cli/commands/run/handlers/output.py,sha256=p1_vXzxrrVuC8cN3PV3e7PUjstReDInsfAdXeCUsn08,63727
27
27
  schemathesis/cli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
28
  schemathesis/cli/ext/fs.py,sha256=3lvoAsEDDdih75ITJJNxemd3nwxX55gGWrI7uDxm0cM,447
29
29
  schemathesis/cli/ext/groups.py,sha256=kQ37t6qeArcKaY2y5VxyK3_KwAkBKCVm58IYV8gewds,2720
@@ -36,23 +36,23 @@ schemathesis/config/_env.py,sha256=8XfIyrnGNQuCDnfG0lwmKRFbasRUjgeQGBAMupsmtOU,6
36
36
  schemathesis/config/_error.py,sha256=jfv9chQ4NGoDYypszNGymr0zxXVo65yP0AWK1WVEPIM,5781
37
37
  schemathesis/config/_generation.py,sha256=giWs4z17z9nRe_9Z3mAZ3LEoyh4hkcJnlAA6LSy6iEo,5210
38
38
  schemathesis/config/_health_check.py,sha256=zC9inla5ibMBlEy5WyM4_TME7ju_KH3Bwfo21RI3Gks,561
39
- schemathesis/config/_operations.py,sha256=2M36b4MMoFtaaFpe9yG-aWRqh0Qm1dpdk5M0V23X2yA,12129
39
+ schemathesis/config/_operations.py,sha256=RhTr0EtJZV3z28-dh9-JUpLePQpj-eG6B952ykWoHaQ,12322
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=NFUhn-xzEQdNtgNVW1t51lMquXbjRNGR_QuiCRLCi28,6454
43
- schemathesis/config/_projects.py,sha256=_fbivneAqa2Y7sCX0T1CBSjo3CHPD1qLZcJYsYnWpQk,19486
42
+ schemathesis/config/_phases.py,sha256=AR5AYBF12xr4iUTCJIwaFcHqnlo7o7QhHI1l1gof4uw,7755
43
+ schemathesis/config/_projects.py,sha256=NAUTp48OLr4wxWaLpgDoPT5NAPG40LvmKug7BNt4quk,20201
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=AzWZmZaAuAk4g7-EL_-LwGux3VScg81epWdPfz-kqG0,19127
49
- schemathesis/core/__init__.py,sha256=j862XBH5dXhxsrDg9mE7n4cSSfol0EHdY0ru1d27tCc,1917
48
+ schemathesis/config/schema.json,sha256=3CRSBfUK2vLVl1h5PfeK_YDdEoBZSojYl8Q1kT-ITLE,19846
49
+ schemathesis/core/__init__.py,sha256=h4gmDePIPvPiVuYxnjrpPKytSZPi6fZeVdTG6c822E4,1973
50
50
  schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1058
51
51
  schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
52
52
  schemathesis/core/curl.py,sha256=yuaCe_zHLGwUjEeloQi6W3tOA3cGdnHDNI17-5jia0o,1723
53
53
  schemathesis/core/deserialization.py,sha256=qjXUPaz_mc1OSgXzTUSkC8tuVR8wgVQtb9g3CcAF6D0,2951
54
54
  schemathesis/core/errors.py,sha256=pwiyGhX7tId88Toe2H4ZYsCDc_OvUJtW8Wv-xDv2UD4,16361
55
- schemathesis/core/failures.py,sha256=MYyRnom-XeUEuBmq2ffdz34xhxmpSHWaQunfHtliVsY,8932
55
+ schemathesis/core/failures.py,sha256=yFpAxWdEnm0Ri8z8RqRI9H7vcLH5ztOeSIi4m4SGx5g,8996
56
56
  schemathesis/core/fs.py,sha256=ItQT0_cVwjDdJX9IiI7EnU75NI2H3_DCEyyUjzg_BgI,472
57
57
  schemathesis/core/hooks.py,sha256=qhbkkRSf8URJ4LKv2wmKRINKpquUOgxQzWBHKWRWo3Q,475
58
58
  schemathesis/core/lazy_import.py,sha256=aMhWYgbU2JOltyWBb32vnWBb6kykOghucEzI_F70yVE,470
@@ -69,29 +69,30 @@ schemathesis/core/version.py,sha256=dOBUWrY3-uA2NQXJp9z7EtZgkR6jYeLg8sMhQCL1mcI,
69
69
  schemathesis/core/output/__init__.py,sha256=SiHqONFskXl73AtP5dV29L14nZoKo7B-IeG52KZB32M,1446
70
70
  schemathesis/core/output/sanitization.py,sha256=Ev3tae8dVwsYd7yVb2_1VBFYs92WFsQ4Eu1fGaymItE,2013
71
71
  schemathesis/engine/__init__.py,sha256=QaFE-FinaTAaarteADo2RRMJ-Sz6hZB9TzD5KjMinIA,706
72
- schemathesis/engine/context.py,sha256=x-I9KX6rO6hdCvvN8FEdzIZBqIcNaxdNYHgQjcXbZhM,3931
72
+ schemathesis/engine/context.py,sha256=Kz-Z_CEZPDgOe1uOJU7ElyjY7Q2E6V9rtFi-tlFov8I,5367
73
73
  schemathesis/engine/control.py,sha256=FXzP8dxL47j1Giqpy2-Bsr_MdMw9YiATSK_UfpFwDtk,1348
74
- schemathesis/engine/core.py,sha256=5jfAqFH0XSD7NVgoSXuUPW-dooItscneAzUNq1RBh1E,5712
74
+ schemathesis/engine/core.py,sha256=qlPHnZVq2RrUe93fOciXd1hC3E1gVyF2BIWMPMeLIj8,6655
75
75
  schemathesis/engine/errors.py,sha256=wbFTOE0pmpU79oOzx1l-ypKG92wdFySmNzrN_KTNizM,19168
76
- schemathesis/engine/events.py,sha256=VV6epicFIJnX4c87fVNSd0ibDccX3gryDv52OUGa3FI,6370
76
+ schemathesis/engine/events.py,sha256=jpCtMkWWfNe2jUeZh_Ly_wfZEF44EOodL-I_W4C9rgg,6594
77
+ schemathesis/engine/observations.py,sha256=T-5R8GeVIqvxpCMxc6vZ04UUxUTx3w7689r3Dc6bIcE,1416
77
78
  schemathesis/engine/recorder.py,sha256=K3HfMARrT5mPWXPnYebjjcq5CcsBRhMrtZwEL9_Lvtg,8432
78
- schemathesis/engine/phases/__init__.py,sha256=jUIfb_9QoUo4zmJEVU0z70PgXPYjt8CIqp4qP_HlYHg,3146
79
- schemathesis/engine/phases/probes.py,sha256=fhe_1ZPYDCfyzqjeg_0aWK_dhXlsgacE3_VVlbhkwdI,5528
79
+ schemathesis/engine/phases/__init__.py,sha256=7Yp7dQbd6-K9pavIJeURg6jiNeMpW8UU-Iiikr668ts,3278
80
+ schemathesis/engine/phases/probes.py,sha256=YogjJcZJcTMS8sMdGnG4oXKmMUj_4r_J7MY-BBJtCRU,5690
80
81
  schemathesis/engine/phases/stateful/__init__.py,sha256=Lz1rgNqCfUSIz173XqCGsiMuUI5bh4L-RIFexU1-c_Q,2461
81
- schemathesis/engine/phases/stateful/_executor.py,sha256=_303Yqflx1iFNTQI2EfjSp_2T21YvzJJgMSazhpv5JQ,15200
82
+ schemathesis/engine/phases/stateful/_executor.py,sha256=6YOgAGynP4UKKTITe7S39SCcnRp5OXQ7fCc8BJIFW3A,15592
82
83
  schemathesis/engine/phases/stateful/context.py,sha256=A7X1SLDOWFpCvFN9IiIeNVZM0emjqatmJL_k9UsO7vM,2946
83
- schemathesis/engine/phases/unit/__init__.py,sha256=BvZh39LZmXg90Cy_Tn0cQY5y7eWzYvAEmJ43fGKFAt8,8715
84
- schemathesis/engine/phases/unit/_executor.py,sha256=tRv_QjwtXOuSZCl_j-S_EnhcrKScr9gyGGZItzg16XI,16190
84
+ schemathesis/engine/phases/unit/__init__.py,sha256=9dDcxyj887pktnE9YDIPNaR-vc7iqKQWIrFr77SbUTQ,8786
85
+ schemathesis/engine/phases/unit/_executor.py,sha256=pqUISTWvnXb61rgrnzwlFn7PyR-ZsGis2kbRgBMH4EA,16519
85
86
  schemathesis/engine/phases/unit/_pool.py,sha256=iU0hdHDmohPnEv7_S1emcabuzbTf-Cznqwn0pGQ5wNQ,2480
86
87
  schemathesis/generation/__init__.py,sha256=tvNO2FLiY8z3fZ_kL_QJhSgzXfnT4UqwSXMHCwfLI0g,645
87
- schemathesis/generation/case.py,sha256=zwAwFQ-Fp7SOxCXYOQyAdwAtNwVJe63PdLpvqackFQY,12296
88
- schemathesis/generation/coverage.py,sha256=UUtY9OfL8TnSslWCrh17njN6Ik99u_qKxfUqcNNdHKw,56166
88
+ schemathesis/generation/case.py,sha256=Qc2_5JrWuUkCzAFTTgnVqNUJ2sioslmINTXiY7nHHgA,12326
89
+ schemathesis/generation/coverage.py,sha256=8kxz08sMe7u3yT09W1PtIg_Y-9f1O-hBTuPyeSge2pU,56569
89
90
  schemathesis/generation/meta.py,sha256=yYR7EB1f5n7RrzWHZ6YATepurnnc_hEe7HnztRbaaA0,2699
90
91
  schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
91
92
  schemathesis/generation/modes.py,sha256=Q1fhjWr3zxabU5qdtLvKfpMFZJAwlW9pnxgenjeXTyU,481
92
93
  schemathesis/generation/overrides.py,sha256=OBWqDQPreiliaf2M-oyXppVKHoJkCRzxtwSJx1b6AFw,3759
93
94
  schemathesis/generation/hypothesis/__init__.py,sha256=jK3G4i0SdcyhqwPQg91RH_yg437lSY-smeIQ-wZLWPc,1959
94
- schemathesis/generation/hypothesis/builder.py,sha256=zOUIp1n6kKkh_M7HiwtCNzDk3wtepwBEjmT2qt6PenM,36078
95
+ schemathesis/generation/hypothesis/builder.py,sha256=HOZLev-b-fkaFwDIxQHlpS59y7anyK9mJ-qw5IeQZqY,36777
95
96
  schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
96
97
  schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
97
98
  schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
@@ -103,14 +104,14 @@ schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzY
103
104
  schemathesis/graphql/loaders.py,sha256=2tgG4HIvFmjHLr_KexVXnT8hSBM-dKG_fuXTZgE97So,9445
104
105
  schemathesis/openapi/__init__.py,sha256=-KcsSAM19uOM0N5J4s-yTnQ1BFsptYhW1E51cEf6kVM,311
105
106
  schemathesis/openapi/checks.py,sha256=VaQRxko6KwZL6saIzc4uUgJa_fj086O7Y6QFK8Zg-7A,12419
106
- schemathesis/openapi/loaders.py,sha256=_ryiESCdh_XJZsjsU4QsDeeqHY6MbBiMP4dDpiQkm-o,10742
107
+ schemathesis/openapi/loaders.py,sha256=-DSFWcvD_PmekTyy0qZrJ1YYODh9C1KuAJJIytEnS1s,10733
107
108
  schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
109
  schemathesis/openapi/generation/filters.py,sha256=pY9cUZdL_kQK80Z2aylTOqqa12zmaYUlYC5BfYgeQMk,2395
109
110
  schemathesis/pytest/__init__.py,sha256=7W0q-Thcw03IAQfXE_Mo8JPZpUdHJzfu85fjK1ZdfQM,88
110
111
  schemathesis/pytest/control_flow.py,sha256=F8rAPsPeNv_sJiJgbZYtTpwKWjauZmqFUaKroY2GmQI,217
111
112
  schemathesis/pytest/lazy.py,sha256=u58q0orI0zisivLJKJkSo53RaQMPLSMiE0vJ1TQ9_uA,11073
112
113
  schemathesis/pytest/loaders.py,sha256=Sbv8e5F77_x4amLP50iwubfm6kpOhx7LhLFGsVXW5Ys,925
113
- schemathesis/pytest/plugin.py,sha256=MXllorF5SqUgqjLyhHb-P0wlWokvZMg0Rm6OTRoFoas,14266
114
+ schemathesis/pytest/plugin.py,sha256=-c92Qi2aEvW45KLAzHj9EDXbY_mYq5B5ZdkRY9Ks_DY,14463
114
115
  schemathesis/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
116
  schemathesis/python/asgi.py,sha256=5PyvuTBaivvyPUEi3pwJni91K1kX5Zc0u9c6c1D8a1Q,287
116
117
  schemathesis/python/wsgi.py,sha256=uShAgo_NChbfYaV1117e6UHp0MTg7jaR0Sy_to3Jmf8,219
@@ -121,18 +122,18 @@ schemathesis/specs/graphql/scalars.py,sha256=6lew8mnwhrtg23leiEbG43mLGPLlRln8mCl
121
122
  schemathesis/specs/graphql/schemas.py,sha256=B6FULWIIWoN_gx9OeQOd-6qWsz9yVg5h1XlxFe06XPM,14097
122
123
  schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzVfHxtdLkCPKM,1422
123
124
  schemathesis/specs/openapi/__init__.py,sha256=C5HOsfuDJGq_3mv8CRBvRvb0Diy1p0BFdqyEXMS-loE,238
124
- schemathesis/specs/openapi/_hypothesis.py,sha256=-DE9jxLcEYn5S5wYTQmIC8Lr8UgyXZ8zIhPaB7qRakc,21308
125
- schemathesis/specs/openapi/checks.py,sha256=1_YIcGqZ2xSN_1Ob_CIt_HfARSodMCCYNX4SQXx03-c,30150
125
+ schemathesis/specs/openapi/_hypothesis.py,sha256=XK-g2284wCsqOuPhubpE-PQ5_YotUwNodAnjeHs_-R0,21712
126
+ schemathesis/specs/openapi/checks.py,sha256=P4WaLJ_dqssrZI-fpRwsy4kZ8u6O93YvpQ-98JuMkIQ,30320
126
127
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
127
128
  schemathesis/specs/openapi/converter.py,sha256=LkpCCAxZzET4Qa_3YStSNuhGlsm5G6TVwpxYu6lPO4g,4169
128
129
  schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
129
130
  schemathesis/specs/openapi/examples.py,sha256=JsAy8Dexw36SUAO5MBB44ji3zEK9Y_JU5d2LRshjEI4,22023
130
- schemathesis/specs/openapi/formats.py,sha256=8AIS7Uey-Z1wm1WYRqnsVqHwG9d316PdqfKLqwUs7us,3516
131
+ schemathesis/specs/openapi/formats.py,sha256=4tYRdckauHxkJCmOhmdwDq_eOpHPaKloi89lzMPbPzw,3975
131
132
  schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKRcUOc41eEwKbo,2472
132
133
  schemathesis/specs/openapi/parameters.py,sha256=XpuZ2sex2aYUzKDK17GXVNWFBmvamuyVtloQ1oGQhLk,14468
133
134
  schemathesis/specs/openapi/patterns.py,sha256=GqPZEXMRdWENQxanWjBOalIZ2MQUjuxk21kmdiI703E,18027
134
135
  schemathesis/specs/openapi/references.py,sha256=40YcDExPLR2B8EOwt-Csw-5MYFi2xj_DXf91J0Pc9d4,8855
135
- schemathesis/specs/openapi/schemas.py,sha256=71fdSVpC3_EDjIMMuQdZV7T32IzhdEHPEVTCZkyE3Co,50301
136
+ schemathesis/specs/openapi/schemas.py,sha256=qJ0ChkZuXQafQ-nPwMzckSk3iC32H2O5W9Cbd7DN_2I,51379
136
137
  schemathesis/specs/openapi/security.py,sha256=6UWYMhL-dPtkTineqqBFNKca1i4EuoTduw-EOLeE0aQ,7149
137
138
  schemathesis/specs/openapi/serialization.py,sha256=VdDLmeHqxlWM4cxQQcCkvrU6XurivolwEEaT13ohelA,11972
138
139
  schemathesis/specs/openapi/utils.py,sha256=ER4vJkdFVDIE7aKyxyYatuuHVRNutytezgE52pqZNE8,900
@@ -148,15 +149,16 @@ schemathesis/specs/openapi/negative/types.py,sha256=a7buCcVxNBG6ILBM3A7oNTAX0lyD
148
149
  schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrrkuNdXX0SDnLoGYA,168
149
150
  schemathesis/specs/openapi/stateful/__init__.py,sha256=DaV7Uuo1GTgZF1JjjoQzbzZw5HQhL6pTByiWqIlWwy4,15996
150
151
  schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8n5ePqSKB00XFxp-MA,3695
152
+ schemathesis/specs/openapi/stateful/inference.py,sha256=RSkmA_fyXreCxVpgnHKYNDRgT3av33HGU1NPNtPcg2g,9602
151
153
  schemathesis/specs/openapi/stateful/links.py,sha256=h5q40jUbcIk5DS_Tih1cvFJxS_QxxG0_9ZQnTs1A_zo,8806
152
154
  schemathesis/transport/__init__.py,sha256=6yg_RfV_9L0cpA6qpbH-SL9_3ggtHQji9CZrpIkbA6s,5321
153
155
  schemathesis/transport/asgi.py,sha256=qTClt6oT_xUEWnRHokACN_uqCNNUZrRPT6YG0PjbElY,926
154
156
  schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEzXd0o,4743
155
- schemathesis/transport/requests.py,sha256=46aplzhSmBupegPNMawma-iJWCegWkEd6mzdWLTpgM4,10742
157
+ schemathesis/transport/requests.py,sha256=XWiQVG4rGnFX0rOhOZAKVIPbrlknLuS7pHYwUcOiEGs,10942
156
158
  schemathesis/transport/serialization.py,sha256=igUXKZ_VJ9gV7P0TUc5PDQBJXl_s0kK9T3ljGWWvo6E,10339
157
159
  schemathesis/transport/wsgi.py,sha256=KoAfvu6RJtzyj24VGB8e-Iaa9smpgXJ3VsM8EgAz2tc,6152
158
- schemathesis-4.0.26.dist-info/METADATA,sha256=-G-Cvrj712t6wjZhCS-FOzJ_57yoPpQMM2scYjSAnI0,8472
159
- schemathesis-4.0.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
160
- schemathesis-4.0.26.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
161
- schemathesis-4.0.26.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
162
- schemathesis-4.0.26.dist-info/RECORD,,
160
+ schemathesis-4.1.1.dist-info/METADATA,sha256=twjFIgwG3ZuiTWbHSwLnuRZtfy03aPhzwOwQQGb-TOo,8540
161
+ schemathesis-4.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
+ schemathesis-4.1.1.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
+ schemathesis-4.1.1.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
+ schemathesis-4.1.1.dist-info/RECORD,,