schemathesis 3.25.5__py3-none-any.whl → 4.0.0a1__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 (221) hide show
  1. schemathesis/__init__.py +27 -65
  2. schemathesis/auths.py +102 -82
  3. schemathesis/checks.py +126 -46
  4. schemathesis/cli/__init__.py +11 -1766
  5. schemathesis/cli/__main__.py +4 -0
  6. schemathesis/cli/commands/__init__.py +37 -0
  7. schemathesis/cli/commands/run/__init__.py +662 -0
  8. schemathesis/cli/commands/run/checks.py +80 -0
  9. schemathesis/cli/commands/run/context.py +117 -0
  10. schemathesis/cli/commands/run/events.py +35 -0
  11. schemathesis/cli/commands/run/executor.py +138 -0
  12. schemathesis/cli/commands/run/filters.py +194 -0
  13. schemathesis/cli/commands/run/handlers/__init__.py +46 -0
  14. schemathesis/cli/commands/run/handlers/base.py +18 -0
  15. schemathesis/cli/commands/run/handlers/cassettes.py +494 -0
  16. schemathesis/cli/commands/run/handlers/junitxml.py +54 -0
  17. schemathesis/cli/commands/run/handlers/output.py +746 -0
  18. schemathesis/cli/commands/run/hypothesis.py +105 -0
  19. schemathesis/cli/commands/run/loaders.py +129 -0
  20. schemathesis/cli/{callbacks.py → commands/run/validation.py} +103 -174
  21. schemathesis/cli/constants.py +5 -52
  22. schemathesis/cli/core.py +17 -0
  23. schemathesis/cli/ext/fs.py +14 -0
  24. schemathesis/cli/ext/groups.py +55 -0
  25. schemathesis/cli/{options.py → ext/options.py} +39 -10
  26. schemathesis/cli/hooks.py +36 -0
  27. schemathesis/contrib/__init__.py +1 -3
  28. schemathesis/contrib/openapi/__init__.py +1 -3
  29. schemathesis/contrib/openapi/fill_missing_examples.py +3 -5
  30. schemathesis/core/__init__.py +58 -0
  31. schemathesis/core/compat.py +25 -0
  32. schemathesis/core/control.py +2 -0
  33. schemathesis/core/curl.py +58 -0
  34. schemathesis/core/deserialization.py +65 -0
  35. schemathesis/core/errors.py +370 -0
  36. schemathesis/core/failures.py +285 -0
  37. schemathesis/core/fs.py +19 -0
  38. schemathesis/{_lazy_import.py → core/lazy_import.py} +1 -0
  39. schemathesis/core/loaders.py +104 -0
  40. schemathesis/core/marks.py +66 -0
  41. schemathesis/{transports/content_types.py → core/media_types.py} +17 -13
  42. schemathesis/core/output/__init__.py +69 -0
  43. schemathesis/core/output/sanitization.py +197 -0
  44. schemathesis/core/rate_limit.py +60 -0
  45. schemathesis/core/registries.py +31 -0
  46. schemathesis/{internal → core}/result.py +1 -1
  47. schemathesis/core/transforms.py +113 -0
  48. schemathesis/core/transport.py +108 -0
  49. schemathesis/core/validation.py +38 -0
  50. schemathesis/core/version.py +7 -0
  51. schemathesis/engine/__init__.py +30 -0
  52. schemathesis/engine/config.py +59 -0
  53. schemathesis/engine/context.py +119 -0
  54. schemathesis/engine/control.py +36 -0
  55. schemathesis/engine/core.py +157 -0
  56. schemathesis/engine/errors.py +394 -0
  57. schemathesis/engine/events.py +337 -0
  58. schemathesis/engine/phases/__init__.py +66 -0
  59. schemathesis/{cli → engine/phases}/probes.py +63 -70
  60. schemathesis/engine/phases/stateful/__init__.py +65 -0
  61. schemathesis/engine/phases/stateful/_executor.py +326 -0
  62. schemathesis/engine/phases/stateful/context.py +85 -0
  63. schemathesis/engine/phases/unit/__init__.py +174 -0
  64. schemathesis/engine/phases/unit/_executor.py +321 -0
  65. schemathesis/engine/phases/unit/_pool.py +74 -0
  66. schemathesis/engine/recorder.py +241 -0
  67. schemathesis/errors.py +31 -0
  68. schemathesis/experimental/__init__.py +18 -14
  69. schemathesis/filters.py +103 -14
  70. schemathesis/generation/__init__.py +21 -37
  71. schemathesis/generation/case.py +190 -0
  72. schemathesis/generation/coverage.py +931 -0
  73. schemathesis/generation/hypothesis/__init__.py +30 -0
  74. schemathesis/generation/hypothesis/builder.py +585 -0
  75. schemathesis/generation/hypothesis/examples.py +50 -0
  76. schemathesis/generation/hypothesis/given.py +66 -0
  77. schemathesis/generation/hypothesis/reporting.py +14 -0
  78. schemathesis/generation/hypothesis/strategies.py +16 -0
  79. schemathesis/generation/meta.py +115 -0
  80. schemathesis/generation/modes.py +28 -0
  81. schemathesis/generation/overrides.py +96 -0
  82. schemathesis/generation/stateful/__init__.py +20 -0
  83. schemathesis/{stateful → generation/stateful}/state_machine.py +68 -81
  84. schemathesis/generation/targets.py +69 -0
  85. schemathesis/graphql/__init__.py +15 -0
  86. schemathesis/graphql/checks.py +115 -0
  87. schemathesis/graphql/loaders.py +131 -0
  88. schemathesis/hooks.py +99 -67
  89. schemathesis/openapi/__init__.py +13 -0
  90. schemathesis/openapi/checks.py +412 -0
  91. schemathesis/openapi/generation/__init__.py +0 -0
  92. schemathesis/openapi/generation/filters.py +63 -0
  93. schemathesis/openapi/loaders.py +178 -0
  94. schemathesis/pytest/__init__.py +5 -0
  95. schemathesis/pytest/control_flow.py +7 -0
  96. schemathesis/pytest/lazy.py +273 -0
  97. schemathesis/pytest/loaders.py +12 -0
  98. schemathesis/{extra/pytest_plugin.py → pytest/plugin.py} +106 -127
  99. schemathesis/python/__init__.py +0 -0
  100. schemathesis/python/asgi.py +12 -0
  101. schemathesis/python/wsgi.py +12 -0
  102. schemathesis/schemas.py +537 -261
  103. schemathesis/specs/graphql/__init__.py +0 -1
  104. schemathesis/specs/graphql/_cache.py +25 -0
  105. schemathesis/specs/graphql/nodes.py +1 -0
  106. schemathesis/specs/graphql/scalars.py +7 -5
  107. schemathesis/specs/graphql/schemas.py +215 -187
  108. schemathesis/specs/graphql/validation.py +11 -18
  109. schemathesis/specs/openapi/__init__.py +7 -1
  110. schemathesis/specs/openapi/_cache.py +122 -0
  111. schemathesis/specs/openapi/_hypothesis.py +146 -165
  112. schemathesis/specs/openapi/checks.py +565 -67
  113. schemathesis/specs/openapi/converter.py +33 -6
  114. schemathesis/specs/openapi/definitions.py +11 -18
  115. schemathesis/specs/openapi/examples.py +153 -39
  116. schemathesis/specs/openapi/expressions/__init__.py +37 -2
  117. schemathesis/specs/openapi/expressions/context.py +4 -6
  118. schemathesis/specs/openapi/expressions/extractors.py +23 -0
  119. schemathesis/specs/openapi/expressions/lexer.py +20 -18
  120. schemathesis/specs/openapi/expressions/nodes.py +38 -14
  121. schemathesis/specs/openapi/expressions/parser.py +26 -5
  122. schemathesis/specs/openapi/formats.py +45 -0
  123. schemathesis/specs/openapi/links.py +65 -165
  124. schemathesis/specs/openapi/media_types.py +32 -0
  125. schemathesis/specs/openapi/negative/__init__.py +7 -3
  126. schemathesis/specs/openapi/negative/mutations.py +24 -8
  127. schemathesis/specs/openapi/parameters.py +46 -30
  128. schemathesis/specs/openapi/patterns.py +137 -0
  129. schemathesis/specs/openapi/references.py +47 -57
  130. schemathesis/specs/openapi/schemas.py +483 -367
  131. schemathesis/specs/openapi/security.py +25 -7
  132. schemathesis/specs/openapi/serialization.py +11 -6
  133. schemathesis/specs/openapi/stateful/__init__.py +185 -73
  134. schemathesis/specs/openapi/utils.py +6 -1
  135. schemathesis/transport/__init__.py +104 -0
  136. schemathesis/transport/asgi.py +26 -0
  137. schemathesis/transport/prepare.py +99 -0
  138. schemathesis/transport/requests.py +221 -0
  139. schemathesis/{_xml.py → transport/serialization.py} +143 -28
  140. schemathesis/transport/wsgi.py +165 -0
  141. schemathesis-4.0.0a1.dist-info/METADATA +297 -0
  142. schemathesis-4.0.0a1.dist-info/RECORD +152 -0
  143. {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/WHEEL +1 -1
  144. {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/entry_points.txt +1 -1
  145. schemathesis/_compat.py +0 -74
  146. schemathesis/_dependency_versions.py +0 -17
  147. schemathesis/_hypothesis.py +0 -246
  148. schemathesis/_override.py +0 -49
  149. schemathesis/cli/cassettes.py +0 -375
  150. schemathesis/cli/context.py +0 -55
  151. schemathesis/cli/debug.py +0 -26
  152. schemathesis/cli/handlers.py +0 -16
  153. schemathesis/cli/junitxml.py +0 -43
  154. schemathesis/cli/output/__init__.py +0 -1
  155. schemathesis/cli/output/default.py +0 -765
  156. schemathesis/cli/output/short.py +0 -40
  157. schemathesis/cli/sanitization.py +0 -20
  158. schemathesis/code_samples.py +0 -149
  159. schemathesis/constants.py +0 -55
  160. schemathesis/contrib/openapi/formats/__init__.py +0 -9
  161. schemathesis/contrib/openapi/formats/uuid.py +0 -15
  162. schemathesis/contrib/unique_data.py +0 -41
  163. schemathesis/exceptions.py +0 -560
  164. schemathesis/extra/_aiohttp.py +0 -27
  165. schemathesis/extra/_flask.py +0 -10
  166. schemathesis/extra/_server.py +0 -17
  167. schemathesis/failures.py +0 -209
  168. schemathesis/fixups/__init__.py +0 -36
  169. schemathesis/fixups/fast_api.py +0 -41
  170. schemathesis/fixups/utf8_bom.py +0 -29
  171. schemathesis/graphql.py +0 -4
  172. schemathesis/internal/__init__.py +0 -7
  173. schemathesis/internal/copy.py +0 -13
  174. schemathesis/internal/datetime.py +0 -5
  175. schemathesis/internal/deprecation.py +0 -34
  176. schemathesis/internal/jsonschema.py +0 -35
  177. schemathesis/internal/transformation.py +0 -15
  178. schemathesis/internal/validation.py +0 -34
  179. schemathesis/lazy.py +0 -361
  180. schemathesis/loaders.py +0 -120
  181. schemathesis/models.py +0 -1231
  182. schemathesis/parameters.py +0 -86
  183. schemathesis/runner/__init__.py +0 -555
  184. schemathesis/runner/events.py +0 -309
  185. schemathesis/runner/impl/__init__.py +0 -3
  186. schemathesis/runner/impl/core.py +0 -986
  187. schemathesis/runner/impl/solo.py +0 -90
  188. schemathesis/runner/impl/threadpool.py +0 -400
  189. schemathesis/runner/serialization.py +0 -411
  190. schemathesis/sanitization.py +0 -248
  191. schemathesis/serializers.py +0 -315
  192. schemathesis/service/__init__.py +0 -18
  193. schemathesis/service/auth.py +0 -11
  194. schemathesis/service/ci.py +0 -201
  195. schemathesis/service/client.py +0 -100
  196. schemathesis/service/constants.py +0 -38
  197. schemathesis/service/events.py +0 -57
  198. schemathesis/service/hosts.py +0 -107
  199. schemathesis/service/metadata.py +0 -46
  200. schemathesis/service/models.py +0 -49
  201. schemathesis/service/report.py +0 -255
  202. schemathesis/service/serialization.py +0 -184
  203. schemathesis/service/usage.py +0 -65
  204. schemathesis/specs/graphql/loaders.py +0 -344
  205. schemathesis/specs/openapi/filters.py +0 -49
  206. schemathesis/specs/openapi/loaders.py +0 -667
  207. schemathesis/specs/openapi/stateful/links.py +0 -92
  208. schemathesis/specs/openapi/validation.py +0 -25
  209. schemathesis/stateful/__init__.py +0 -133
  210. schemathesis/targets.py +0 -45
  211. schemathesis/throttling.py +0 -41
  212. schemathesis/transports/__init__.py +0 -5
  213. schemathesis/transports/auth.py +0 -15
  214. schemathesis/transports/headers.py +0 -35
  215. schemathesis/transports/responses.py +0 -52
  216. schemathesis/types.py +0 -35
  217. schemathesis/utils.py +0 -169
  218. schemathesis-3.25.5.dist-info/METADATA +0 -356
  219. schemathesis-3.25.5.dist-info/RECORD +0 -134
  220. /schemathesis/{extra → cli/ext}/__init__.py +0 -0
  221. {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/licenses/LICENSE +0 -0
@@ -1,86 +0,0 @@
1
- """API operation parameters.
2
-
3
- These are basic entities that describe what data could be sent to the API.
4
- """
5
- from __future__ import annotations
6
- from dataclasses import dataclass, field
7
- from typing import TYPE_CHECKING, Any, Generator, Generic, TypeVar
8
-
9
- if TYPE_CHECKING:
10
- from .models import APIOperation
11
-
12
-
13
- @dataclass(eq=False)
14
- class Parameter:
15
- """A logically separate parameter bound to a location (e.g., to "query string").
16
-
17
- For example, if the API requires multiple headers to be present, each header is presented as a separate
18
- `Parameter` instance.
19
- """
20
-
21
- # The parameter definition in the language acceptable by the API
22
- definition: Any
23
-
24
- @property
25
- def location(self) -> str:
26
- """Where this parameter is located.
27
-
28
- E.g. "query" or "body"
29
- """
30
- raise NotImplementedError
31
-
32
- @property
33
- def name(self) -> str:
34
- """Parameter name."""
35
- raise NotImplementedError
36
-
37
- @property
38
- def is_required(self) -> bool:
39
- """Whether the parameter is required for a successful API call."""
40
- raise NotImplementedError
41
-
42
- def serialize(self, operation: APIOperation) -> str:
43
- """Get parameter's string representation."""
44
- raise NotImplementedError
45
-
46
-
47
- P = TypeVar("P", bound=Parameter)
48
-
49
-
50
- @dataclass
51
- class ParameterSet(Generic[P]):
52
- """A set of parameters for the same location."""
53
-
54
- items: list[P] = field(default_factory=list)
55
-
56
- def add(self, parameter: P) -> None:
57
- """Add a new parameter."""
58
- self.items.append(parameter)
59
-
60
- def get(self, name: str) -> P | None:
61
- for parameter in self:
62
- if parameter.name == name:
63
- return parameter
64
- return None
65
-
66
- def contains(self, name: str) -> bool:
67
- return self.get(name) is not None
68
-
69
- def __contains__(self, item: str) -> bool:
70
- return self.contains(item)
71
-
72
- def __bool__(self) -> bool:
73
- return bool(self.items)
74
-
75
- def __iter__(self) -> Generator[P, None, None]:
76
- yield from iter(self.items)
77
-
78
- def __len__(self) -> int:
79
- return len(self.items)
80
-
81
- def __getitem__(self, item: int) -> P:
82
- return self.items[item]
83
-
84
-
85
- class PayloadAlternatives(ParameterSet[P]):
86
- """A set of alternative payloads."""
@@ -1,555 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from random import Random
4
- from typing import Any, Callable, Generator, Iterable, TYPE_CHECKING
5
- from urllib.parse import urlparse
6
-
7
- from .._override import CaseOverride
8
- from ..generation import DEFAULT_DATA_GENERATION_METHODS, DataGenerationMethod, GenerationConfig
9
- from ..constants import (
10
- DEFAULT_DEADLINE,
11
- DEFAULT_STATEFUL_RECURSION_LIMIT,
12
- HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER,
13
- )
14
- from ..internal.deprecation import deprecated_function
15
- from ..internal.datetime import current_datetime
16
- from ..internal.validation import file_exists
17
- from ..transports.auth import get_requests_auth
18
- from ..exceptions import SchemaError
19
- from ..loaders import load_app
20
- from ..specs.graphql import loaders as gql_loaders
21
- from ..specs.openapi import loaders as oas_loaders
22
- from ..targets import DEFAULT_TARGETS, Target
23
- from ..types import Filter, NotSet, RawAuth, RequestCert
24
-
25
- if TYPE_CHECKING:
26
- from . import events
27
- from ..models import CheckFunction
28
- from ..schemas import BaseSchema
29
- from .impl import BaseRunner
30
- from ..stateful import Stateful
31
- import hypothesis
32
-
33
-
34
- @deprecated_function(removed_in="4.0", replacement="schemathesis.runner.from_schema")
35
- def prepare(
36
- schema_uri: str | dict[str, Any],
37
- *,
38
- # Runtime behavior
39
- checks: Iterable[CheckFunction] | None = None,
40
- data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
41
- max_response_time: int | None = None,
42
- targets: Iterable[Target] = DEFAULT_TARGETS,
43
- workers_num: int = 1,
44
- seed: int | None = None,
45
- exit_first: bool = False,
46
- dry_run: bool = False,
47
- store_interactions: bool = False,
48
- stateful: Stateful | None = None,
49
- stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
50
- # Schema loading
51
- loader: Callable = oas_loaders.from_uri,
52
- base_url: str | None = None,
53
- auth: tuple[str, str] | None = None,
54
- auth_type: str | None = None,
55
- override: CaseOverride | None = None,
56
- headers: dict[str, str] | None = None,
57
- request_timeout: int | None = None,
58
- request_tls_verify: bool | str = True,
59
- request_cert: RequestCert | None = None,
60
- endpoint: Filter | None = None,
61
- method: Filter | None = None,
62
- tag: Filter | None = None,
63
- operation_id: Filter | None = None,
64
- app: str | None = None,
65
- validate_schema: bool = True,
66
- skip_deprecated_operations: bool = False,
67
- force_schema_version: str | None = None,
68
- count_operations: bool = True,
69
- count_links: bool = True,
70
- # Hypothesis-specific configuration
71
- hypothesis_deadline: int | NotSet | None = None,
72
- hypothesis_derandomize: bool | None = None,
73
- hypothesis_max_examples: int | None = None,
74
- hypothesis_phases: list[hypothesis.Phase] | None = None,
75
- hypothesis_report_multiple_bugs: bool | None = None,
76
- hypothesis_suppress_health_check: list[hypothesis.HealthCheck] | None = None,
77
- hypothesis_verbosity: hypothesis.Verbosity | None = None,
78
- ) -> Generator[events.ExecutionEvent, None, None]:
79
- """Prepare a generator that will run test cases against the given API definition."""
80
- from ..checks import DEFAULT_CHECKS
81
-
82
- checks = checks or DEFAULT_CHECKS
83
-
84
- validate_loader(loader, schema_uri)
85
-
86
- if auth is None:
87
- # Auth type doesn't matter if auth is not passed
88
- auth_type = None # type: ignore
89
- hypothesis_settings = prepare_hypothesis_settings(
90
- deadline=hypothesis_deadline,
91
- derandomize=hypothesis_derandomize,
92
- max_examples=hypothesis_max_examples,
93
- phases=hypothesis_phases,
94
- report_multiple_bugs=hypothesis_report_multiple_bugs,
95
- suppress_health_check=hypothesis_suppress_health_check,
96
- verbosity=hypothesis_verbosity,
97
- )
98
- return execute_from_schema(
99
- schema_uri=schema_uri,
100
- loader=loader,
101
- base_url=base_url,
102
- endpoint=endpoint,
103
- method=method,
104
- tag=tag,
105
- operation_id=operation_id,
106
- app=app,
107
- validate_schema=validate_schema,
108
- skip_deprecated_operations=skip_deprecated_operations,
109
- force_schema_version=force_schema_version,
110
- checks=checks,
111
- data_generation_methods=data_generation_methods,
112
- max_response_time=max_response_time,
113
- targets=targets,
114
- hypothesis_settings=hypothesis_settings,
115
- seed=seed,
116
- workers_num=workers_num,
117
- exit_first=exit_first,
118
- dry_run=dry_run,
119
- auth=auth,
120
- auth_type=auth_type,
121
- override=override,
122
- headers=headers,
123
- request_timeout=request_timeout,
124
- request_tls_verify=request_tls_verify,
125
- request_cert=request_cert,
126
- store_interactions=store_interactions,
127
- stateful=stateful,
128
- stateful_recursion_limit=stateful_recursion_limit,
129
- count_operations=count_operations,
130
- count_links=count_links,
131
- )
132
-
133
-
134
- def validate_loader(loader: Callable, schema_uri: str | dict[str, Any]) -> None:
135
- """Sanity checking for input schema & loader."""
136
- if loader not in (
137
- oas_loaders.from_uri,
138
- oas_loaders.from_aiohttp,
139
- oas_loaders.from_dict,
140
- oas_loaders.from_file,
141
- oas_loaders.from_path,
142
- oas_loaders.from_asgi,
143
- oas_loaders.from_wsgi,
144
- gql_loaders.from_dict,
145
- gql_loaders.from_url,
146
- gql_loaders.from_wsgi,
147
- ):
148
- # Custom loaders are not checked
149
- return
150
- if isinstance(schema_uri, dict):
151
- if loader not in (oas_loaders.from_dict, gql_loaders.from_dict):
152
- raise ValueError("Dictionary as a schema is allowed only with `from_dict` loader")
153
- elif loader in (oas_loaders.from_dict, gql_loaders.from_dict):
154
- raise ValueError("Schema should be a dictionary for `from_dict` loader")
155
-
156
-
157
- def execute_from_schema(
158
- *,
159
- schema_uri: str | dict[str, Any],
160
- loader: Callable = oas_loaders.from_uri,
161
- base_url: str | None = None,
162
- endpoint: Filter | None = None,
163
- method: Filter | None = None,
164
- tag: Filter | None = None,
165
- operation_id: Filter | None = None,
166
- app: str | None = None,
167
- validate_schema: bool = True,
168
- skip_deprecated_operations: bool = False,
169
- force_schema_version: str | None = None,
170
- checks: Iterable[CheckFunction],
171
- data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
172
- max_response_time: int | None = None,
173
- targets: Iterable[Target],
174
- workers_num: int = 1,
175
- hypothesis_settings: hypothesis.settings,
176
- auth: RawAuth | None = None,
177
- auth_type: str | None = None,
178
- override: CaseOverride | None = None,
179
- headers: dict[str, Any] | None = None,
180
- request_timeout: int | None = None,
181
- request_tls_verify: bool | str = True,
182
- request_cert: RequestCert | None = None,
183
- seed: int | None = None,
184
- exit_first: bool = False,
185
- dry_run: bool = False,
186
- store_interactions: bool = False,
187
- stateful: Stateful | None = None,
188
- stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
189
- count_operations: bool = True,
190
- count_links: bool = True,
191
- ) -> Generator[events.ExecutionEvent, None, None]:
192
- """Execute tests for the given schema.
193
-
194
- Provides the main testing loop and preparation step.
195
- """
196
- try:
197
- if app is not None:
198
- app = load_app(app)
199
- schema = load_schema(
200
- schema_uri,
201
- base_url=base_url,
202
- loader=loader,
203
- app=app,
204
- validate_schema=validate_schema,
205
- skip_deprecated_operations=skip_deprecated_operations,
206
- auth=auth,
207
- auth_type=auth_type,
208
- headers=headers,
209
- endpoint=endpoint,
210
- method=method,
211
- tag=tag,
212
- operation_id=operation_id,
213
- data_generation_methods=data_generation_methods,
214
- force_schema_version=force_schema_version,
215
- request_tls_verify=request_tls_verify,
216
- request_cert=request_cert,
217
- )
218
- yield from from_schema(
219
- schema,
220
- checks=checks,
221
- max_response_time=max_response_time,
222
- targets=targets,
223
- hypothesis_settings=hypothesis_settings,
224
- auth=auth,
225
- auth_type=auth_type,
226
- override=override,
227
- headers=headers,
228
- seed=seed,
229
- workers_num=workers_num,
230
- request_timeout=request_timeout,
231
- request_tls_verify=request_tls_verify,
232
- request_cert=request_cert,
233
- exit_first=exit_first,
234
- dry_run=dry_run,
235
- store_interactions=store_interactions,
236
- stateful=stateful,
237
- stateful_recursion_limit=stateful_recursion_limit,
238
- count_operations=count_operations,
239
- count_links=count_links,
240
- ).execute()
241
- except SchemaError as error:
242
- yield events.InternalError.from_schema_error(error)
243
- except Exception as exc:
244
- yield events.InternalError.from_exc(exc)
245
-
246
-
247
- def load_schema(
248
- schema_uri: str | dict[str, Any],
249
- *,
250
- base_url: str | None = None,
251
- loader: Callable = oas_loaders.from_uri,
252
- app: Any = None,
253
- validate_schema: bool = True,
254
- skip_deprecated_operations: bool = False,
255
- data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
256
- force_schema_version: str | None = None,
257
- request_tls_verify: bool | str = True,
258
- request_cert: RequestCert | None = None,
259
- # Network request parameters
260
- auth: tuple[str, str] | None = None,
261
- auth_type: str | None = None,
262
- headers: dict[str, str] | None = None,
263
- # Schema filters
264
- endpoint: Filter | None = None,
265
- method: Filter | None = None,
266
- tag: Filter | None = None,
267
- operation_id: Filter | None = None,
268
- ) -> BaseSchema:
269
- """Load schema via specified loader and parameters."""
270
- loader_options = {
271
- key: value
272
- for key, value in (
273
- ("base_url", base_url),
274
- ("endpoint", endpoint),
275
- ("method", method),
276
- ("tag", tag),
277
- ("operation_id", operation_id),
278
- ("app", app),
279
- ("data_generation_methods", data_generation_methods),
280
- )
281
- if value
282
- }
283
-
284
- if not isinstance(schema_uri, dict):
285
- if file_exists(schema_uri):
286
- loader = oas_loaders.from_path
287
- elif loader is not oas_loaders.from_path:
288
- if app is not None and not urlparse(schema_uri).netloc:
289
- # If `schema` is not an existing filesystem path, or a URL then it is considered as a path within
290
- # the given app
291
- loader = oas_loaders.get_loader_for_app(app)
292
- if headers:
293
- loader_options["headers"] = headers
294
- else:
295
- if headers:
296
- loader_options["headers"] = headers
297
- if auth:
298
- loader_options["auth"] = auth
299
- if auth_type:
300
- loader_options["auth_type"] = auth_type
301
-
302
- if loader is oas_loaders.from_uri and loader_options.get("auth"):
303
- loader_options["auth"] = get_requests_auth(loader_options["auth"], loader_options.pop("auth_type", None))
304
- if loader in (oas_loaders.from_uri, oas_loaders.from_aiohttp):
305
- loader_options["verify"] = request_tls_verify
306
- loader_options["cert"] = request_cert
307
-
308
- return loader(
309
- schema_uri,
310
- validate_schema=validate_schema,
311
- skip_deprecated_operations=skip_deprecated_operations,
312
- force_schema_version=force_schema_version,
313
- **loader_options,
314
- )
315
-
316
-
317
- def from_schema(
318
- schema: BaseSchema,
319
- *,
320
- override: CaseOverride | None = None,
321
- checks: Iterable[CheckFunction] | None = None,
322
- max_response_time: int | None = None,
323
- targets: Iterable[Target] = DEFAULT_TARGETS,
324
- workers_num: int = 1,
325
- hypothesis_settings: hypothesis.settings | None = None,
326
- generation_config: GenerationConfig | None = None,
327
- auth: RawAuth | None = None,
328
- auth_type: str | None = None,
329
- headers: dict[str, Any] | None = None,
330
- request_timeout: int | None = None,
331
- request_tls_verify: bool | str = True,
332
- request_proxy: str | None = None,
333
- request_cert: RequestCert | None = None,
334
- seed: int | None = None,
335
- exit_first: bool = False,
336
- max_failures: int | None = None,
337
- started_at: str | None = None,
338
- dry_run: bool = False,
339
- store_interactions: bool = False,
340
- stateful: Stateful | None = None,
341
- stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
342
- count_operations: bool = True,
343
- count_links: bool = True,
344
- ) -> BaseRunner:
345
- from starlette.applications import Starlette
346
- import hypothesis
347
- from ..checks import DEFAULT_CHECKS
348
- from .impl import (
349
- SingleThreadASGIRunner,
350
- SingleThreadRunner,
351
- SingleThreadWSGIRunner,
352
- ThreadPoolASGIRunner,
353
- ThreadPoolRunner,
354
- ThreadPoolWSGIRunner,
355
- )
356
-
357
- checks = checks or DEFAULT_CHECKS
358
-
359
- hypothesis_settings = hypothesis_settings or hypothesis.settings(deadline=DEFAULT_DEADLINE)
360
- generation_config = generation_config or GenerationConfig()
361
-
362
- # Use the same seed for all tests unless `derandomize=True` is used
363
- if seed is None and not hypothesis_settings.derandomize:
364
- seed = Random().getrandbits(128)
365
-
366
- started_at = started_at or current_datetime()
367
- if workers_num > 1:
368
- if not schema.app:
369
- return ThreadPoolRunner(
370
- schema=schema,
371
- checks=checks,
372
- max_response_time=max_response_time,
373
- targets=targets,
374
- hypothesis_settings=hypothesis_settings,
375
- generation_config=generation_config,
376
- auth=auth,
377
- auth_type=auth_type,
378
- override=override,
379
- headers=headers,
380
- seed=seed,
381
- workers_num=workers_num,
382
- request_timeout=request_timeout,
383
- request_tls_verify=request_tls_verify,
384
- request_proxy=request_proxy,
385
- request_cert=request_cert,
386
- exit_first=exit_first,
387
- max_failures=max_failures,
388
- started_at=started_at,
389
- dry_run=dry_run,
390
- store_interactions=store_interactions,
391
- stateful=stateful,
392
- stateful_recursion_limit=stateful_recursion_limit,
393
- count_operations=count_operations,
394
- count_links=count_links,
395
- )
396
- if isinstance(schema.app, Starlette):
397
- return ThreadPoolASGIRunner(
398
- schema=schema,
399
- checks=checks,
400
- max_response_time=max_response_time,
401
- targets=targets,
402
- hypothesis_settings=hypothesis_settings,
403
- generation_config=generation_config,
404
- auth=auth,
405
- auth_type=auth_type,
406
- override=override,
407
- headers=headers,
408
- seed=seed,
409
- exit_first=exit_first,
410
- max_failures=max_failures,
411
- started_at=started_at,
412
- dry_run=dry_run,
413
- store_interactions=store_interactions,
414
- stateful=stateful,
415
- stateful_recursion_limit=stateful_recursion_limit,
416
- count_operations=count_operations,
417
- count_links=count_links,
418
- )
419
- return ThreadPoolWSGIRunner(
420
- schema=schema,
421
- checks=checks,
422
- max_response_time=max_response_time,
423
- targets=targets,
424
- hypothesis_settings=hypothesis_settings,
425
- generation_config=generation_config,
426
- auth=auth,
427
- auth_type=auth_type,
428
- override=override,
429
- headers=headers,
430
- seed=seed,
431
- workers_num=workers_num,
432
- exit_first=exit_first,
433
- max_failures=max_failures,
434
- started_at=started_at,
435
- dry_run=dry_run,
436
- store_interactions=store_interactions,
437
- stateful=stateful,
438
- stateful_recursion_limit=stateful_recursion_limit,
439
- count_operations=count_operations,
440
- count_links=count_links,
441
- )
442
- if not schema.app:
443
- return SingleThreadRunner(
444
- schema=schema,
445
- checks=checks,
446
- max_response_time=max_response_time,
447
- targets=targets,
448
- hypothesis_settings=hypothesis_settings,
449
- generation_config=generation_config,
450
- auth=auth,
451
- auth_type=auth_type,
452
- override=override,
453
- headers=headers,
454
- seed=seed,
455
- request_timeout=request_timeout,
456
- request_tls_verify=request_tls_verify,
457
- request_proxy=request_proxy,
458
- request_cert=request_cert,
459
- exit_first=exit_first,
460
- max_failures=max_failures,
461
- started_at=started_at,
462
- dry_run=dry_run,
463
- store_interactions=store_interactions,
464
- stateful=stateful,
465
- stateful_recursion_limit=stateful_recursion_limit,
466
- count_operations=count_operations,
467
- count_links=count_links,
468
- )
469
- if isinstance(schema.app, Starlette):
470
- return SingleThreadASGIRunner(
471
- schema=schema,
472
- checks=checks,
473
- max_response_time=max_response_time,
474
- targets=targets,
475
- hypothesis_settings=hypothesis_settings,
476
- generation_config=generation_config,
477
- auth=auth,
478
- auth_type=auth_type,
479
- override=override,
480
- headers=headers,
481
- seed=seed,
482
- exit_first=exit_first,
483
- max_failures=max_failures,
484
- started_at=started_at,
485
- dry_run=dry_run,
486
- store_interactions=store_interactions,
487
- stateful=stateful,
488
- stateful_recursion_limit=stateful_recursion_limit,
489
- count_operations=count_operations,
490
- count_links=count_links,
491
- )
492
- return SingleThreadWSGIRunner(
493
- schema=schema,
494
- checks=checks,
495
- max_response_time=max_response_time,
496
- targets=targets,
497
- hypothesis_settings=hypothesis_settings,
498
- generation_config=generation_config,
499
- auth=auth,
500
- auth_type=auth_type,
501
- override=override,
502
- headers=headers,
503
- seed=seed,
504
- exit_first=exit_first,
505
- max_failures=max_failures,
506
- started_at=started_at,
507
- dry_run=dry_run,
508
- store_interactions=store_interactions,
509
- stateful=stateful,
510
- stateful_recursion_limit=stateful_recursion_limit,
511
- count_operations=count_operations,
512
- count_links=count_links,
513
- )
514
-
515
-
516
- def prepare_hypothesis_settings(
517
- database: str | None = None,
518
- deadline: int | NotSet | None = None,
519
- derandomize: bool | None = None,
520
- max_examples: int | None = None,
521
- phases: list[hypothesis.Phase] | None = None,
522
- report_multiple_bugs: bool | None = None,
523
- suppress_health_check: list[hypothesis.HealthCheck] | None = None,
524
- verbosity: hypothesis.Verbosity | None = None,
525
- ) -> hypothesis.settings:
526
- import hypothesis
527
- from hypothesis.database import DirectoryBasedExampleDatabase, InMemoryExampleDatabase
528
-
529
- kwargs = {
530
- key: value
531
- for key, value in (
532
- ("derandomize", derandomize),
533
- ("max_examples", max_examples),
534
- ("phases", phases),
535
- ("report_multiple_bugs", report_multiple_bugs),
536
- ("suppress_health_check", suppress_health_check),
537
- ("verbosity", verbosity),
538
- )
539
- if value is not None
540
- }
541
- # `deadline` is special, since Hypothesis allows passing `None`
542
- if deadline is not None:
543
- if isinstance(deadline, NotSet):
544
- kwargs["deadline"] = None
545
- else:
546
- kwargs["deadline"] = deadline
547
- if database is not None:
548
- if database.lower() == "none":
549
- kwargs["database"] = None
550
- elif database == HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER:
551
- kwargs["database"] = InMemoryExampleDatabase()
552
- else:
553
- kwargs["database"] = DirectoryBasedExampleDatabase(database)
554
- kwargs.setdefault("deadline", DEFAULT_DEADLINE)
555
- return hypothesis.settings(print_blob=False, **kwargs)