schemathesis 3.26.2__py3-none-any.whl → 3.27.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.
@@ -45,7 +45,8 @@ StrategyFactory = Callable[[Dict[str, Any], str, str, Optional[str], GenerationC
45
45
  def header_values(blacklist_characters: str = "\n\r") -> st.SearchStrategy[str]:
46
46
  return st.text(
47
47
  alphabet=st.characters(min_codepoint=0, max_codepoint=255, blacklist_characters=blacklist_characters)
48
- )
48
+ # Header values with leading non-visible chars can't be sent with `requests`
49
+ ).map(str.lstrip)
49
50
 
50
51
 
51
52
  @lru_cache
@@ -67,8 +68,7 @@ def get_default_format_strategies() -> dict[str, st.SearchStrategy]:
67
68
  "_header_name": st.text(
68
69
  min_size=1, alphabet=st.sampled_from("!#$%&'*+-.^_`|~" + string.digits + string.ascii_letters)
69
70
  ),
70
- # Header values with leading non-visible chars can't be sent with `requests`
71
- HEADER_FORMAT: header_value.map(str.lstrip),
71
+ HEADER_FORMAT: header_value,
72
72
  "_basic_auth": st.tuples(latin1_text, latin1_text).map(make_basic_auth_str),
73
73
  "_bearer_auth": header_value.map("Bearer {}".format),
74
74
  }
@@ -425,6 +425,15 @@ def jsonify_python_specific_types(value: dict[str, Any]) -> dict[str, Any]:
425
425
  return value
426
426
 
427
427
 
428
+ def _build_custom_formats(
429
+ custom_formats: dict[str, st.SearchStrategy] | None, generation_config: GenerationConfig
430
+ ) -> dict[str, st.SearchStrategy]:
431
+ custom_formats = {**get_default_format_strategies(), **STRING_FORMATS, **(custom_formats or {})}
432
+ if generation_config.headers.strategy is not None:
433
+ custom_formats[HEADER_FORMAT] = generation_config.headers.strategy
434
+ return custom_formats
435
+
436
+
428
437
  def make_positive_strategy(
429
438
  schema: dict[str, Any],
430
439
  operation_name: str,
@@ -441,9 +450,10 @@ def make_positive_strategy(
441
450
  for sub_schema in schema.get("properties", {}).values():
442
451
  if list(sub_schema) == ["type"] and sub_schema["type"] == "string":
443
452
  sub_schema.setdefault("format", HEADER_FORMAT)
453
+ custom_formats = _build_custom_formats(custom_formats, generation_config)
444
454
  return from_schema(
445
455
  schema,
446
- custom_formats={**get_default_format_strategies(), **STRING_FORMATS, **(custom_formats or {})},
456
+ custom_formats=custom_formats,
447
457
  allow_x00=generation_config.allow_x00,
448
458
  codec=generation_config.codec,
449
459
  )
@@ -462,12 +472,13 @@ def make_negative_strategy(
462
472
  generation_config: GenerationConfig,
463
473
  custom_formats: dict[str, st.SearchStrategy] | None = None,
464
474
  ) -> st.SearchStrategy:
475
+ custom_formats = _build_custom_formats(custom_formats, generation_config)
465
476
  return negative_schema(
466
477
  schema,
467
478
  operation_name=operation_name,
468
479
  location=location,
469
480
  media_type=media_type,
470
- custom_formats={**get_default_format_strategies(), **STRING_FORMATS, **(custom_formats or {})},
481
+ custom_formats=custom_formats,
471
482
  generation_config=generation_config,
472
483
  )
473
484
 
@@ -304,6 +304,7 @@ def from_dict(
304
304
  :param dict raw_schema: A schema to load.
305
305
  """
306
306
  from .schemas import OpenApi30, SwaggerV20
307
+ from ... import transports
307
308
 
308
309
  if not isinstance(raw_schema, dict):
309
310
  raise SchemaError(SchemaErrorType.OPEN_API_INVALID_SCHEMA, SCHEMA_INVALID_ERROR)
@@ -338,6 +339,7 @@ def from_dict(
338
339
  location=location,
339
340
  rate_limiter=rate_limiter,
340
341
  sanitize_output=sanitize_output,
342
+ transport=transports.get(app),
341
343
  )
342
344
  dispatch("after_load_schema", hook_context, instance)
343
345
  return instance
@@ -379,6 +381,7 @@ def from_dict(
379
381
  location=location,
380
382
  rate_limiter=rate_limiter,
381
383
  sanitize_output=sanitize_output,
384
+ transport=transports.get(app),
382
385
  )
383
386
  dispatch("after_load_schema", hook_context, instance)
384
387
  return instance
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import time
4
4
  import re
5
5
  from dataclasses import dataclass
6
- from typing import TYPE_CHECKING, Any, Callable, ClassVar
6
+ from typing import TYPE_CHECKING, Any, ClassVar
7
7
 
8
8
  from hypothesis.errors import InvalidDefinition
9
9
  from hypothesis.stateful import RuleBasedStateMachine
@@ -189,13 +189,12 @@ class APIStateMachine(RuleBasedStateMachine):
189
189
  :return: Response from the application under test.
190
190
 
191
191
  Note that WSGI/ASGI applications are detected automatically in this method. Depending on the result of this
192
- detection the state machine will call ``call``, ``call_wsgi`` or ``call_asgi`` methods.
192
+ detection the state machine will call the ``call`` method.
193
193
 
194
194
  Usually, you don't need to override this method unless you are building a different state machine on top of this
195
195
  one and want to customize the transport layer itself.
196
196
  """
197
- method = self._get_call_method(case)
198
- return method(**kwargs)
197
+ return case.call(**kwargs)
199
198
 
200
199
  def get_call_kwargs(self, case: Case) -> dict[str, Any]:
201
200
  """Create custom keyword arguments that will be passed to the :meth:`Case.call` method.
@@ -214,15 +213,6 @@ class APIStateMachine(RuleBasedStateMachine):
214
213
  """
215
214
  return {}
216
215
 
217
- def _get_call_method(self, case: Case) -> Callable:
218
- if case.app is not None:
219
- from starlette.applications import Starlette
220
-
221
- if isinstance(case.app, Starlette):
222
- return case.call_asgi
223
- return case.call_wsgi
224
- return case.call
225
-
226
216
  def validate_response(
227
217
  self, response: GenericResponse, case: Case, additional_checks: tuple[CheckFunction, ...] = ()
228
218
  ) -> None:
@@ -1,5 +1,312 @@
1
+ from __future__ import annotations
2
+
1
3
  import base64
4
+ import time
5
+ from inspect import iscoroutinefunction
6
+ from contextlib import contextmanager
7
+ from dataclasses import dataclass
8
+ from datetime import timedelta
9
+ from typing import TYPE_CHECKING, Any, Generator, Protocol, TypeVar, cast
10
+ from urllib.parse import urlparse
11
+
12
+ from .. import failures
13
+ from .._dependency_versions import IS_WERKZEUG_ABOVE_3
14
+ from ..constants import DEFAULT_RESPONSE_TIMEOUT
15
+ from ..exceptions import get_timeout_error
16
+ from ..serializers import SerializerContext
17
+ from ..types import Cookies, NotSet
18
+
19
+ if TYPE_CHECKING:
20
+ import requests
21
+ import werkzeug
22
+ from _typeshed.wsgi import WSGIApplication
23
+ from starlette_testclient._testclient import ASGI2App, ASGI3App
24
+
25
+ from ..models import Case
26
+ from .responses import WSGIResponse
2
27
 
3
28
 
4
29
  def serialize_payload(payload: bytes) -> str:
5
30
  return base64.b64encode(payload).decode()
31
+
32
+
33
+ def get(app: Any) -> Transport:
34
+ """Get transport to send the data to the application."""
35
+ if app is None:
36
+ return RequestsTransport()
37
+ if iscoroutinefunction(app) or (
38
+ hasattr(app, "__call__") and iscoroutinefunction(app.__call__) # noqa: B004
39
+ ):
40
+ return ASGITransport(app=app)
41
+ return WSGITransport(app=app)
42
+
43
+
44
+ S = TypeVar("S", contravariant=True)
45
+ R = TypeVar("R", covariant=True)
46
+
47
+
48
+ class Transport(Protocol[S, R]):
49
+ def serialize_case(
50
+ self,
51
+ case: Case,
52
+ *,
53
+ base_url: str | None = None,
54
+ headers: dict[str, Any] | None = None,
55
+ params: dict[str, Any] | None = None,
56
+ cookies: dict[str, Any] | None = None,
57
+ ) -> dict[str, Any]:
58
+ raise NotImplementedError
59
+
60
+ def send(
61
+ self,
62
+ case: Case,
63
+ *,
64
+ session: S | None = None,
65
+ base_url: str | None = None,
66
+ headers: dict[str, Any] | None = None,
67
+ params: dict[str, Any] | None = None,
68
+ cookies: dict[str, Any] | None = None,
69
+ **kwargs: Any,
70
+ ) -> R:
71
+ raise NotImplementedError
72
+
73
+
74
+ class RequestsTransport:
75
+ def serialize_case(
76
+ self,
77
+ case: Case,
78
+ *,
79
+ base_url: str | None = None,
80
+ headers: dict[str, Any] | None = None,
81
+ params: dict[str, Any] | None = None,
82
+ cookies: dict[str, Any] | None = None,
83
+ ) -> dict[str, Any]:
84
+ final_headers = case._get_headers(headers)
85
+ if case.media_type and case.media_type != "multipart/form-data" and not isinstance(case.body, NotSet):
86
+ # `requests` will handle multipart form headers with the proper `boundary` value.
87
+ if "content-type" not in final_headers:
88
+ final_headers["Content-Type"] = case.media_type
89
+ url = case._get_url(base_url)
90
+ serializer = case._get_serializer()
91
+ if serializer is not None and not isinstance(case.body, NotSet):
92
+ context = SerializerContext(case=case)
93
+ extra = serializer.as_requests(context, case._get_body())
94
+ else:
95
+ extra = {}
96
+ if case._auth is not None:
97
+ extra["auth"] = case._auth
98
+ additional_headers = extra.pop("headers", None)
99
+ if additional_headers:
100
+ # Additional headers, needed for the serializer
101
+ for key, value in additional_headers.items():
102
+ final_headers.setdefault(key, value)
103
+ data = {
104
+ "method": case.method,
105
+ "url": url,
106
+ "cookies": case.cookies,
107
+ "headers": final_headers,
108
+ "params": case.query,
109
+ **extra,
110
+ }
111
+ if params is not None:
112
+ _merge_dict_to(data, "params", params)
113
+ if cookies is not None:
114
+ _merge_dict_to(data, "cookies", cookies)
115
+ return data
116
+
117
+ def send(
118
+ self,
119
+ case: Case,
120
+ *,
121
+ session: requests.Session | None = None,
122
+ base_url: str | None = None,
123
+ headers: dict[str, Any] | None = None,
124
+ params: dict[str, Any] | None = None,
125
+ cookies: dict[str, Any] | None = None,
126
+ **kwargs: Any,
127
+ ) -> requests.Response:
128
+ import requests
129
+ from urllib3.exceptions import ReadTimeoutError
130
+
131
+ data = self.serialize_case(case, base_url=base_url, headers=headers, params=params, cookies=cookies)
132
+ data.update(kwargs)
133
+ data.setdefault("timeout", DEFAULT_RESPONSE_TIMEOUT / 1000)
134
+ if session is None:
135
+ validate_vanilla_requests_kwargs(data)
136
+ session = requests.Session()
137
+ close_session = True
138
+ else:
139
+ close_session = False
140
+ verify = data.get("verify", True)
141
+ try:
142
+ with case.operation.schema.ratelimit():
143
+ response = session.request(**data) # type: ignore
144
+ except (requests.Timeout, requests.ConnectionError) as exc:
145
+ if isinstance(exc, requests.ConnectionError):
146
+ if not isinstance(exc.args[0], ReadTimeoutError):
147
+ raise
148
+ req = requests.Request(
149
+ method=data["method"].upper(),
150
+ url=data["url"],
151
+ headers=data["headers"],
152
+ files=data.get("files"),
153
+ data=data.get("data") or {},
154
+ json=data.get("json"),
155
+ params=data.get("params") or {},
156
+ auth=data.get("auth"),
157
+ cookies=data["cookies"],
158
+ hooks=data.get("hooks"),
159
+ )
160
+ request = session.prepare_request(req)
161
+ else:
162
+ request = cast(requests.PreparedRequest, exc.request)
163
+ timeout = 1000 * data["timeout"] # It is defined and not empty, since the exception happened
164
+ code_message = case._get_code_message(case.operation.schema.code_sample_style, request, verify=verify)
165
+ message = f"The server failed to respond within the specified limit of {timeout:.2f}ms"
166
+ raise get_timeout_error(timeout)(
167
+ f"\n\n1. {failures.RequestTimeout.title}\n\n{message}\n\n{code_message}",
168
+ context=failures.RequestTimeout(message=message, timeout=timeout),
169
+ ) from None
170
+ response.verify = verify # type: ignore[attr-defined]
171
+ if close_session:
172
+ session.close()
173
+ return response
174
+
175
+
176
+ def _merge_dict_to(data: dict[str, Any], data_key: str, new: dict[str, Any]) -> None:
177
+ original = data[data_key] or {}
178
+ for key, value in new.items():
179
+ original[key] = value
180
+ data[data_key] = original
181
+
182
+
183
+ def validate_vanilla_requests_kwargs(data: dict[str, Any]) -> None:
184
+ """Check arguments for `requests.Session.request`.
185
+
186
+ Some arguments can be valid for cases like ASGI integration, but at the same time they won't work for the regular
187
+ `requests` calls. In such cases we need to avoid an obscure error message, that comes from `requests`.
188
+ """
189
+ url = data["url"]
190
+ if not urlparse(url).netloc:
191
+ raise RuntimeError(
192
+ "The URL should be absolute, so Schemathesis knows where to send the data. \n"
193
+ f"If you use the ASGI integration, please supply your test client "
194
+ f"as the `session` argument to `call`.\nURL: {url}"
195
+ )
196
+
197
+
198
+ @dataclass
199
+ class ASGITransport(RequestsTransport):
200
+ app: ASGI2App | ASGI3App
201
+
202
+ def send(
203
+ self,
204
+ case: Case,
205
+ *,
206
+ session: requests.Session | None = None,
207
+ base_url: str | None = None,
208
+ headers: dict[str, Any] | None = None,
209
+ params: dict[str, Any] | None = None,
210
+ cookies: dict[str, Any] | None = None,
211
+ **kwargs: Any,
212
+ ) -> requests.Response:
213
+ from starlette_testclient import TestClient as ASGIClient
214
+
215
+ if base_url is None:
216
+ base_url = case.get_full_base_url()
217
+ with ASGIClient(self.app) as client:
218
+ return super().send(
219
+ case, session=client, base_url=base_url, headers=headers, params=params, cookies=cookies, **kwargs
220
+ )
221
+
222
+
223
+ @dataclass
224
+ class WSGITransport:
225
+ app: WSGIApplication
226
+
227
+ def serialize_case(
228
+ self,
229
+ case: Case,
230
+ *,
231
+ base_url: str | None = None,
232
+ headers: dict[str, Any] | None = None,
233
+ params: dict[str, Any] | None = None,
234
+ cookies: dict[str, Any] | None = None,
235
+ ) -> dict[str, Any]:
236
+ final_headers = case._get_headers(headers)
237
+ if case.media_type and not isinstance(case.body, NotSet):
238
+ # If we need to send a payload, then the Content-Type header should be set
239
+ final_headers["Content-Type"] = case.media_type
240
+ extra: dict[str, Any]
241
+ serializer = case._get_serializer()
242
+ if serializer is not None and not isinstance(case.body, NotSet):
243
+ context = SerializerContext(case=case)
244
+ extra = serializer.as_werkzeug(context, case._get_body())
245
+ else:
246
+ extra = {}
247
+ data = {
248
+ "method": case.method,
249
+ "path": case.operation.schema.get_full_path(case.formatted_path),
250
+ # Convert to a regular dictionary, as we use `CaseInsensitiveDict` which is not supported by Werkzeug
251
+ "headers": dict(final_headers),
252
+ "query_string": case.query,
253
+ **extra,
254
+ }
255
+ if params is not None:
256
+ _merge_dict_to(data, "query_string", params)
257
+ return data
258
+
259
+ def send(
260
+ self,
261
+ case: Case,
262
+ *,
263
+ session: Any = None,
264
+ base_url: str | None = None,
265
+ headers: dict[str, Any] | None = None,
266
+ params: dict[str, Any] | None = None,
267
+ cookies: dict[str, Any] | None = None,
268
+ **kwargs: Any,
269
+ ) -> WSGIResponse:
270
+ import requests
271
+ import werkzeug
272
+
273
+ from .responses import WSGIResponse
274
+
275
+ application = kwargs.pop("app", self.app) or self.app
276
+ data = self.serialize_case(case, headers=headers, params=params)
277
+ data.update(kwargs)
278
+ client = werkzeug.Client(application, WSGIResponse)
279
+ cookies = {**(case.cookies or {}), **(cookies or {})}
280
+ with cookie_handler(client, cookies), case.operation.schema.ratelimit():
281
+ start = time.monotonic()
282
+ response = client.open(**data)
283
+ elapsed = time.monotonic() - start
284
+ requests_kwargs = RequestsTransport().serialize_case(
285
+ case,
286
+ base_url=case.get_full_base_url(),
287
+ headers=headers,
288
+ params=params,
289
+ cookies=cookies,
290
+ )
291
+ response.request = requests.Request(**requests_kwargs).prepare()
292
+ response.elapsed = timedelta(seconds=elapsed)
293
+ return response
294
+
295
+
296
+ @contextmanager
297
+ def cookie_handler(client: werkzeug.Client, cookies: Cookies | None) -> Generator[None, None, None]:
298
+ """Set cookies required for a call."""
299
+ if not cookies:
300
+ yield
301
+ else:
302
+ for key, value in cookies.items():
303
+ if IS_WERKZEUG_ABOVE_3:
304
+ client.set_cookie(key=key, value=value, domain="localhost")
305
+ else:
306
+ client.set_cookie("localhost", key=key, value=value)
307
+ yield
308
+ for key in cookies:
309
+ if IS_WERKZEUG_ABOVE_3:
310
+ client.delete_cookie(key=key, domain="localhost")
311
+ else:
312
+ client.delete_cookie("localhost", key=key)
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import sys
4
4
  import json
5
+ from datetime import timedelta
5
6
  from typing import Union, TYPE_CHECKING, NoReturn, Any
6
7
  from .._compat import JSONMixin
7
8
  from werkzeug.wrappers import Response as BaseResponse
@@ -15,6 +16,7 @@ if TYPE_CHECKING:
15
16
  class WSGIResponse(BaseResponse, JSONMixin):
16
17
  # We store "requests" request to build a reproduction code
17
18
  request: PreparedRequest
19
+ elapsed: timedelta
18
20
 
19
21
  def on_json_loading_failed(self, e: json.JSONDecodeError) -> NoReturn:
20
22
  # We don't need a werkzeug-specific exception when JSON parsing error happens
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schemathesis
3
- Version: 3.26.2
3
+ Version: 3.27.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://schemathesis.readthedocs.io/en/stable/changelog.html
@@ -28,7 +28,6 @@ Classifier: Programming Language :: Python :: 3.12
28
28
  Classifier: Programming Language :: Python :: Implementation :: CPython
29
29
  Classifier: Topic :: Software Development :: Testing
30
30
  Requires-Python: >=3.8
31
- Requires-Dist: anyio<4
32
31
  Requires-Dist: backoff<3.0,>=2.1.2
33
32
  Requires-Dist: click<9.0,>=7.0
34
33
  Requires-Dist: colorama<1.0,>=0.4
@@ -44,7 +43,7 @@ Requires-Dist: pytest-subtests<0.8.0,>=0.2.1
44
43
  Requires-Dist: pytest<9,>=4.6.4
45
44
  Requires-Dist: pyyaml<7.0,>=5.1
46
45
  Requires-Dist: requests<3,>=2.22
47
- Requires-Dist: starlette-testclient<1
46
+ Requires-Dist: starlette-testclient<1,>=0.4.1
48
47
  Requires-Dist: starlette<1,>=0.13
49
48
  Requires-Dist: tomli-w<2.0,>=1.0.0
50
49
  Requires-Dist: tomli<3.0,>=2.0.1
@@ -1,4 +1,4 @@
1
- schemathesis/__init__.py,sha256=WW1NBZxmc5jRR0c24xz-ZtTkJMUQG5MOw1MGVRRGc1s,1970
1
+ schemathesis/__init__.py,sha256=zAa981OnVdIdjiETPP5a5vZL8QXAh2HbTWj8iEoxKC4,1984
2
2
  schemathesis/_compat.py,sha256=VizWR0QAVj4l7WZautNe_zmo3AJ7WBl2zrJQOfJAQtk,1837
3
3
  schemathesis/_dependency_versions.py,sha256=InIv6MZmuRVHc_9FxAiRg7_dY-vuF0jT69FBxrBLK6U,879
4
4
  schemathesis/_hypothesis.py,sha256=O3rfMbT0rChFONMUsYmMEGV9nPG5cHd_6v9NhWDI_IQ,10763
@@ -17,28 +17,30 @@ schemathesis/graphql.py,sha256=YkoKWY5K8lxp7H3ikAs-IsoDbiPwJvChG7O8p3DgwtI,229
17
17
  schemathesis/hooks.py,sha256=cNJgCh7SyLWT1sYDKF5ncDC80ld08CinvKo2IqLMV4g,12396
18
18
  schemathesis/lazy.py,sha256=CivWpvesh4iYLSkatXbQPTEOruWmXvuZQ29gng5p9wM,14846
19
19
  schemathesis/loaders.py,sha256=RJnrbf-3vZ7KXmRBkmr3uqWyg0eHzOnONABuudWcTIg,4586
20
- schemathesis/models.py,sha256=Rcgm2VX7oQN3HN-ThZlqWmBuNsV1Hrd2_xbvh0K6KQY,46883
20
+ schemathesis/models.py,sha256=KtWx7k9M8wrkaCZ82kfLMKd7jmvFxZnGyUuTE_nPhU0,42974
21
21
  schemathesis/parameters.py,sha256=VheEffVzoSfYaSEcG7KhPlA4ypifosG8biiHifzwL8g,2257
22
22
  schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  schemathesis/sanitization.py,sha256=WSV_MB5YRrYkp1pQRPHrzsidqsKcqYZiq64N9grKobo,8956
24
- schemathesis/schemas.py,sha256=H13rs5X-FkNcGIB9W__oolu-AM-vIyYEiArXpg-rKU0,18429
24
+ schemathesis/schemas.py,sha256=RzxAoBoJJSLsixrkTZPe2N_oWbWv8n5RL4XaYRyoSIo,18531
25
25
  schemathesis/serializers.py,sha256=_xoebWkVrgbGbPjPgTgwuN-fN4YT004aj7kImyPComY,11619
26
26
  schemathesis/targets.py,sha256=tzp7VZ2-7g2nZHCooRgFzTMtOVcbl0rvtNR421hQthA,1162
27
27
  schemathesis/throttling.py,sha256=uwhL4XWPWAU8HECg0NhibfCMn5dT7NElTx3fdL3Mmcc,1065
28
28
  schemathesis/types.py,sha256=AglR5M0bce-YXeDRkweToXTP0GjNOWVjS_mIsxLobwc,919
29
29
  schemathesis/utils.py,sha256=4HXvHysnHp-Uz2HfNgLfW5F5VjL-mtixrjjzRCEJhYo,5233
30
- schemathesis/cli/__init__.py,sha256=MSdz9Xt2qvey-3HbWj5nfwV2nZ-rdV05u_Eh_Be9m0c,64909
30
+ schemathesis/cli/__init__.py,sha256=oTBqweV5CP681LqRFdRXtkd0VyYoG_xUKshkKEPnqIQ,64871
31
+ schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
31
32
  schemathesis/cli/callbacks.py,sha256=HmD0WmSYf5x8v4xeZdOKzy_8CEk23NitUlL8JQ7LHdQ,14950
32
33
  schemathesis/cli/cassettes.py,sha256=1ucgYyOZiNu44uOv044FdfKTzQolUyhAM2onk4m3MD0,12988
33
34
  schemathesis/cli/constants.py,sha256=XoezT0_fHuiOY2e--cmBUhNieJsepcUoW8e48QuLSDI,1544
34
35
  schemathesis/cli/context.py,sha256=wwfdSL_NKHEyzQnj8PcnaJdzasa_N08e2KPvy4Wl8N4,1874
35
36
  schemathesis/cli/debug.py,sha256=PDEa-oHyz5bZ8aYjRYARwQaCv_AC6HM_L43LJfe4vUM,657
36
37
  schemathesis/cli/handlers.py,sha256=62GPWPmgeGUz3pkDd01H4UCXcIy5a9yRtU7qaAeeR-A,389
37
- schemathesis/cli/junitxml.py,sha256=jMZzYBYpBE7Rl5n1ct3J0bhhPa1lhBeYb33lTZE1eW8,1792
38
+ schemathesis/cli/junitxml.py,sha256=JMMtWz7grPQw66Ruh-tLR8YVn-58Q0o0l_MxZWQ4V3M,4586
38
39
  schemathesis/cli/options.py,sha256=7_dXcrPT0kWqAkm60cAT1J0IsTOcvNFxT1pcHYttBuI,2558
40
+ schemathesis/cli/reporting.py,sha256=uTtoEJT4maJRGPsVZH184S0hohX-4SwO_dAL__i6H10,3401
39
41
  schemathesis/cli/sanitization.py,sha256=v-9rsMCBpWhom0Bfzj_8c6InqxkVjSWK6kRoURa52Nk,727
40
42
  schemathesis/cli/output/__init__.py,sha256=AXaUzQ1nhQ-vXhW4-X-91vE2VQtEcCOrGtQXXNN55iQ,29
41
- schemathesis/cli/output/default.py,sha256=XxnfZXXERuB1X3M8dlVBZnYUuZ0JXsQMCX4EEv5-oYg,38213
43
+ schemathesis/cli/output/default.py,sha256=GjT-j9pNxVYQmU6nOu08hBqvR9uD_TMI15jZitWgI0A,36781
42
44
  schemathesis/cli/output/short.py,sha256=MmFMOKBRqqvgq7Kmx6XJc7Vqkr9g5BrJBxRbyZ0Rh-k,2068
43
45
  schemathesis/contrib/__init__.py,sha256=FH8NL8NXgSKBFOF8Jy_EB6T4CJEaiM-tmDhz16B2o4k,187
44
46
  schemathesis/contrib/unique_data.py,sha256=zxrmAlQH7Bcil9YSfy2EazwLj2rxLzOvAE3O6QRRkFY,1317
@@ -55,7 +57,7 @@ schemathesis/extra/pytest_plugin.py,sha256=44RRkjkN1JupWu0muq9B5b3K9goucYndB394Q
55
57
  schemathesis/fixups/__init__.py,sha256=iTpOm-cwyZQRglbWRJHxj3k7WO9a4a-MCq-UDQa6U0Y,966
56
58
  schemathesis/fixups/fast_api.py,sha256=-gjYNSUtiKl7cKgyQ_rON0Oo_sGm6r7rOQDH0ahG32A,1322
57
59
  schemathesis/fixups/utf8_bom.py,sha256=ttzPOaJb6K7QtNAbIZ_TWrrm0N9FylS8QzO6zI0jXgY,764
58
- schemathesis/generation/__init__.py,sha256=NOmYWmbTt0uW5Vlx2-xfoXV_lLQs08d9T12v9pFBhrA,1951
60
+ schemathesis/generation/__init__.py,sha256=UXRrDTaUEX29VEK9bLqVi_xVzyNNqul3WhpLh1za90M,2277
59
61
  schemathesis/internal/__init__.py,sha256=93HcdG3LF0BbQKbCteOsFMa1w6nXl8yTmx87QLNJOik,161
60
62
  schemathesis/internal/copy.py,sha256=xsC7RyrFa9KadMsj9ai_aAy0XZg0oplz3cFZCka_2fg,459
61
63
  schemathesis/internal/datetime.py,sha256=zPLBL0XXLNfP-KYel3H2m8pnsxjsA_4d-zTOhJg2EPQ,136
@@ -67,9 +69,9 @@ schemathesis/internal/validation.py,sha256=G7i8jIMUpAeOnDsDF_eWYvRZe_yMprRswx0QA
67
69
  schemathesis/runner/__init__.py,sha256=kkqjC_5G2Mrq00syLNUDHP3sXqwiId8_cusKtIlOyXM,21419
68
70
  schemathesis/runner/events.py,sha256=eZc4TT8C8mWCMr9h4JvlijvQQ-x8wFry8LntdsYIL-A,10200
69
71
  schemathesis/runner/probes.py,sha256=t_B38-ljy-p3Odw-dqcZUVIjYTPwBvac8KE5GaLnz4M,5546
70
- schemathesis/runner/serialization.py,sha256=JgkZrbELi2rL7iCsQ0yySOADwxSNF96gd_DOHVANPVU,16080
72
+ schemathesis/runner/serialization.py,sha256=7DBve7E6JAbAHH5npzjME7lFnysKCc9dPXMmdIIYrNI,16667
71
73
  schemathesis/runner/impl/__init__.py,sha256=1E2iME8uthYPBh9MjwVBCTFV-P3fi7AdphCCoBBspjs,199
72
- schemathesis/runner/impl/core.py,sha256=vaw6OBgYOVT44-gR2t_EiWLArX2RmtAxITR3WZWCX8k,39558
74
+ schemathesis/runner/impl/core.py,sha256=Y8WyKEUeuEs0xi9hWmEA63a39-NO7L6I5hQRhwo9JBQ,39621
73
75
  schemathesis/runner/impl/solo.py,sha256=Y_tNhVBVxcuxv65hN0FjxLlVSC41ebHMOM1xSzVrNk8,3358
74
76
  schemathesis/runner/impl/threadpool.py,sha256=2-2Wvw7msezZtenZY5vU_x3FGLLVlH-ywvhU9hTwAAo,15073
75
77
  schemathesis/service/__init__.py,sha256=cDVTCFD1G-vvhxZkJUwiToTAEQ-0ByIoqwXvJBCf_V8,472
@@ -87,13 +89,13 @@ schemathesis/service/serialization.py,sha256=OjWG7FfihEl4LtpOD8N-fmjOTzSPUm6A4x6
87
89
  schemathesis/service/usage.py,sha256=Z-GCwFcW1pS6YdC-ziEOynikqgOttxp2Uyj_dfK5Q7A,2437
88
90
  schemathesis/specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
91
  schemathesis/specs/graphql/__init__.py,sha256=fgyHtvWNUVWismBTOqxQtgLoTighTfvMv6v6QCD_Oyc,85
90
- schemathesis/specs/graphql/loaders.py,sha256=16fGT4rSqVF91DPY90cKDaFsbtRb9_ZdLnlGY1Gb_vg,11391
92
+ schemathesis/specs/graphql/loaders.py,sha256=5BcHD-w0XU_CRfS53SN4iuGDOfvUfjOfyiRMRGmNDVc,11461
91
93
  schemathesis/specs/graphql/nodes.py,sha256=7F5jbk96uTZZXK9Ulr86KpCAn8z6LKMBcrLrdJHggH0,540
92
94
  schemathesis/specs/graphql/scalars.py,sha256=W5oj6AcjiXpR-Z6eSSp1oPWl0mjH2NF-w87nRFhrHHg,1805
93
- schemathesis/specs/graphql/schemas.py,sha256=XK-zbR_d8zER2HLU3zH-BrKnfoV9hb0VXvDueryp8Y0,14091
95
+ schemathesis/specs/graphql/schemas.py,sha256=6BlTF9iAongsDxzy4_l85YjDob2QzpB0Vt7mlbIUxaw,12637
94
96
  schemathesis/specs/graphql/validation.py,sha256=SqQbj9uymGUQxlHXc8HkQccIq25uwP5CvLF1zReb1Xg,1636
95
97
  schemathesis/specs/openapi/__init__.py,sha256=HDcx3bqpa6qWPpyMrxAbM3uTo0Lqpg-BUNZhDJSJKnw,279
96
- schemathesis/specs/openapi/_hypothesis.py,sha256=o1ssS7JJZ45l750ogoZ3gXoedzLmRsXqpPb1LCZXikY,22835
98
+ schemathesis/specs/openapi/_hypothesis.py,sha256=Qrm6Po2W2wsxZAlLFRUwq0svO8SmQp-5InCFa2cwYaw,23275
97
99
  schemathesis/specs/openapi/checks.py,sha256=1WB_UGNqptfJThWLUNbds1Q-IzOGbbHCOYPIhBYk-zs,5411
98
100
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
99
101
  schemathesis/specs/openapi/converter.py,sha256=9TKeKvNi9MVvoNMfqoPz_cODO8oNrMSTXTOwLLfjD_Q,2799
@@ -102,7 +104,7 @@ schemathesis/specs/openapi/examples.py,sha256=igLDfMpNhRMAk7mYBqi93CtVRQTZCWjCJ2
102
104
  schemathesis/specs/openapi/filters.py,sha256=Ei-QTFcGCvGSIunT-GYQrtqzB-kqvUePOcUuC7B7mT8,1436
103
105
  schemathesis/specs/openapi/formats.py,sha256=JmmkQWNAj5XreXb7Edgj4LADAf4m86YulR_Ec8evpJ4,1220
104
106
  schemathesis/specs/openapi/links.py,sha256=FUjqEf6Sv6PeS0UX7CLL5p2VHa9vA1MGDPhx2pfYg1s,14576
105
- schemathesis/specs/openapi/loaders.py,sha256=Jm37MTUmbVVkOxoRAJOo_T_Ex-tWu2ir7YG7y-v-BjM,24014
107
+ schemathesis/specs/openapi/loaders.py,sha256=QoEFJ7fxJz5XcGTEWV_ZGXARiektmyyT_xmVtcHco6Q,24131
106
108
  schemathesis/specs/openapi/media_types.py,sha256=dNTxpRQbY3SubdVjh4Cjb38R6Bc9MF9BsRQwPD87x0g,1017
107
109
  schemathesis/specs/openapi/parameters.py,sha256=5jMZQZFsZNBFjG22Bqot-Rc65emiSA4E95rIzwImThk,13610
108
110
  schemathesis/specs/openapi/references.py,sha256=YGunHAGubYPKbMqQtpFWZm1D4AGxB8wLuiVhE6T6cWo,8978
@@ -124,14 +126,14 @@ schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrr
124
126
  schemathesis/specs/openapi/stateful/__init__.py,sha256=R8RhPJD3rDzqL4eA9jSnUwh9Q_Mv27ka1C5FdRuyusY,4509
125
127
  schemathesis/specs/openapi/stateful/links.py,sha256=cSIwho2Hroty6au-gyCD-OwqnuCcIpnIIHU6FvF0SwA,3533
126
128
  schemathesis/stateful/__init__.py,sha256=T7rvhzftfl3wumEsir33DBBzCTK2PtRp9CxBxMLdMSE,4693
127
- schemathesis/stateful/state_machine.py,sha256=o940A5Uk-7DaeaVUg4Yf_xbG11v36eoEz-I5D4JKpOY,11717
128
- schemathesis/transports/__init__.py,sha256=Wix_WnOxZlDFD_XFqPMIqz_3TAc7Xda6UGicONaLnNM,108
129
+ schemathesis/stateful/state_machine.py,sha256=ZcKpbvEl1QGhVOYnA7Ow6zkuFHtEPDAyCjroPrj-FgU,11343
130
+ schemathesis/transports/__init__.py,sha256=IHQaob4pLHPP0zXXJukWEQBpV4aSIhGPHHMm0up8x64,11287
129
131
  schemathesis/transports/auth.py,sha256=ZKFku9gjhIG6445qNC2p_64Yt9Iz_4azbvja8AMptBk,404
130
132
  schemathesis/transports/content_types.py,sha256=xU8RZWxz-CyWRqQTI2fGYQacB7KasoY7LL_bxPQdyPY,2144
131
133
  schemathesis/transports/headers.py,sha256=EDxpm8su0AuhyqZUkMex-OFZMAJN_5NHah7fDT2HDZE,989
132
- schemathesis/transports/responses.py,sha256=U6z1VW5w19c9qRRoyf2ljkuXR2smTfWikmrTGqlgl18,1619
133
- schemathesis-3.26.2.dist-info/METADATA,sha256=6ILqISo9c7aYKJCwsxMgNop39oJl1ZPz2qtbhLD_1nc,16257
134
- schemathesis-3.26.2.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
135
- schemathesis-3.26.2.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
136
- schemathesis-3.26.2.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
137
- schemathesis-3.26.2.dist-info/RECORD,,
134
+ schemathesis/transports/responses.py,sha256=j_-udvWbmi6XtEYmpdX8WoFnlrQ6-i3PSBizfozRjQI,1673
135
+ schemathesis-3.27.1.dist-info/METADATA,sha256=GtcBreI2a4R9b3KL_eS-QQb57LTmQckmsQ_vkPTIdDs,16242
136
+ schemathesis-3.27.1.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
137
+ schemathesis-3.27.1.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
138
+ schemathesis-3.27.1.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
139
+ schemathesis-3.27.1.dist-info/RECORD,,