schemathesis 3.21.2__py3-none-any.whl → 3.22.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 (95) hide show
  1. schemathesis/__init__.py +1 -1
  2. schemathesis/_compat.py +2 -18
  3. schemathesis/_dependency_versions.py +1 -6
  4. schemathesis/_hypothesis.py +15 -12
  5. schemathesis/_lazy_import.py +3 -2
  6. schemathesis/_xml.py +12 -11
  7. schemathesis/auths.py +88 -81
  8. schemathesis/checks.py +4 -4
  9. schemathesis/cli/__init__.py +202 -171
  10. schemathesis/cli/callbacks.py +29 -32
  11. schemathesis/cli/cassettes.py +25 -25
  12. schemathesis/cli/context.py +18 -12
  13. schemathesis/cli/junitxml.py +2 -2
  14. schemathesis/cli/options.py +10 -11
  15. schemathesis/cli/output/default.py +64 -34
  16. schemathesis/code_samples.py +10 -10
  17. schemathesis/constants.py +1 -1
  18. schemathesis/contrib/unique_data.py +2 -2
  19. schemathesis/exceptions.py +55 -42
  20. schemathesis/extra/_aiohttp.py +2 -2
  21. schemathesis/extra/_flask.py +2 -2
  22. schemathesis/extra/_server.py +3 -2
  23. schemathesis/extra/pytest_plugin.py +10 -10
  24. schemathesis/failures.py +16 -16
  25. schemathesis/filters.py +40 -41
  26. schemathesis/fixups/__init__.py +4 -3
  27. schemathesis/fixups/fast_api.py +5 -4
  28. schemathesis/generation/__init__.py +16 -4
  29. schemathesis/hooks.py +25 -25
  30. schemathesis/internal/jsonschema.py +4 -3
  31. schemathesis/internal/transformation.py +3 -2
  32. schemathesis/lazy.py +39 -31
  33. schemathesis/loaders.py +8 -8
  34. schemathesis/models.py +128 -126
  35. schemathesis/parameters.py +6 -5
  36. schemathesis/runner/__init__.py +107 -81
  37. schemathesis/runner/events.py +37 -26
  38. schemathesis/runner/impl/core.py +86 -81
  39. schemathesis/runner/impl/solo.py +19 -15
  40. schemathesis/runner/impl/threadpool.py +40 -22
  41. schemathesis/runner/serialization.py +67 -40
  42. schemathesis/sanitization.py +18 -20
  43. schemathesis/schemas.py +83 -72
  44. schemathesis/serializers.py +39 -30
  45. schemathesis/service/ci.py +20 -21
  46. schemathesis/service/client.py +29 -9
  47. schemathesis/service/constants.py +1 -0
  48. schemathesis/service/events.py +2 -2
  49. schemathesis/service/hosts.py +8 -7
  50. schemathesis/service/metadata.py +5 -0
  51. schemathesis/service/models.py +22 -4
  52. schemathesis/service/report.py +15 -15
  53. schemathesis/service/serialization.py +23 -27
  54. schemathesis/service/usage.py +8 -7
  55. schemathesis/specs/graphql/loaders.py +31 -24
  56. schemathesis/specs/graphql/nodes.py +3 -2
  57. schemathesis/specs/graphql/scalars.py +26 -2
  58. schemathesis/specs/graphql/schemas.py +38 -34
  59. schemathesis/specs/openapi/_hypothesis.py +62 -44
  60. schemathesis/specs/openapi/checks.py +10 -10
  61. schemathesis/specs/openapi/converter.py +10 -9
  62. schemathesis/specs/openapi/definitions.py +2 -2
  63. schemathesis/specs/openapi/examples.py +22 -21
  64. schemathesis/specs/openapi/expressions/nodes.py +5 -4
  65. schemathesis/specs/openapi/expressions/parser.py +7 -6
  66. schemathesis/specs/openapi/filters.py +6 -6
  67. schemathesis/specs/openapi/formats.py +2 -2
  68. schemathesis/specs/openapi/links.py +19 -21
  69. schemathesis/specs/openapi/loaders.py +133 -78
  70. schemathesis/specs/openapi/negative/__init__.py +16 -11
  71. schemathesis/specs/openapi/negative/mutations.py +11 -10
  72. schemathesis/specs/openapi/parameters.py +20 -19
  73. schemathesis/specs/openapi/references.py +21 -20
  74. schemathesis/specs/openapi/schemas.py +97 -84
  75. schemathesis/specs/openapi/security.py +25 -24
  76. schemathesis/specs/openapi/serialization.py +20 -23
  77. schemathesis/specs/openapi/stateful/__init__.py +12 -11
  78. schemathesis/specs/openapi/stateful/links.py +7 -7
  79. schemathesis/specs/openapi/utils.py +4 -3
  80. schemathesis/specs/openapi/validation.py +3 -2
  81. schemathesis/stateful/__init__.py +15 -16
  82. schemathesis/stateful/state_machine.py +9 -9
  83. schemathesis/targets.py +3 -3
  84. schemathesis/throttling.py +2 -2
  85. schemathesis/transports/auth.py +2 -2
  86. schemathesis/transports/content_types.py +5 -0
  87. schemathesis/transports/headers.py +3 -2
  88. schemathesis/transports/responses.py +1 -1
  89. schemathesis/utils.py +7 -10
  90. {schemathesis-3.21.2.dist-info → schemathesis-3.22.1.dist-info}/METADATA +12 -13
  91. schemathesis-3.22.1.dist-info/RECORD +130 -0
  92. schemathesis-3.21.2.dist-info/RECORD +0 -130
  93. {schemathesis-3.21.2.dist-info → schemathesis-3.22.1.dist-info}/WHEEL +0 -0
  94. {schemathesis-3.21.2.dist-info → schemathesis-3.22.1.dist-info}/entry_points.txt +0 -0
  95. {schemathesis-3.21.2.dist-info → schemathesis-3.22.1.dist-info}/licenses/LICENSE +0 -0
@@ -8,7 +8,7 @@ import uuid
8
8
  from contextlib import contextmanager
9
9
  from dataclasses import dataclass, field
10
10
  from types import TracebackType
11
- from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Type, Union, cast, TYPE_CHECKING
11
+ from typing import Any, Callable, Generator, Iterable, cast, TYPE_CHECKING, Literal
12
12
  from warnings import WarningMessage, catch_warnings
13
13
 
14
14
  import hypothesis
@@ -21,9 +21,8 @@ from requests.auth import HTTPDigestAuth, _basic_auth_str
21
21
 
22
22
  from ... import failures, hooks
23
23
  from ..._compat import MultipleFailures
24
- from ..._dependency_versions import IS_HYPOTHESIS_ABOVE_6_54
25
24
  from ...auths import unregister as unregister_auth
26
- from ...generation import DataGenerationMethod
25
+ from ...generation import DataGenerationMethod, GenerationConfig
27
26
  from ...constants import DEFAULT_STATEFUL_RECURSION_LIMIT, RECURSIVE_REFERENCE_ERROR_MESSAGE, USER_AGENT
28
27
  from ...exceptions import (
29
28
  CheckFailed,
@@ -61,25 +60,27 @@ def _should_count_towards_stop(event: events.ExecutionEvent) -> bool:
61
60
  class BaseRunner:
62
61
  schema: BaseSchema
63
62
  checks: Iterable[CheckFunction]
64
- max_response_time: Optional[int]
63
+ max_response_time: int | None
65
64
  targets: Iterable[Target]
66
65
  hypothesis_settings: hypothesis.settings
67
- auth: Optional[RawAuth] = None
68
- auth_type: Optional[str] = None
69
- headers: Optional[Dict[str, Any]] = None
70
- request_timeout: Optional[int] = None
66
+ generation_config: GenerationConfig
67
+ auth: RawAuth | None = None
68
+ auth_type: str | None = None
69
+ headers: dict[str, Any] | None = None
70
+ request_timeout: int | None = None
71
71
  store_interactions: bool = False
72
- seed: Optional[int] = None
72
+ seed: int | None = None
73
73
  exit_first: bool = False
74
- max_failures: Optional[int] = None
74
+ max_failures: int | None = None
75
75
  started_at: str = field(default_factory=current_datetime)
76
76
  dry_run: bool = False
77
- stateful: Optional[Stateful] = None
77
+ stateful: Stateful | None = None
78
78
  stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT
79
79
  count_operations: bool = True
80
+ count_links: bool = True
80
81
  _failures_counter: int = 0
81
82
 
82
- def execute(self) -> "EventStream":
83
+ def execute(self) -> EventStream:
83
84
  """Common logic for all runners."""
84
85
  event = threading.Event()
85
86
  return EventStream(self._generate_events(event), event)
@@ -88,9 +89,11 @@ class BaseRunner:
88
89
  # If auth is explicitly provided, then the global provider is ignored
89
90
  if self.auth is not None:
90
91
  unregister_auth()
91
- results = TestResultSet()
92
+ results = TestResultSet(seed=self.seed)
92
93
 
93
- initialized = events.Initialized.from_schema(schema=self.schema, count_operations=self.count_operations)
94
+ initialized = events.Initialized.from_schema(
95
+ schema=self.schema, count_operations=self.count_operations, count_links=self.count_links, seed=self.seed
96
+ )
94
97
 
95
98
  def _finish() -> events.Finished:
96
99
  if has_all_not_found(results):
@@ -108,8 +111,7 @@ class BaseRunner:
108
111
  return
109
112
 
110
113
  try:
111
- for event in self._execute(results, stop_event):
112
- yield event
114
+ yield from self._execute(results, stop_event)
113
115
  except KeyboardInterrupt:
114
116
  yield events.Interrupted()
115
117
 
@@ -134,10 +136,11 @@ class BaseRunner:
134
136
  maker: Callable,
135
137
  template: Callable,
136
138
  settings: hypothesis.settings,
137
- seed: Optional[int],
139
+ generation_config: GenerationConfig,
140
+ seed: int | None,
138
141
  results: TestResultSet,
139
142
  recursion_level: int = 0,
140
- headers: Optional[Dict[str, Any]] = None,
143
+ headers: dict[str, Any] | None = None,
141
144
  **kwargs: Any,
142
145
  ) -> Generator[events.ExecutionEvent, None, None]:
143
146
  """Run tests and recursively run additional tests."""
@@ -148,7 +151,13 @@ class BaseRunner:
148
151
  as_strategy_kwargs["headers"] = {
149
152
  key: value for key, value in headers.items() if key.lower() != "user-agent"
150
153
  }
151
- for result in maker(template, settings, seed, as_strategy_kwargs=as_strategy_kwargs):
154
+ for result in maker(
155
+ template,
156
+ settings=settings,
157
+ generation_config=generation_config,
158
+ seed=seed,
159
+ as_strategy_kwargs=as_strategy_kwargs,
160
+ ):
152
161
  if isinstance(result, Ok):
153
162
  operation, test = result.ok()
154
163
  feedback = Feedback(self.stateful, operation)
@@ -176,8 +185,9 @@ class BaseRunner:
176
185
  yield from self._run_tests(
177
186
  feedback.get_stateful_tests,
178
187
  template,
179
- settings,
180
- seed,
188
+ settings=settings,
189
+ generation_config=generation_config,
190
+ seed=seed,
181
191
  recursion_level=recursion_level + 1,
182
192
  results=results,
183
193
  headers=headers,
@@ -233,7 +243,7 @@ def handle_schema_error(
233
243
  data_generation_methods: Iterable[DataGenerationMethod],
234
244
  recursion_level: int,
235
245
  *,
236
- before_execution_correlation_id: Optional[str] = None,
246
+ before_execution_correlation_id: str | None = None,
237
247
  ) -> Generator[events.ExecutionEvent, None, None]:
238
248
  if error.method is not None:
239
249
  assert error.path is not None
@@ -288,7 +298,7 @@ def run_test(
288
298
  data_generation_methods: Iterable[DataGenerationMethod],
289
299
  targets: Iterable[Target],
290
300
  results: TestResultSet,
291
- headers: Optional[Dict[str, Any]],
301
+ headers: dict[str, Any] | None,
292
302
  recursion_level: int,
293
303
  **kwargs: Any,
294
304
  ) -> Generator[events.ExecutionEvent, None, None]:
@@ -308,8 +318,8 @@ def run_test(
308
318
  data_generation_method=data_generation_methods,
309
319
  correlation_id=correlation_id,
310
320
  )
311
- hypothesis_output: List[str] = []
312
- errors: List[Exception] = []
321
+ hypothesis_output: list[str] = []
322
+ errors: list[Exception] = []
313
323
  test_start_time = time.monotonic()
314
324
  setup_hypothesis_database_key(test, operation)
315
325
  try:
@@ -326,13 +336,13 @@ def run_test(
326
336
  # Test body was not executed at all - Hypothesis did not generate any tests, but there is no error
327
337
  if not result.is_executed:
328
338
  status = Status.skip
329
- result.mark_skipped()
339
+ result.mark_skipped(None)
330
340
  else:
331
341
  status = Status.success
332
- except unittest.case.SkipTest:
342
+ except unittest.case.SkipTest as exc:
333
343
  # Newer Hypothesis versions raise this exception if no tests were executed
334
344
  status = Status.skip
335
- result.mark_skipped()
345
+ result.mark_skipped(exc)
336
346
  except CheckFailed:
337
347
  status = Status.failure
338
348
  except NonCheckError:
@@ -359,9 +369,9 @@ def run_test(
359
369
  except KeyboardInterrupt:
360
370
  yield events.Interrupted()
361
371
  return
362
- except SkipTest:
372
+ except SkipTest as exc:
363
373
  status = Status.skip
364
- result.mark_skipped()
374
+ result.mark_skipped(exc)
365
375
  except AssertionError: # comes from `hypothesis-jsonschema`
366
376
  error = reraise(operation)
367
377
  status = Status.error
@@ -384,6 +394,7 @@ def run_test(
384
394
  status = Status.error
385
395
  result.add_error(error)
386
396
  test_elapsed_time = time.monotonic() - test_start_time
397
+ # DEPRECATED: Seed is the same per test run
387
398
  # Fetch seed value, hypothesis generates it during test execution
388
399
  # It may be `None` if the `derandomize` config option is set to `True`
389
400
  result.seed = getattr(test, "_hypothesis_internal_use_seed", None) or getattr(
@@ -456,7 +467,7 @@ def setup_hypothesis_database_key(test: Callable, operation: APIOperation) -> No
456
467
  test.hypothesis.inner_test._hypothesis_internal_add_digest = extra # type: ignore
457
468
 
458
469
 
459
- def get_invalid_regular_expression_message(warnings: List[WarningMessage]) -> Optional[str]:
470
+ def get_invalid_regular_expression_message(warnings: list[WarningMessage]) -> str | None:
460
471
  for warning in warnings:
461
472
  message = str(warning.message)
462
473
  if "is not valid syntax for a Python regular expression" in message:
@@ -477,7 +488,7 @@ def reraise(operation: APIOperation) -> OperationSchemaError:
477
488
  MEMORY_ADDRESS_RE = re.compile("0x[0-9a-fA-F]+")
478
489
 
479
490
 
480
- def deduplicate_errors(errors: List[Exception]) -> Generator[Exception, None, None]:
491
+ def deduplicate_errors(errors: list[Exception]) -> Generator[Exception, None, None]:
481
492
  """Deduplicate errors by their messages + tracebacks."""
482
493
  seen = set()
483
494
  for error in errors:
@@ -494,11 +505,11 @@ def run_checks(
494
505
  *,
495
506
  case: Case,
496
507
  checks: Iterable[CheckFunction],
497
- check_results: List[Check],
508
+ check_results: list[Check],
498
509
  result: TestResult,
499
510
  response: GenericResponse,
500
511
  elapsed_time: float,
501
- max_response_time: Optional[int] = None,
512
+ max_response_time: int | None = None,
502
513
  ) -> None:
503
514
  errors = []
504
515
 
@@ -523,11 +534,7 @@ def run_checks(
523
534
  except AssertionError as exc:
524
535
  add_single_failure(exc)
525
536
  except MultipleFailures as exc:
526
- if not IS_HYPOTHESIS_ABOVE_6_54:
527
- exceptions = exc.args[1]
528
- else:
529
- exceptions = exc.exceptions
530
- for exception in exceptions:
537
+ for exception in exc.exceptions:
531
538
  add_single_failure(exception)
532
539
 
533
540
  if max_response_time:
@@ -577,16 +584,14 @@ class ErrorCollector:
577
584
  function signatures, which are used by Hypothesis.
578
585
  """
579
586
 
580
- errors: List[Exception]
587
+ errors: list[Exception]
581
588
 
582
- def __enter__(self) -> "ErrorCollector":
589
+ def __enter__(self) -> ErrorCollector:
583
590
  return self
584
591
 
585
- # Typing: The return type suggested by mypy is `Literal[False]`, but I don't want to introduce dependency on the
586
- # `typing_extensions` package for Python 3.7
587
592
  def __exit__(
588
- self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType]
589
- ) -> Any:
593
+ self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None
594
+ ) -> Literal[False]:
590
595
  # Don't do anything special if:
591
596
  # - Tests are successful
592
597
  # - Checks failed
@@ -602,7 +607,7 @@ class ErrorCollector:
602
607
  raise NonCheckError from None
603
608
 
604
609
 
605
- def _force_data_generation_method(values: List[DataGenerationMethod], case: Case) -> None:
610
+ def _force_data_generation_method(values: list[DataGenerationMethod], case: Case) -> None:
606
611
  # Set data generation method to the one that actually used
607
612
  data_generation_method = cast(DataGenerationMethod, case.data_generation_method)
608
613
  values[:] = [data_generation_method]
@@ -614,16 +619,16 @@ def network_test(
614
619
  targets: Iterable[Target],
615
620
  result: TestResult,
616
621
  session: requests.Session,
617
- request_timeout: Optional[int],
622
+ request_timeout: int | None,
618
623
  request_tls_verify: bool,
619
- request_cert: Optional[RequestCert],
624
+ request_cert: RequestCert | None,
620
625
  store_interactions: bool,
621
- headers: Optional[Dict[str, Any]],
626
+ headers: dict[str, Any] | None,
622
627
  feedback: Feedback,
623
- max_response_time: Optional[int],
624
- data_generation_methods: List[DataGenerationMethod],
628
+ max_response_time: int | None,
629
+ data_generation_methods: list[DataGenerationMethod],
625
630
  dry_run: bool,
626
- errors: List[Exception],
631
+ errors: list[Exception],
627
632
  ) -> None:
628
633
  """A single test body will be executed against the target."""
629
634
  with ErrorCollector(errors):
@@ -657,18 +662,18 @@ def _network_test(
657
662
  targets: Iterable[Target],
658
663
  result: TestResult,
659
664
  session: requests.Session,
660
- timeout: Optional[float],
665
+ timeout: float | None,
661
666
  store_interactions: bool,
662
- headers: Optional[Dict[str, Any]],
667
+ headers: dict[str, Any] | None,
663
668
  feedback: Feedback,
664
669
  request_tls_verify: bool,
665
- request_cert: Optional[RequestCert],
666
- max_response_time: Optional[int],
670
+ request_cert: RequestCert | None,
671
+ max_response_time: int | None,
667
672
  ) -> requests.Response:
668
- check_results: List[Check] = []
673
+ check_results: list[Check] = []
669
674
  try:
670
675
  hook_context = HookContext(operation=case.operation)
671
- kwargs: Dict[str, Any] = {
676
+ kwargs: dict[str, Any] = {
672
677
  "session": session,
673
678
  "headers": headers,
674
679
  "timeout": timeout,
@@ -711,16 +716,16 @@ def _network_test(
711
716
 
712
717
 
713
718
  @contextmanager
714
- def get_session(auth: Optional[Union[HTTPDigestAuth, RawAuth]] = None) -> Generator[requests.Session, None, None]:
719
+ def get_session(auth: HTTPDigestAuth | RawAuth | None = None) -> Generator[requests.Session, None, None]:
715
720
  with requests.Session() as session:
716
721
  if auth is not None:
717
722
  session.auth = auth
718
723
  yield session
719
724
 
720
725
 
721
- def prepare_timeout(timeout: Optional[int]) -> Optional[float]:
726
+ def prepare_timeout(timeout: int | None) -> float | None:
722
727
  """Request timeout is in milliseconds, but `requests` uses seconds."""
723
- output: Optional[Union[int, float]] = timeout
728
+ output: int | float | None = timeout
724
729
  if timeout is not None:
725
730
  output = timeout / 1000
726
731
  return output
@@ -731,15 +736,15 @@ def wsgi_test(
731
736
  checks: Iterable[CheckFunction],
732
737
  targets: Iterable[Target],
733
738
  result: TestResult,
734
- auth: Optional[RawAuth],
735
- auth_type: Optional[str],
736
- headers: Optional[Dict[str, Any]],
739
+ auth: RawAuth | None,
740
+ auth_type: str | None,
741
+ headers: dict[str, Any] | None,
737
742
  store_interactions: bool,
738
743
  feedback: Feedback,
739
- max_response_time: Optional[int],
740
- data_generation_methods: List[DataGenerationMethod],
744
+ max_response_time: int | None,
745
+ data_generation_methods: list[DataGenerationMethod],
741
746
  dry_run: bool,
742
- errors: List[Exception],
747
+ errors: list[Exception],
743
748
  ) -> None:
744
749
  with ErrorCollector(errors):
745
750
  _force_data_generation_method(data_generation_methods, case)
@@ -764,10 +769,10 @@ def _wsgi_test(
764
769
  checks: Iterable[CheckFunction],
765
770
  targets: Iterable[Target],
766
771
  result: TestResult,
767
- headers: Dict[str, Any],
772
+ headers: dict[str, Any],
768
773
  store_interactions: bool,
769
774
  feedback: Feedback,
770
- max_response_time: Optional[int],
775
+ max_response_time: int | None,
771
776
  ) -> WSGIResponse:
772
777
  with catching_logs(LogCaptureHandler(), level=logging.DEBUG) as recorded:
773
778
  start = time.monotonic()
@@ -780,7 +785,7 @@ def _wsgi_test(
780
785
  run_targets(targets, context)
781
786
  result.logs.extend(recorded.records)
782
787
  status = Status.success
783
- check_results: List[Check] = []
788
+ check_results: list[Check] = []
784
789
  try:
785
790
  run_checks(
786
791
  case=case,
@@ -802,8 +807,8 @@ def _wsgi_test(
802
807
 
803
808
 
804
809
  def _prepare_wsgi_headers(
805
- headers: Optional[Dict[str, Any]], auth: Optional[RawAuth], auth_type: Optional[str]
806
- ) -> Dict[str, Any]:
810
+ headers: dict[str, Any] | None, auth: RawAuth | None, auth_type: str | None
811
+ ) -> dict[str, Any]:
807
812
  headers = headers or {}
808
813
  if "user-agent" not in {header.lower() for header in headers}:
809
814
  headers["User-Agent"] = USER_AGENT
@@ -813,7 +818,7 @@ def _prepare_wsgi_headers(
813
818
  return headers
814
819
 
815
820
 
816
- def get_wsgi_auth(auth: Optional[RawAuth], auth_type: Optional[str]) -> Optional[str]:
821
+ def get_wsgi_auth(auth: RawAuth | None, auth_type: str | None) -> str | None:
817
822
  if auth:
818
823
  if auth_type == "digest":
819
824
  raise ValueError("Digest auth is not supported for WSGI apps")
@@ -827,12 +832,12 @@ def asgi_test(
827
832
  targets: Iterable[Target],
828
833
  result: TestResult,
829
834
  store_interactions: bool,
830
- headers: Optional[Dict[str, Any]],
835
+ headers: dict[str, Any] | None,
831
836
  feedback: Feedback,
832
- max_response_time: Optional[int],
833
- data_generation_methods: List[DataGenerationMethod],
837
+ max_response_time: int | None,
838
+ data_generation_methods: list[DataGenerationMethod],
834
839
  dry_run: bool,
835
- errors: List[Exception],
840
+ errors: list[Exception],
836
841
  ) -> None:
837
842
  """A single test body will be executed against the target."""
838
843
  with ErrorCollector(errors):
@@ -860,18 +865,18 @@ def _asgi_test(
860
865
  targets: Iterable[Target],
861
866
  result: TestResult,
862
867
  store_interactions: bool,
863
- headers: Optional[Dict[str, Any]],
868
+ headers: dict[str, Any] | None,
864
869
  feedback: Feedback,
865
- max_response_time: Optional[int],
870
+ max_response_time: int | None,
866
871
  ) -> requests.Response:
867
872
  hook_context = HookContext(operation=case.operation)
868
- kwargs: Dict[str, Any] = {"headers": headers}
873
+ kwargs: dict[str, Any] = {"headers": headers}
869
874
  hooks.dispatch("process_call_kwargs", hook_context, case, kwargs)
870
875
  response = case.call_asgi(**kwargs)
871
876
  context = TargetContext(case=case, response=response, response_time=response.elapsed.total_seconds())
872
877
  run_targets(targets, context)
873
878
  status = Status.success
874
- check_results: List[Check] = []
879
+ check_results: list[Check] = []
875
880
  try:
876
881
  run_checks(
877
882
  case=case,
@@ -1,6 +1,7 @@
1
+ from __future__ import annotations
1
2
  import threading
2
3
  from dataclasses import dataclass
3
- from typing import Generator, Optional, Union
4
+ from typing import Generator
4
5
 
5
6
  from ...models import TestResultSet
6
7
  from ...types import RequestCert
@@ -13,8 +14,8 @@ from .core import BaseRunner, asgi_test, get_session, network_test, wsgi_test
13
14
  class SingleThreadRunner(BaseRunner):
14
15
  """Fast runner that runs tests sequentially in the main thread."""
15
16
 
16
- request_tls_verify: Union[bool, str] = True
17
- request_cert: Optional[RequestCert] = None
17
+ request_tls_verify: bool | str = True
18
+ request_cert: RequestCert | None = None
18
19
 
19
20
  def _execute(
20
21
  self, results: TestResultSet, stop_event: threading.Event
@@ -28,10 +29,11 @@ class SingleThreadRunner(BaseRunner):
28
29
  auth = get_requests_auth(self.auth, self.auth_type)
29
30
  with get_session(auth) as session:
30
31
  yield from self._run_tests(
31
- self.schema.get_all_tests,
32
- network_test,
33
- self.hypothesis_settings,
34
- self.seed,
32
+ maker=self.schema.get_all_tests,
33
+ template=network_test,
34
+ settings=self.hypothesis_settings,
35
+ generation_config=self.generation_config,
36
+ seed=self.seed,
35
37
  checks=self.checks,
36
38
  max_response_time=self.max_response_time,
37
39
  targets=self.targets,
@@ -50,10 +52,11 @@ class SingleThreadRunner(BaseRunner):
50
52
  class SingleThreadWSGIRunner(SingleThreadRunner):
51
53
  def _execute_impl(self, results: TestResultSet) -> Generator[events.ExecutionEvent, None, None]:
52
54
  yield from self._run_tests(
53
- self.schema.get_all_tests,
54
- wsgi_test,
55
- self.hypothesis_settings,
56
- self.seed,
55
+ maker=self.schema.get_all_tests,
56
+ template=wsgi_test,
57
+ settings=self.hypothesis_settings,
58
+ generation_config=self.generation_config,
59
+ seed=self.seed,
57
60
  checks=self.checks,
58
61
  max_response_time=self.max_response_time,
59
62
  targets=self.targets,
@@ -70,10 +73,11 @@ class SingleThreadWSGIRunner(SingleThreadRunner):
70
73
  class SingleThreadASGIRunner(SingleThreadRunner):
71
74
  def _execute_impl(self, results: TestResultSet) -> Generator[events.ExecutionEvent, None, None]:
72
75
  yield from self._run_tests(
73
- self.schema.get_all_tests,
74
- asgi_test,
75
- self.hypothesis_settings,
76
- self.seed,
76
+ maker=self.schema.get_all_tests,
77
+ template=asgi_test,
78
+ settings=self.hypothesis_settings,
79
+ generation_config=self.generation_config,
80
+ seed=self.seed,
77
81
  checks=self.checks,
78
82
  max_response_time=self.max_response_time,
79
83
  targets=self.targets,