schemathesis 3.25.5__py3-none-any.whl → 3.25.6__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.
@@ -41,16 +41,15 @@ from .._override import CaseOverride
41
41
  from ..transports.auth import get_requests_auth
42
42
  from ..hooks import GLOBAL_HOOK_DISPATCHER, HookContext, HookDispatcher, HookScope
43
43
  from ..models import Case, CheckFunction
44
- from ..runner import events, prepare_hypothesis_settings
44
+ from ..runner import events, prepare_hypothesis_settings, probes
45
45
  from ..specs.graphql import loaders as gql_loaders
46
46
  from ..specs.openapi import loaders as oas_loaders
47
- from ..specs.openapi import formats
48
47
  from ..stateful import Stateful
49
48
  from ..targets import Target
50
49
  from ..types import Filter, PathLike, RequestCert
51
50
  from ..internal.datetime import current_datetime
52
51
  from ..internal.validation import file_exists
53
- from . import callbacks, cassettes, output, probes
52
+ from . import callbacks, cassettes, output
54
53
  from .constants import DEFAULT_WORKERS, MAX_WORKERS, MIN_WORKERS
55
54
  from .context import ExecutionContext, FileReportContext, ServiceReportContext
56
55
  from .debug import DebugOutputHandler
@@ -1100,10 +1099,9 @@ def into_event_stream(
1100
1099
  tag=tag or None,
1101
1100
  operation_id=operation_id or None,
1102
1101
  )
1103
- loaded_schema = load_schema(config)
1104
- run_probes(loaded_schema, config)
1102
+ schema = load_schema(config)
1105
1103
  yield from runner.from_schema(
1106
- loaded_schema,
1104
+ schema,
1107
1105
  auth=auth,
1108
1106
  auth_type=auth_type,
1109
1107
  override=override,
@@ -1126,6 +1124,15 @@ def into_event_stream(
1126
1124
  stateful_recursion_limit=stateful_recursion_limit,
1127
1125
  hypothesis_settings=hypothesis_settings,
1128
1126
  generation_config=generation_config,
1127
+ probe_config=probes.ProbeConfig(
1128
+ base_url=config.base_url,
1129
+ request_tls_verify=config.request_tls_verify,
1130
+ request_proxy=config.request_proxy,
1131
+ request_cert=config.request_cert,
1132
+ auth=config.auth,
1133
+ auth_type=config.auth_type,
1134
+ headers=config.headers,
1135
+ ),
1129
1136
  ).execute()
1130
1137
  except SchemaError as error:
1131
1138
  yield events.InternalError.from_schema_error(error)
@@ -1133,19 +1140,6 @@ def into_event_stream(
1133
1140
  yield events.InternalError.from_exc(exc)
1134
1141
 
1135
1142
 
1136
- def run_probes(schema: BaseSchema, config: LoaderConfig) -> None:
1137
- """Discover capabilities of the tested app."""
1138
- probe_results = probes.run(schema, config)
1139
- for result in probe_results:
1140
- if isinstance(result.probe, probes.NullByteInHeader) and result.is_failure:
1141
- from ..specs.openapi._hypothesis import HEADER_FORMAT, header_values
1142
-
1143
- formats.register(
1144
- HEADER_FORMAT,
1145
- header_values(blacklist_characters="\n\r\x00").map(str.lstrip),
1146
- )
1147
-
1148
-
1149
1143
  def load_schema(config: LoaderConfig) -> BaseSchema:
1150
1144
  """Automatically load API schema."""
1151
1145
  first: Callable[[LoaderConfig], BaseSchema]
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+
2
3
  import os
3
4
  import shutil
4
5
  from dataclasses import dataclass, field
@@ -8,6 +9,7 @@ from typing import TYPE_CHECKING
8
9
  from ..code_samples import CodeSampleStyle
9
10
  from ..internal.deprecation import deprecated_property
10
11
  from ..runner.serialization import SerializedTestResult
12
+ from ..runner.probes import ProbeRun
11
13
 
12
14
  if TYPE_CHECKING:
13
15
  import hypothesis
@@ -49,6 +51,7 @@ class ExecutionContext:
49
51
  verbosity: int = 0
50
52
  code_sample_style: CodeSampleStyle = CodeSampleStyle.default()
51
53
  report: ServiceReportContext | FileReportContext | None = None
54
+ probes: list[ProbeRun] | None = None
52
55
 
53
56
  @deprecated_property(removed_in="4.0", replacement="show_trace")
54
57
  def show_errors_tracebacks(self) -> bool:
@@ -1,35 +1,37 @@
1
1
  from __future__ import annotations
2
+
2
3
  import base64
3
4
  import os
4
5
  import platform
5
6
  import shutil
6
7
  import textwrap
7
8
  import time
9
+ from importlib import metadata
8
10
  from itertools import groupby
9
11
  from queue import Queue
10
12
  from typing import Any, Generator, cast
11
13
 
12
14
  import click
13
- from importlib import metadata
14
15
 
15
16
  from ... import service
16
17
  from ...code_samples import CodeSampleStyle
17
18
  from ...constants import (
18
19
  DISCORD_LINK,
20
+ FALSE_VALUES,
19
21
  FLAKY_FAILURE_MESSAGE,
22
+ GITHUB_APP_LINK,
23
+ ISSUE_TRACKER_URL,
20
24
  REPORT_SUGGESTION_ENV_VAR,
21
25
  SCHEMATHESIS_TEST_CASE_HEADER,
22
26
  SCHEMATHESIS_VERSION,
23
- FALSE_VALUES,
24
- ISSUE_TRACKER_URL,
25
- GITHUB_APP_LINK,
26
27
  )
27
28
  from ...exceptions import RuntimeErrorType, prepare_response_payload
28
29
  from ...experimental import GLOBAL_EXPERIMENTS
29
30
  from ...models import Status
30
31
  from ...runner import events
31
32
  from ...runner.events import InternalErrorType, SchemaErrorType
32
- from ...runner.serialization import SerializedError, SerializedTestResult, deduplicate_failures, SerializedCheck
33
+ from ...runner.probes import ProbeOutcome
34
+ from ...runner.serialization import SerializedCheck, SerializedError, SerializedTestResult, deduplicate_failures
33
35
  from ..context import ExecutionContext, FileReportContext, ServiceReportContext
34
36
  from ..handlers import EventHandler
35
37
 
@@ -487,7 +489,7 @@ def display_service_unauthorized(hostname: str) -> None:
487
489
 
488
490
  def display_service_error(event: service.Error, message_prefix: str = "") -> None:
489
491
  """Show information about an error during communication with Schemathesis.io."""
490
- from requests import RequestException, HTTPError, Response
492
+ from requests import HTTPError, RequestException, Response
491
493
 
492
494
  if isinstance(event.exception, HTTPError):
493
495
  response = cast(Response, event.exception.response)
@@ -694,7 +696,26 @@ def handle_initialized(context: ExecutionContext, event: events.Initialized) ->
694
696
  click.secho(f"Collected API links: {links_count}", bold=True)
695
697
  if isinstance(context.report, ServiceReportContext):
696
698
  click.secho("Report to Schemathesis.io: ENABLED", bold=True)
697
- if context.operations_count >= 1:
699
+
700
+
701
+ def handle_before_probing(context: ExecutionContext, event: events.BeforeProbing) -> None:
702
+ click.secho("API probing: ...\r", bold=True, nl=False)
703
+
704
+
705
+ def handle_after_probing(context: ExecutionContext, event: events.AfterProbing) -> None:
706
+ context.probes = event.probes
707
+ status = "SKIP"
708
+ if event.probes is not None:
709
+ for probe in event.probes:
710
+ if probe.outcome in (ProbeOutcome.SUCCESS, ProbeOutcome.FAILURE):
711
+ # The probe itself has been executed
712
+ status = "SUCCESS"
713
+ elif probe.outcome == ProbeOutcome.ERROR:
714
+ status = "ERROR"
715
+ click.secho(f"API probing: {status}\r", bold=True, nl=False)
716
+ click.echo()
717
+ operations_count = cast(int, context.operations_count) # INVARIANT: should not be `None`
718
+ if operations_count >= 1:
698
719
  click.echo()
699
720
 
700
721
 
@@ -752,6 +773,10 @@ class DefaultOutputStyleHandler(EventHandler):
752
773
  """Choose and execute a proper handler for the given event."""
753
774
  if isinstance(event, events.Initialized):
754
775
  handle_initialized(context, event)
776
+ if isinstance(event, events.BeforeProbing):
777
+ handle_before_probing(context, event)
778
+ if isinstance(event, events.AfterProbing):
779
+ handle_after_probing(context, event)
755
780
  if isinstance(event, events.BeforeExecution):
756
781
  handle_before_execution(context, event)
757
782
  if isinstance(event, events.AfterExecution):
@@ -26,6 +26,10 @@ class ShortOutputStyleHandler(EventHandler):
26
26
  """
27
27
  if isinstance(event, events.Initialized):
28
28
  default.handle_initialized(context, event)
29
+ if isinstance(event, events.BeforeProbing):
30
+ default.handle_before_probing(context, event)
31
+ if isinstance(event, events.AfterProbing):
32
+ default.handle_after_probing(context, event)
29
33
  if isinstance(event, events.BeforeExecution):
30
34
  handle_before_execution(context, event)
31
35
  if isinstance(event, events.AfterExecution):
schemathesis/models.py CHANGED
@@ -960,9 +960,12 @@ class Response:
960
960
  @classmethod
961
961
  def from_requests(cls, response: requests.Response) -> Response:
962
962
  """Create a response from requests.Response."""
963
- headers = {name: response.raw.headers.getlist(name) for name in response.raw.headers.keys()}
963
+ raw = response.raw
964
+ raw_headers = raw.headers if raw is not None else {}
965
+ headers = {name: response.raw.headers.getlist(name) for name in raw_headers.keys()}
964
966
  # Similar to http.client:319 (HTTP version detection in stdlib's `http` package)
965
- http_version = "1.0" if response.raw.version == 10 else "1.1"
967
+ version = raw.version if raw is not None else 10
968
+ http_version = "1.0" if version == 10 else "1.1"
966
969
 
967
970
  def is_empty(_response: requests.Response) -> bool:
968
971
  # Assume the response is empty if:
@@ -1,34 +1,36 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from random import Random
4
- from typing import Any, Callable, Generator, Iterable, TYPE_CHECKING
4
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Iterable
5
5
  from urllib.parse import urlparse
6
6
 
7
7
  from .._override import CaseOverride
8
- from ..generation import DEFAULT_DATA_GENERATION_METHODS, DataGenerationMethod, GenerationConfig
9
8
  from ..constants import (
10
9
  DEFAULT_DEADLINE,
11
10
  DEFAULT_STATEFUL_RECURSION_LIMIT,
12
11
  HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER,
13
12
  )
14
- from ..internal.deprecation import deprecated_function
13
+ from ..exceptions import SchemaError
14
+ from ..generation import DEFAULT_DATA_GENERATION_METHODS, DataGenerationMethod, GenerationConfig
15
15
  from ..internal.datetime import current_datetime
16
+ from ..internal.deprecation import deprecated_function
16
17
  from ..internal.validation import file_exists
17
- from ..transports.auth import get_requests_auth
18
- from ..exceptions import SchemaError
19
18
  from ..loaders import load_app
20
19
  from ..specs.graphql import loaders as gql_loaders
21
20
  from ..specs.openapi import loaders as oas_loaders
22
21
  from ..targets import DEFAULT_TARGETS, Target
22
+ from ..transports.auth import get_requests_auth
23
23
  from ..types import Filter, NotSet, RawAuth, RequestCert
24
+ from .probes import ProbeConfig
24
25
 
25
26
  if TYPE_CHECKING:
26
- from . import events
27
+ import hypothesis
28
+
27
29
  from ..models import CheckFunction
28
30
  from ..schemas import BaseSchema
29
- from .impl import BaseRunner
30
31
  from ..stateful import Stateful
31
- import hypothesis
32
+ from . import events
33
+ from .impl import BaseRunner
32
34
 
33
35
 
34
36
  @deprecated_function(removed_in="4.0", replacement="schemathesis.runner.from_schema")
@@ -75,6 +77,7 @@ def prepare(
75
77
  hypothesis_report_multiple_bugs: bool | None = None,
76
78
  hypothesis_suppress_health_check: list[hypothesis.HealthCheck] | None = None,
77
79
  hypothesis_verbosity: hypothesis.Verbosity | None = None,
80
+ probe_config: ProbeConfig | None = None,
78
81
  ) -> Generator[events.ExecutionEvent, None, None]:
79
82
  """Prepare a generator that will run test cases against the given API definition."""
80
83
  from ..checks import DEFAULT_CHECKS
@@ -128,6 +131,7 @@ def prepare(
128
131
  stateful_recursion_limit=stateful_recursion_limit,
129
132
  count_operations=count_operations,
130
133
  count_links=count_links,
134
+ probe_config=probe_config,
131
135
  )
132
136
 
133
137
 
@@ -188,6 +192,7 @@ def execute_from_schema(
188
192
  stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
189
193
  count_operations: bool = True,
190
194
  count_links: bool = True,
195
+ probe_config: ProbeConfig | None = None,
191
196
  ) -> Generator[events.ExecutionEvent, None, None]:
192
197
  """Execute tests for the given schema.
193
198
 
@@ -237,6 +242,7 @@ def execute_from_schema(
237
242
  stateful_recursion_limit=stateful_recursion_limit,
238
243
  count_operations=count_operations,
239
244
  count_links=count_links,
245
+ probe_config=probe_config,
240
246
  ).execute()
241
247
  except SchemaError as error:
242
248
  yield events.InternalError.from_schema_error(error)
@@ -341,9 +347,11 @@ def from_schema(
341
347
  stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
342
348
  count_operations: bool = True,
343
349
  count_links: bool = True,
350
+ probe_config: ProbeConfig | None = None,
344
351
  ) -> BaseRunner:
345
- from starlette.applications import Starlette
346
352
  import hypothesis
353
+ from starlette.applications import Starlette
354
+
347
355
  from ..checks import DEFAULT_CHECKS
348
356
  from .impl import (
349
357
  SingleThreadASGIRunner,
@@ -355,6 +363,7 @@ def from_schema(
355
363
  )
356
364
 
357
365
  checks = checks or DEFAULT_CHECKS
366
+ probe_config = probe_config or ProbeConfig()
358
367
 
359
368
  hypothesis_settings = hypothesis_settings or hypothesis.settings(deadline=DEFAULT_DEADLINE)
360
369
  generation_config = generation_config or GenerationConfig()
@@ -392,6 +401,7 @@ def from_schema(
392
401
  stateful_recursion_limit=stateful_recursion_limit,
393
402
  count_operations=count_operations,
394
403
  count_links=count_links,
404
+ probe_config=probe_config,
395
405
  )
396
406
  if isinstance(schema.app, Starlette):
397
407
  return ThreadPoolASGIRunner(
@@ -415,6 +425,7 @@ def from_schema(
415
425
  stateful_recursion_limit=stateful_recursion_limit,
416
426
  count_operations=count_operations,
417
427
  count_links=count_links,
428
+ probe_config=probe_config,
418
429
  )
419
430
  return ThreadPoolWSGIRunner(
420
431
  schema=schema,
@@ -438,6 +449,7 @@ def from_schema(
438
449
  stateful_recursion_limit=stateful_recursion_limit,
439
450
  count_operations=count_operations,
440
451
  count_links=count_links,
452
+ probe_config=probe_config,
441
453
  )
442
454
  if not schema.app:
443
455
  return SingleThreadRunner(
@@ -465,6 +477,7 @@ def from_schema(
465
477
  stateful_recursion_limit=stateful_recursion_limit,
466
478
  count_operations=count_operations,
467
479
  count_links=count_links,
480
+ probe_config=probe_config,
468
481
  )
469
482
  if isinstance(schema.app, Starlette):
470
483
  return SingleThreadASGIRunner(
@@ -488,6 +501,7 @@ def from_schema(
488
501
  stateful_recursion_limit=stateful_recursion_limit,
489
502
  count_operations=count_operations,
490
503
  count_links=count_links,
504
+ probe_config=probe_config,
491
505
  )
492
506
  return SingleThreadWSGIRunner(
493
507
  schema=schema,
@@ -510,6 +524,7 @@ def from_schema(
510
524
  stateful_recursion_limit=stateful_recursion_limit,
511
525
  count_operations=count_operations,
512
526
  count_links=count_links,
527
+ probe_config=probe_config,
513
528
  )
514
529
 
515
530
 
@@ -14,6 +14,7 @@ from .serialization import SerializedError, SerializedTestResult
14
14
  if TYPE_CHECKING:
15
15
  from ..models import APIOperation, Status, TestResult, TestResultSet
16
16
  from ..schemas import BaseSchema
17
+ from . import probes
17
18
 
18
19
 
19
20
  @dataclass
@@ -60,6 +61,7 @@ class Initialized(ExecutionEvent):
60
61
  schema: BaseSchema,
61
62
  count_operations: bool = True,
62
63
  count_links: bool = True,
64
+ start_time: float | None = None,
63
65
  started_at: str | None = None,
64
66
  seed: int | None,
65
67
  ) -> Initialized:
@@ -70,12 +72,27 @@ class Initialized(ExecutionEvent):
70
72
  links_count=schema.links_count if count_links else None,
71
73
  location=schema.location,
72
74
  base_url=schema.get_base_url(),
75
+ start_time=start_time or time.monotonic(),
73
76
  started_at=started_at or current_datetime(),
74
77
  specification_name=schema.verbose_name,
75
78
  seed=seed,
76
79
  )
77
80
 
78
81
 
82
+ @dataclass
83
+ class BeforeProbing(ExecutionEvent):
84
+ pass
85
+
86
+
87
+ @dataclass
88
+ class AfterProbing(ExecutionEvent):
89
+ probes: list[probes.ProbeRun] | None
90
+
91
+ def asdict(self, **kwargs: Any) -> dict[str, Any]:
92
+ probes = self.probes or []
93
+ return {"probes": [probe.serialize() for probe in probes], "events_type": self.__class__.__name__}
94
+
95
+
79
96
  class CurrentOperationMixin:
80
97
  method: str
81
98
  path: str
@@ -188,6 +205,9 @@ class InternalErrorType(str, enum.Enum):
188
205
  OTHER = "other"
189
206
 
190
207
 
208
+ DEFAULT_INTERNAL_ERROR_MESSAGE = "An internal error occurred during the test run"
209
+
210
+
191
211
  @dataclass
192
212
  class InternalError(ExecutionEvent):
193
213
  """An error that happened inside the runner."""
@@ -226,7 +246,7 @@ class InternalError(ExecutionEvent):
226
246
  type_=InternalErrorType.OTHER,
227
247
  subtype=None,
228
248
  title="Test Execution Error",
229
- message="An internal error occurred during the test run",
249
+ message=DEFAULT_INTERNAL_ERROR_MESSAGE,
230
250
  extras=[],
231
251
  )
232
252
 
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+
2
3
  import logging
3
4
  import re
4
5
  import threading
@@ -8,7 +9,7 @@ import uuid
8
9
  from contextlib import contextmanager
9
10
  from dataclasses import dataclass, field
10
11
  from types import TracebackType
11
- from typing import Any, Callable, Generator, Iterable, cast, TYPE_CHECKING, Literal
12
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Iterable, List, Literal, cast
12
13
  from warnings import WarningMessage, catch_warnings
13
14
 
14
15
  import hypothesis
@@ -16,53 +17,56 @@ import requests
16
17
  from _pytest.logging import LogCaptureHandler, catching_logs
17
18
  from hypothesis.errors import HypothesisException, InvalidArgument
18
19
  from hypothesis_jsonschema._canonicalise import HypothesisRefResolutionError
19
- from jsonschema.exceptions import ValidationError, SchemaError as JsonSchemaError
20
+ from jsonschema.exceptions import SchemaError as JsonSchemaError
21
+ from jsonschema.exceptions import ValidationError
20
22
  from requests.auth import HTTPDigestAuth, _basic_auth_str
21
23
 
22
- from ..._override import CaseOverride
23
24
  from ... import failures, hooks
24
25
  from ..._compat import MultipleFailures
25
26
  from ..._hypothesis import (
26
- has_unsatisfied_example_mark,
27
- get_non_serializable_mark,
28
- get_invalid_regex_mark,
29
27
  get_invalid_example_headers_mark,
28
+ get_invalid_regex_mark,
29
+ get_non_serializable_mark,
30
+ has_unsatisfied_example_mark,
30
31
  )
32
+ from ..._override import CaseOverride
31
33
  from ...auths import unregister as unregister_auth
32
- from ...generation import DataGenerationMethod, GenerationConfig
33
34
  from ...constants import (
34
35
  DEFAULT_STATEFUL_RECURSION_LIMIT,
35
36
  RECURSIVE_REFERENCE_ERROR_MESSAGE,
36
- USER_AGENT,
37
37
  SERIALIZERS_SUGGESTION_MESSAGE,
38
+ USER_AGENT,
38
39
  )
39
40
  from ...exceptions import (
40
41
  CheckFailed,
41
42
  DeadlineExceeded,
43
+ InvalidHeadersExample,
42
44
  InvalidRegularExpression,
43
45
  NonCheckError,
44
46
  OperationSchemaError,
47
+ SerializationNotPossible,
45
48
  SkipTest,
49
+ format_exception,
46
50
  get_grouped_exception,
47
51
  maybe_set_assertion_message,
48
- format_exception,
49
- SerializationNotPossible,
50
- InvalidHeadersExample,
51
52
  )
53
+ from ...generation import DataGenerationMethod, GenerationConfig
52
54
  from ...hooks import HookContext, get_all_by_name
55
+ from ...internal.datetime import current_datetime
53
56
  from ...internal.result import Ok
54
57
  from ...models import APIOperation, Case, Check, CheckFunction, Status, TestResult, TestResultSet
55
58
  from ...runner import events
56
- from ...internal.datetime import current_datetime
57
59
  from ...schemas import BaseSchema
60
+ from ...specs.openapi import formats
58
61
  from ...stateful import Feedback, Stateful
59
62
  from ...targets import Target, TargetContext
60
63
  from ...types import RawAuth, RequestCert
61
64
  from ...utils import capture_hypothesis_output
65
+ from .. import probes
62
66
  from ..serialization import SerializedTestResult
63
67
 
64
68
  if TYPE_CHECKING:
65
- from ...transports.responses import WSGIResponse, GenericResponse
69
+ from ...transports.responses import GenericResponse, WSGIResponse
66
70
 
67
71
 
68
72
  def _should_count_towards_stop(event: events.ExecutionEvent) -> bool:
@@ -77,6 +81,7 @@ class BaseRunner:
77
81
  targets: Iterable[Target]
78
82
  hypothesis_settings: hypothesis.settings
79
83
  generation_config: GenerationConfig
84
+ probe_config: probes.ProbeConfig
80
85
  override: CaseOverride | None = None
81
86
  auth: RawAuth | None = None
82
87
  auth_type: str | None = None
@@ -104,26 +109,56 @@ class BaseRunner:
104
109
  if self.auth is not None:
105
110
  unregister_auth()
106
111
  results = TestResultSet(seed=self.seed)
107
-
108
- initialized = events.Initialized.from_schema(
109
- schema=self.schema, count_operations=self.count_operations, count_links=self.count_links, seed=self.seed
110
- )
112
+ initialized = None
113
+ __probes = None
114
+ start_time = time.monotonic()
115
+
116
+ def _initialize() -> events.Initialized:
117
+ nonlocal initialized
118
+ initialized = events.Initialized.from_schema(
119
+ schema=self.schema,
120
+ count_operations=self.count_operations,
121
+ count_links=self.count_links,
122
+ seed=self.seed,
123
+ start_time=start_time,
124
+ )
125
+ return initialized
111
126
 
112
127
  def _finish() -> events.Finished:
113
128
  if has_all_not_found(results):
114
129
  results.add_warning(ALL_NOT_FOUND_WARNING_MESSAGE)
115
- return events.Finished.from_results(results=results, running_time=time.monotonic() - initialized.start_time)
130
+ return events.Finished.from_results(results=results, running_time=time.monotonic() - start_time)
116
131
 
117
- if stop_event.is_set():
118
- yield _finish()
119
- return
132
+ def _before_probes() -> events.BeforeProbing:
133
+ return events.BeforeProbing()
120
134
 
121
- yield initialized
135
+ def _run_probes() -> None:
136
+ if not self.dry_run:
137
+ nonlocal __probes
138
+
139
+ __probes = run_probes(self.schema, self.probe_config)
140
+
141
+ def _after_probes() -> events.AfterProbing:
142
+ _probes = cast(List[probes.ProbeRun], __probes)
143
+ return events.AfterProbing(probes=_probes)
122
144
 
123
145
  if stop_event.is_set():
124
146
  yield _finish()
125
147
  return
126
148
 
149
+ for event_factory in (
150
+ _initialize,
151
+ _before_probes,
152
+ _run_probes,
153
+ _after_probes,
154
+ ):
155
+ event = event_factory()
156
+ if event is not None:
157
+ yield event
158
+ if stop_event.is_set():
159
+ yield _finish()
160
+ return
161
+
127
162
  try:
128
163
  yield from self._execute(results, stop_event)
129
164
  except KeyboardInterrupt:
@@ -228,6 +263,20 @@ class BaseRunner:
228
263
  )
229
264
 
230
265
 
266
+ def run_probes(schema: BaseSchema, config: probes.ProbeConfig) -> list[probes.ProbeRun]:
267
+ """Discover capabilities of the tested app."""
268
+ results = probes.run(schema, config)
269
+ for result in results:
270
+ if isinstance(result.probe, probes.NullByteInHeader) and result.is_failure:
271
+ from ...specs.openapi._hypothesis import HEADER_FORMAT, header_values
272
+
273
+ formats.register(
274
+ HEADER_FORMAT,
275
+ header_values(blacklist_characters="\n\r\x00").map(str.lstrip),
276
+ )
277
+ return results
278
+
279
+
231
280
  @dataclass
232
281
  class EventStream:
233
282
  """Schemathesis event stream.
@@ -21,13 +21,24 @@ from ..transports.auth import get_requests_auth
21
21
  if TYPE_CHECKING:
22
22
  import requests
23
23
 
24
+ from ..types import RequestCert
24
25
  from ..schemas import BaseSchema
25
- from . import LoaderConfig
26
26
 
27
27
 
28
28
  HEADER_NAME = "X-Schemathesis-Probe"
29
29
 
30
30
 
31
+ @dataclass
32
+ class ProbeConfig:
33
+ base_url: str | None = None
34
+ request_tls_verify: bool | str = True
35
+ request_proxy: str | None = None
36
+ request_cert: RequestCert | None = None
37
+ auth: tuple[str, str] | None = None
38
+ auth_type: str | None = None
39
+ headers: dict[str, str] | None = None
40
+
41
+
31
42
  @dataclass
32
43
  class Probe:
33
44
  """A request to determine the capabilities of the application under test."""
@@ -35,15 +46,15 @@ class Probe:
35
46
  name: str
36
47
 
37
48
  def prepare_request(
38
- self, session: requests.Session, request: requests.Request, schema: BaseSchema, config: LoaderConfig
49
+ self, session: requests.Session, request: requests.Request, schema: BaseSchema, config: ProbeConfig
39
50
  ) -> requests.PreparedRequest:
40
51
  raise NotImplementedError
41
52
 
42
- def analyze_response(self, response: requests.Response) -> ProbeResultType:
53
+ def analyze_response(self, response: requests.Response) -> ProbeOutcome:
43
54
  raise NotImplementedError
44
55
 
45
56
 
46
- class ProbeResultType(str, enum.Enum):
57
+ class ProbeOutcome(str, enum.Enum):
47
58
  # Capability is supported
48
59
  SUCCESS = "success"
49
60
  # Capability is not supported
@@ -55,18 +66,16 @@ class ProbeResultType(str, enum.Enum):
55
66
 
56
67
 
57
68
  @dataclass
58
- class ProbeResult:
59
- """Result of a probe."""
60
-
69
+ class ProbeRun:
61
70
  probe: Probe
62
- type: ProbeResultType
71
+ outcome: ProbeOutcome
63
72
  request: requests.PreparedRequest | None = None
64
73
  response: requests.Response | None = None
65
74
  error: requests.RequestException | None = None
66
75
 
67
76
  @property
68
77
  def is_failure(self) -> bool:
69
- return self.type == ProbeResultType.FAILURE
78
+ return self.outcome == ProbeOutcome.FAILURE
70
79
 
71
80
  def serialize(self) -> dict[str, Any]:
72
81
  """Serialize probe results so it can be sent over the network."""
@@ -87,7 +96,7 @@ class ProbeResult:
87
96
  error = None
88
97
  return {
89
98
  "name": self.probe.name,
90
- "type": self.type.value,
99
+ "outcome": self.outcome.value,
91
100
  "request": request,
92
101
  "response": response,
93
102
  "error": error,
@@ -101,25 +110,25 @@ class NullByteInHeader(Probe):
101
110
  name: str = "NULL_BYTE_IN_HEADER"
102
111
 
103
112
  def prepare_request(
104
- self, session: requests.Session, request: requests.Request, schema: BaseSchema, config: LoaderConfig
113
+ self, session: requests.Session, request: requests.Request, schema: BaseSchema, config: ProbeConfig
105
114
  ) -> requests.PreparedRequest:
106
115
  request.method = "GET"
107
116
  request.url = config.base_url or schema.get_base_url()
108
117
  request.headers = {"X-Schemathesis-Probe-Null": "\x00"}
109
118
  return session.prepare_request(request)
110
119
 
111
- def analyze_response(self, response: requests.Response) -> ProbeResultType:
120
+ def analyze_response(self, response: requests.Response) -> ProbeOutcome:
112
121
  if response.status_code == 400:
113
- return ProbeResultType.FAILURE
114
- return ProbeResultType.SUCCESS
122
+ return ProbeOutcome.FAILURE
123
+ return ProbeOutcome.SUCCESS
115
124
 
116
125
 
117
126
  PROBES = (NullByteInHeader,)
118
127
 
119
128
 
120
- def send(probe: Probe, session: requests.Session, schema: BaseSchema, config: LoaderConfig) -> ProbeResult:
129
+ def send(probe: Probe, session: requests.Session, schema: BaseSchema, config: ProbeConfig) -> ProbeRun:
121
130
  """Send the probe to the application."""
122
- from requests import Request, RequestException, PreparedRequest
131
+ from requests import PreparedRequest, Request, RequestException
123
132
  from requests.exceptions import MissingSchema
124
133
  from urllib3.exceptions import InsecureRequestWarning
125
134
 
@@ -129,23 +138,24 @@ def send(probe: Probe, session: requests.Session, schema: BaseSchema, config: Lo
129
138
  request.headers["User-Agent"] = USER_AGENT
130
139
  with warnings.catch_warnings():
131
140
  warnings.simplefilter("ignore", InsecureRequestWarning)
132
- response = session.send(request)
141
+ response = session.send(request, timeout=2)
133
142
  except MissingSchema:
134
143
  # In-process ASGI/WSGI testing will have local URLs and requires extra handling
135
144
  # which is not currently implemented
136
- return ProbeResult(probe, ProbeResultType.SKIP, None, None, None)
145
+ return ProbeRun(probe, ProbeOutcome.SKIP, None, None, None)
137
146
  except RequestException as exc:
138
147
  req = exc.request if isinstance(exc.request, PreparedRequest) else None
139
- return ProbeResult(probe, ProbeResultType.ERROR, req, None, exc)
148
+ return ProbeRun(probe, ProbeOutcome.ERROR, req, None, exc)
140
149
  result_type = probe.analyze_response(response)
141
- return ProbeResult(probe, result_type, request, response)
150
+ return ProbeRun(probe, result_type, request, response)
142
151
 
143
152
 
144
- def run(schema: BaseSchema, config: LoaderConfig) -> list[ProbeResult]:
153
+ def run(schema: BaseSchema, config: ProbeConfig) -> list[ProbeRun]:
145
154
  """Run all probes against the given schema."""
146
155
  from requests import Session
147
156
 
148
157
  session = Session()
158
+ session.headers.update(config.headers or {})
149
159
  session.verify = config.request_tls_verify
150
160
  if config.request_cert is not None:
151
161
  session.cert = config.request_cert
@@ -1,4 +1,5 @@
1
1
  from __future__ import annotations
2
+
2
3
  import binascii
3
4
  import os
4
5
  from dataclasses import dataclass
@@ -10,13 +11,14 @@ from typing import (
10
11
  Collection,
11
12
  Dict,
12
13
  Generator,
13
- cast,
14
14
  Protocol,
15
+ cast,
15
16
  runtime_checkable,
16
17
  )
17
18
 
18
- from .internal.copy import fast_deepcopy
19
19
  from ._xml import _to_xml
20
+ from .internal.copy import fast_deepcopy
21
+ from .internal.jsonschema import traverse_schema
20
22
  from .transports.content_types import (
21
23
  is_json_media_type,
22
24
  is_plain_text_media_type,
@@ -150,6 +152,10 @@ class JSONSerializer:
150
152
  return _to_json(value)
151
153
 
152
154
 
155
+ def _replace_binary(value: dict) -> dict:
156
+ return {key: value.data if isinstance(value, Binary) else value for key, value in value.items()}
157
+
158
+
153
159
  def _to_yaml(value: Any) -> dict[str, Any]:
154
160
  import yaml
155
161
 
@@ -162,6 +168,8 @@ def _to_yaml(value: Any) -> dict[str, Any]:
162
168
  return {"data": value}
163
169
  if isinstance(value, Binary):
164
170
  return {"data": value.data}
171
+ if isinstance(value, (list, dict)):
172
+ value = traverse_schema(value, _replace_binary)
165
173
  return {"data": yaml.dump(value, Dumper=SafeDumper)}
166
174
 
167
175
 
@@ -19,6 +19,15 @@ def serialize_initialized(event: events.Initialized) -> dict[str, Any] | None:
19
19
  }
20
20
 
21
21
 
22
+ def serialize_before_probing(_: events.BeforeProbing) -> None:
23
+ return None
24
+
25
+
26
+ def serialize_after_probing(event: events.AfterProbing) -> dict[str, Any] | None:
27
+ probes = event.probes or []
28
+ return {"probes": [probe.serialize() for probe in probes]}
29
+
30
+
22
31
  def serialize_before_execution(event: events.BeforeExecution) -> dict[str, Any] | None:
23
32
  return {
24
33
  "correlation_id": event.correlation_id,
@@ -116,6 +125,8 @@ def serialize_finished(event: events.Finished) -> dict[str, Any] | None:
116
125
 
117
126
  SERIALIZER_MAP = {
118
127
  events.Initialized: serialize_initialized,
128
+ events.BeforeProbing: serialize_before_probing,
129
+ events.AfterProbing: serialize_after_probing,
119
130
  events.BeforeExecution: serialize_before_execution,
120
131
  events.AfterExecution: serialize_after_execution,
121
132
  events.Interrupted: serialize_interrupted,
@@ -128,6 +139,8 @@ def serialize_event(
128
139
  event: events.ExecutionEvent,
129
140
  *,
130
141
  on_initialized: SerializeFunc | None = None,
142
+ on_before_probing: SerializeFunc | None = None,
143
+ on_after_probing: SerializeFunc | None = None,
131
144
  on_before_execution: SerializeFunc | None = None,
132
145
  on_after_execution: SerializeFunc | None = None,
133
146
  on_interrupted: SerializeFunc | None = None,
@@ -139,6 +152,8 @@ def serialize_event(
139
152
  # Use the explicitly provided serializer for this event and fallback to default one if it is not provided
140
153
  serializer = {
141
154
  events.Initialized: on_initialized,
155
+ events.BeforeProbing: on_before_probing,
156
+ events.AfterProbing: on_after_probing,
142
157
  events.BeforeExecution: on_before_execution,
143
158
  events.AfterExecution: on_after_execution,
144
159
  events.Interrupted: on_interrupted,
@@ -134,7 +134,7 @@ def get_case_strategy(
134
134
 
135
135
  context = HookContext(operation)
136
136
 
137
- generation_config = generation_config or GenerationConfig()
137
+ generation_config = generation_config or operation.schema.generation_config
138
138
 
139
139
  path_parameters_ = generate_parameter(
140
140
  "path", path_parameters, operation, draw, context, hooks, generator, generation_config
@@ -3,19 +3,24 @@ from __future__ import annotations
3
3
  from contextlib import suppress
4
4
  from dataclasses import dataclass
5
5
  from functools import lru_cache
6
- from itertools import islice, cycle, chain
7
- from typing import Any, Generator, Union, cast
6
+ from itertools import chain, cycle, islice
7
+ from typing import TYPE_CHECKING, Any, Generator, Union, cast
8
8
 
9
9
  import requests
10
- import hypothesis
11
- from hypothesis_jsonschema import from_schema
12
10
  from hypothesis.strategies import SearchStrategy
11
+ from hypothesis_jsonschema import from_schema
13
12
 
14
- from .parameters import OpenAPIParameter, OpenAPIBody
15
13
  from ...constants import DEFAULT_RESPONSE_TIMEOUT
16
14
  from ...models import APIOperation, Case
17
- from ._hypothesis import get_case_strategy
15
+ from ..._hypothesis import get_single_example
16
+ from ._hypothesis import get_case_strategy, get_default_format_strategies
17
+ from .formats import STRING_FORMATS
18
18
  from .constants import LOCATION_TO_CONTAINER
19
+ from .parameters import OpenAPIBody, OpenAPIParameter
20
+
21
+
22
+ if TYPE_CHECKING:
23
+ from ...generation import GenerationConfig
19
24
 
20
25
 
21
26
  @dataclass
@@ -248,7 +253,7 @@ def extract_from_schema(
248
253
  # Generated by one of `anyOf` or similar sub-schemas
249
254
  continue
250
255
  subschema = operation.schema.prepare_schema(subschema)
251
- generated = _generate_single_example(subschema)
256
+ generated = _generate_single_example(subschema, operation.schema.generation_config)
252
257
  variants[name] = [generated]
253
258
  # Calculate the maximum number of examples any property has
254
259
  total_combos = max(len(examples) for examples in variants.values())
@@ -264,24 +269,17 @@ def extract_from_schema(
264
269
  yield [value]
265
270
 
266
271
 
267
- def _generate_single_example(schema: dict[str, Any]) -> Any:
268
- examples = []
269
-
270
- @hypothesis.given(from_schema(schema)) # type: ignore
271
- @hypothesis.settings( # type: ignore
272
- database=None,
273
- max_examples=1,
274
- deadline=None,
275
- verbosity=hypothesis.Verbosity.quiet,
276
- phases=(hypothesis.Phase.generate,),
277
- suppress_health_check=list(hypothesis.HealthCheck),
272
+ def _generate_single_example(
273
+ schema: dict[str, Any],
274
+ generation_config: GenerationConfig,
275
+ ) -> Any:
276
+ strategy = from_schema(
277
+ schema,
278
+ custom_formats={**get_default_format_strategies(), **STRING_FORMATS},
279
+ allow_x00=generation_config.allow_x00,
280
+ codec=generation_config.codec,
278
281
  )
279
- def example_generating_inner_function(ex: Any) -> None:
280
- examples.append(ex)
281
-
282
- example_generating_inner_function()
283
-
284
- return examples[0]
282
+ return get_single_example(strategy)
285
283
 
286
284
 
287
285
  def produce_combinations(examples: list[Example]) -> Generator[dict[str, Any], None, None]:
@@ -33,6 +33,7 @@ from ...auths import AuthStorage
33
33
  from ...generation import DataGenerationMethod, GenerationConfig
34
34
  from ...constants import HTTP_METHODS, NOT_SET
35
35
  from ...exceptions import (
36
+ InternalError,
36
37
  OperationSchemaError,
37
38
  UsageError,
38
39
  get_missing_content_type_error,
@@ -808,7 +809,7 @@ class SwaggerV20(BaseOpenAPISchema):
808
809
 
809
810
  @property
810
811
  def spec_version(self) -> str:
811
- return self.raw_schema["swagger"]
812
+ return self.raw_schema.get("swagger", "2.0")
812
813
 
813
814
  @property
814
815
  def verbose_name(self) -> str:
@@ -1060,8 +1061,14 @@ class OpenApi30(SwaggerV20):
1060
1061
  files = []
1061
1062
  content = operation.definition.resolved["requestBody"]["content"]
1062
1063
  # Open API 3.0 requires media types to be present. We can get here only if the schema defines
1063
- # the "multipart/form-data" media type
1064
- schema = content["multipart/form-data"]["schema"]
1064
+ # the "multipart/form-data" media type, or any other more general media type that matches it (like `*/*`)
1065
+ for media_type, entry in content.items():
1066
+ main, sub = parse_content_type(media_type)
1067
+ if main in ("*", "multipart") and sub in ("*", "form-data"):
1068
+ schema = entry["schema"]
1069
+ break
1070
+ else:
1071
+ raise InternalError("No 'multipart/form-data' media type found in the schema")
1065
1072
  for name, property_schema in schema.get("properties", {}).items():
1066
1073
  if name in form_data:
1067
1074
  if isinstance(form_data[name], list):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schemathesis
3
- Version: 3.25.5
3
+ Version: 3.25.6
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
@@ -16,30 +16,29 @@ schemathesis/graphql.py,sha256=YkoKWY5K8lxp7H3ikAs-IsoDbiPwJvChG7O8p3DgwtI,229
16
16
  schemathesis/hooks.py,sha256=cNJgCh7SyLWT1sYDKF5ncDC80ld08CinvKo2IqLMV4g,12396
17
17
  schemathesis/lazy.py,sha256=CivWpvesh4iYLSkatXbQPTEOruWmXvuZQ29gng5p9wM,14846
18
18
  schemathesis/loaders.py,sha256=RJnrbf-3vZ7KXmRBkmr3uqWyg0eHzOnONABuudWcTIg,4586
19
- schemathesis/models.py,sha256=OcKi__d_PyLcvjc05jCsmLNJwj5DlEdxiBktAo_HxOQ,46634
19
+ schemathesis/models.py,sha256=F2aWZW_BqCFzgv9s7KFkRt-EGQTimhKbYaehRtqC6Lw,46757
20
20
  schemathesis/parameters.py,sha256=xHd3DAkq7z9FAnYDJXXeeOW8XKRsCIW23qtFOPYvGVs,2256
21
21
  schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  schemathesis/sanitization.py,sha256=WSV_MB5YRrYkp1pQRPHrzsidqsKcqYZiq64N9grKobo,8956
23
23
  schemathesis/schemas.py,sha256=VfNMjBzQNSY7YFhtM_IfpjI48wyff0yZ_QnXM6gA48A,18251
24
- schemathesis/serializers.py,sha256=cYWblkz-fghGClYWlBdxiebqXqksxuHVFonRBj7daL8,11296
24
+ schemathesis/serializers.py,sha256=RUvFrZftIk3bcAlG2WP-HlP_r_xRyKSd3uRnyFomlFU,11587
25
25
  schemathesis/targets.py,sha256=tzp7VZ2-7g2nZHCooRgFzTMtOVcbl0rvtNR421hQthA,1162
26
26
  schemathesis/throttling.py,sha256=QQcS7TFpXHavUjm0kdFaCcCRhAGlgQ4y3XIbkdRoW20,1079
27
27
  schemathesis/types.py,sha256=AglR5M0bce-YXeDRkweToXTP0GjNOWVjS_mIsxLobwc,919
28
28
  schemathesis/utils.py,sha256=4HXvHysnHp-Uz2HfNgLfW5F5VjL-mtixrjjzRCEJhYo,5233
29
- schemathesis/cli/__init__.py,sha256=aijICr5cRlKISUWYAQOurcOhZOhLxk1u04pXM0cNb-U,64814
29
+ schemathesis/cli/__init__.py,sha256=1m3rkoJyK35uvE2NCVjL2FJ8kprqiRppRAcDtPtLAsQ,64586
30
30
  schemathesis/cli/callbacks.py,sha256=HmD0WmSYf5x8v4xeZdOKzy_8CEk23NitUlL8JQ7LHdQ,14950
31
31
  schemathesis/cli/cassettes.py,sha256=gPPvcuIj1WnoP-yqqvGCJNe49SWlDFu8OdQkOmY453A,12988
32
32
  schemathesis/cli/constants.py,sha256=XoezT0_fHuiOY2e--cmBUhNieJsepcUoW8e48QuLSDI,1544
33
- schemathesis/cli/context.py,sha256=QrNr-5-7Z8TWGNzlD87hJZau6wU--ZboYHN92cyg82k,1652
33
+ schemathesis/cli/context.py,sha256=jfCIzPsdnxsKzdtKKxVM8Jygr2fMIWlAWRi0rP1cmZ8,1731
34
34
  schemathesis/cli/debug.py,sha256=PDEa-oHyz5bZ8aYjRYARwQaCv_AC6HM_L43LJfe4vUM,657
35
35
  schemathesis/cli/handlers.py,sha256=62GPWPmgeGUz3pkDd01H4UCXcIy5a9yRtU7qaAeeR-A,389
36
36
  schemathesis/cli/junitxml.py,sha256=jMZzYBYpBE7Rl5n1ct3J0bhhPa1lhBeYb33lTZE1eW8,1792
37
37
  schemathesis/cli/options.py,sha256=7_dXcrPT0kWqAkm60cAT1J0IsTOcvNFxT1pcHYttBuI,2558
38
- schemathesis/cli/probes.py,sha256=HAz5kWeXL9NiRFtLC86rDvBgpwDLJ8NnCDyVU74Yp9I,5245
39
38
  schemathesis/cli/sanitization.py,sha256=v-9rsMCBpWhom0Bfzj_8c6InqxkVjSWK6kRoURa52Nk,727
40
39
  schemathesis/cli/output/__init__.py,sha256=AXaUzQ1nhQ-vXhW4-X-91vE2VQtEcCOrGtQXXNN55iQ,29
41
- schemathesis/cli/output/default.py,sha256=WUIWgqzqlRR3afBIt9EnCEwSzgT46gEs6dMtwZ1AMZg,31980
42
- schemathesis/cli/output/short.py,sha256=Ui21Ko7eY5igs4CyNFb88-KRXKmMjz776l9aCHpYq8o,1628
40
+ schemathesis/cli/output/default.py,sha256=1Kmx6WTIhE2AMivoe631y9ES0KwSLnxwhHn56zmqxRw,33011
41
+ schemathesis/cli/output/short.py,sha256=kr_1WBPh-_hIST3rpV34py2oquKn1Il5E0ZBlmZjjA4,1846
43
42
  schemathesis/contrib/__init__.py,sha256=FH8NL8NXgSKBFOF8Jy_EB6T4CJEaiM-tmDhz16B2o4k,187
44
43
  schemathesis/contrib/unique_data.py,sha256=zxrmAlQH7Bcil9YSfy2EazwLj2rxLzOvAE3O6QRRkFY,1317
45
44
  schemathesis/contrib/openapi/__init__.py,sha256=YMj_b2f3ohGwEt8QQXlxBT60wqvdCFS6516I4EHWVNM,217
@@ -64,11 +63,12 @@ schemathesis/internal/jsonschema.py,sha256=eQEkBLTdJ__U7Z0XYXB_RVBQJ4texfFO0AaOo
64
63
  schemathesis/internal/result.py,sha256=Og_ZfwwQ6JFmW79ExC1ndjVMIOHJB7o9XtrfhYIjOOs,461
65
64
  schemathesis/internal/transformation.py,sha256=ZNEtL8ezryLdP9-of4eSRBMSjjV_lBQ5DZZfoPGZFEU,449
66
65
  schemathesis/internal/validation.py,sha256=G7i8jIMUpAeOnDsDF_eWYvRZe_yMprRswx0QAtMPyEw,966
67
- schemathesis/runner/__init__.py,sha256=mEfQP6_u_HTVxJe4YlXr0ddSu3NUcEwuWfen4gqKfUA,20358
68
- schemathesis/runner/events.py,sha256=whpHGXcT7esnJ2bNsFirUrrELI3GtDAAoJ7VVTty2mc,9416
66
+ schemathesis/runner/__init__.py,sha256=PZ2kdk4xI853BC3nmJsPRCbBFoR_PKgpjTja1dn9SPA,20888
67
+ schemathesis/runner/events.py,sha256=A0vyMQOM5OjsNMR7OZ-OtWEU7tKKggt-z81nBulvxxU,9950
68
+ schemathesis/runner/probes.py,sha256=WrMc_BX7PaaqNTL3UEDQd_nfgyw7b1kjrlaYUhUGSXM,5545
69
69
  schemathesis/runner/serialization.py,sha256=WvAVInu_Pe088p5lWupHvWVDMUjepcf8CIfPi0tLYdg,15900
70
70
  schemathesis/runner/impl/__init__.py,sha256=1E2iME8uthYPBh9MjwVBCTFV-P3fi7AdphCCoBBspjs,199
71
- schemathesis/runner/impl/core.py,sha256=koma7LEah5YJJTmqlLV9An5x-dBUMiKn1oEq1umDtTA,36760
71
+ schemathesis/runner/impl/core.py,sha256=uRQpd5KXHNwfXJSBu9nTwYTqaEOUSO6sb2oaQacq_Fo,38406
72
72
  schemathesis/runner/impl/solo.py,sha256=Y_tNhVBVxcuxv65hN0FjxLlVSC41ebHMOM1xSzVrNk8,3358
73
73
  schemathesis/runner/impl/threadpool.py,sha256=2-2Wvw7msezZtenZY5vU_x3FGLLVlH-ywvhU9hTwAAo,15073
74
74
  schemathesis/service/__init__.py,sha256=cDVTCFD1G-vvhxZkJUwiToTAEQ-0ByIoqwXvJBCf_V8,472
@@ -81,7 +81,7 @@ schemathesis/service/hosts.py,sha256=WEiVaLpVka3mhl-T0LjD4WJDEGC-dqOFNmiB4H7Cx5Q
81
81
  schemathesis/service/metadata.py,sha256=jsPeif2XbrwjZgzDD3YysuUgGaSZm6Hkc4e3raDewqo,1475
82
82
  schemathesis/service/models.py,sha256=bY9g48TdtEPS0yO2lTKEsHtKl81Hh5vSJtMDe8kkWSI,850
83
83
  schemathesis/service/report.py,sha256=ua1-cfa-TgGshZgimUQ3-YQqykhZqMHCkEificBKncM,8294
84
- schemathesis/service/serialization.py,sha256=uXB-pRi1oylJ6n2CveoVyaK9m1tbQgykDcgTNPvGhHc,6781
84
+ schemathesis/service/serialization.py,sha256=Tx-gEBw6J1qMFMbE9O_r504DNSVHYpW5VhgoOH80AQc,7342
85
85
  schemathesis/service/usage.py,sha256=Z-GCwFcW1pS6YdC-ziEOynikqgOttxp2Uyj_dfK5Q7A,2437
86
86
  schemathesis/specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
87
  schemathesis/specs/graphql/__init__.py,sha256=fgyHtvWNUVWismBTOqxQtgLoTighTfvMv6v6QCD_Oyc,85
@@ -91,19 +91,19 @@ schemathesis/specs/graphql/scalars.py,sha256=W5oj6AcjiXpR-Z6eSSp1oPWl0mjH2NF-w87
91
91
  schemathesis/specs/graphql/schemas.py,sha256=pbonjYD2neMujoMZZMM_MXFJt-gk1qsW59Qkfed9Ltg,13967
92
92
  schemathesis/specs/graphql/validation.py,sha256=SqQbj9uymGUQxlHXc8HkQccIq25uwP5CvLF1zReb1Xg,1636
93
93
  schemathesis/specs/openapi/__init__.py,sha256=Ue1Qod8IpzeJ5dwxjAHNv97Nh8NVzm_6fnHR2BIzfHY,220
94
- schemathesis/specs/openapi/_hypothesis.py,sha256=bJHTlz4SYq7Z79ihxlsZ1WpK5q-1tVTJHBAaPvuq0xg,22157
94
+ schemathesis/specs/openapi/_hypothesis.py,sha256=wVbww3uxbwvAwc-LVldV8xTJsnGaR4zj_9SIYsXAeUc,22173
95
95
  schemathesis/specs/openapi/checks.py,sha256=1WB_UGNqptfJThWLUNbds1Q-IzOGbbHCOYPIhBYk-zs,5411
96
96
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
97
97
  schemathesis/specs/openapi/converter.py,sha256=9TKeKvNi9MVvoNMfqoPz_cODO8oNrMSTXTOwLLfjD_Q,2799
98
98
  schemathesis/specs/openapi/definitions.py,sha256=t5xffHLBnSgptBdDkSqYN1OfT-DaXoeUw2tIgNEe2q8,94057
99
- schemathesis/specs/openapi/examples.py,sha256=6SKlA3DyOTivaetWmKTata3ehlFGFaRh5pajZKNEdJ4,14917
99
+ schemathesis/specs/openapi/examples.py,sha256=igLDfMpNhRMAk7mYBqi93CtVRQTZCWjCJ2KxlQFotdA,14932
100
100
  schemathesis/specs/openapi/filters.py,sha256=Ei-QTFcGCvGSIunT-GYQrtqzB-kqvUePOcUuC7B7mT8,1436
101
101
  schemathesis/specs/openapi/formats.py,sha256=JmmkQWNAj5XreXb7Edgj4LADAf4m86YulR_Ec8evpJ4,1220
102
102
  schemathesis/specs/openapi/links.py,sha256=YryI35djHOhTikRV3FLafy_jhYFypF7E8Yb6dg9ksWc,14575
103
103
  schemathesis/specs/openapi/loaders.py,sha256=Jm37MTUmbVVkOxoRAJOo_T_Ex-tWu2ir7YG7y-v-BjM,24014
104
104
  schemathesis/specs/openapi/parameters.py,sha256=5jMZQZFsZNBFjG22Bqot-Rc65emiSA4E95rIzwImThk,13610
105
105
  schemathesis/specs/openapi/references.py,sha256=YGunHAGubYPKbMqQtpFWZm1D4AGxB8wLuiVhE6T6cWo,8978
106
- schemathesis/specs/openapi/schemas.py,sha256=QmcA7ACKRpebO3iYnWKC9hcx_jkLeEy6ll72x-eDu90,50039
106
+ schemathesis/specs/openapi/schemas.py,sha256=mIoJkuaQeF5fcrjBFGuudglQJz93vbaMc0wFVJjdVTg,50424
107
107
  schemathesis/specs/openapi/security.py,sha256=lNRD4RSYe341f_ayhl_bQuYlFbGzx4luhXi6qJwzrOY,6495
108
108
  schemathesis/specs/openapi/serialization.py,sha256=jajqowTIiyEVWEx-Gy4ZinXZewNg0n_ipsGzz7JXP7c,11383
109
109
  schemathesis/specs/openapi/utils.py,sha256=gmW4v6o6sZQifajfPquhFeWmZWGQM89mOOBYZvjnE7g,741
@@ -127,8 +127,8 @@ schemathesis/transports/auth.py,sha256=ZKFku9gjhIG6445qNC2p_64Yt9Iz_4azbvja8AMpt
127
127
  schemathesis/transports/content_types.py,sha256=xU8RZWxz-CyWRqQTI2fGYQacB7KasoY7LL_bxPQdyPY,2144
128
128
  schemathesis/transports/headers.py,sha256=EDxpm8su0AuhyqZUkMex-OFZMAJN_5NHah7fDT2HDZE,989
129
129
  schemathesis/transports/responses.py,sha256=U6z1VW5w19c9qRRoyf2ljkuXR2smTfWikmrTGqlgl18,1619
130
- schemathesis-3.25.5.dist-info/METADATA,sha256=1MNBBPfjk_19WvZfNbZDjxVBkgyNyUFxl5fA51R7rYI,15668
131
- schemathesis-3.25.5.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
132
- schemathesis-3.25.5.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
133
- schemathesis-3.25.5.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
134
- schemathesis-3.25.5.dist-info/RECORD,,
130
+ schemathesis-3.25.6.dist-info/METADATA,sha256=z6ZLtx0WmChQbDgAb0WmCJlts2QywnGX3CUU4z6FpcQ,15668
131
+ schemathesis-3.25.6.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
132
+ schemathesis-3.25.6.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
133
+ schemathesis-3.25.6.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
134
+ schemathesis-3.25.6.dist-info/RECORD,,