schemathesis 3.13.0__py3-none-any.whl → 4.4.2__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 (245) hide show
  1. schemathesis/__init__.py +53 -25
  2. schemathesis/auths.py +507 -0
  3. schemathesis/checks.py +190 -25
  4. schemathesis/cli/__init__.py +27 -1016
  5. schemathesis/cli/__main__.py +4 -0
  6. schemathesis/cli/commands/__init__.py +133 -0
  7. schemathesis/cli/commands/data.py +10 -0
  8. schemathesis/cli/commands/run/__init__.py +602 -0
  9. schemathesis/cli/commands/run/context.py +228 -0
  10. schemathesis/cli/commands/run/events.py +60 -0
  11. schemathesis/cli/commands/run/executor.py +157 -0
  12. schemathesis/cli/commands/run/filters.py +53 -0
  13. schemathesis/cli/commands/run/handlers/__init__.py +46 -0
  14. schemathesis/cli/commands/run/handlers/base.py +45 -0
  15. schemathesis/cli/commands/run/handlers/cassettes.py +464 -0
  16. schemathesis/cli/commands/run/handlers/junitxml.py +60 -0
  17. schemathesis/cli/commands/run/handlers/output.py +1750 -0
  18. schemathesis/cli/commands/run/loaders.py +118 -0
  19. schemathesis/cli/commands/run/validation.py +256 -0
  20. schemathesis/cli/constants.py +5 -0
  21. schemathesis/cli/core.py +19 -0
  22. schemathesis/cli/ext/fs.py +16 -0
  23. schemathesis/cli/ext/groups.py +203 -0
  24. schemathesis/cli/ext/options.py +81 -0
  25. schemathesis/config/__init__.py +202 -0
  26. schemathesis/config/_auth.py +51 -0
  27. schemathesis/config/_checks.py +268 -0
  28. schemathesis/config/_diff_base.py +101 -0
  29. schemathesis/config/_env.py +21 -0
  30. schemathesis/config/_error.py +163 -0
  31. schemathesis/config/_generation.py +157 -0
  32. schemathesis/config/_health_check.py +24 -0
  33. schemathesis/config/_operations.py +335 -0
  34. schemathesis/config/_output.py +171 -0
  35. schemathesis/config/_parameters.py +19 -0
  36. schemathesis/config/_phases.py +253 -0
  37. schemathesis/config/_projects.py +543 -0
  38. schemathesis/config/_rate_limit.py +17 -0
  39. schemathesis/config/_report.py +120 -0
  40. schemathesis/config/_validator.py +9 -0
  41. schemathesis/config/_warnings.py +89 -0
  42. schemathesis/config/schema.json +975 -0
  43. schemathesis/core/__init__.py +72 -0
  44. schemathesis/core/adapter.py +34 -0
  45. schemathesis/core/compat.py +32 -0
  46. schemathesis/core/control.py +2 -0
  47. schemathesis/core/curl.py +100 -0
  48. schemathesis/core/deserialization.py +210 -0
  49. schemathesis/core/errors.py +588 -0
  50. schemathesis/core/failures.py +316 -0
  51. schemathesis/core/fs.py +19 -0
  52. schemathesis/core/hooks.py +20 -0
  53. schemathesis/core/jsonschema/__init__.py +13 -0
  54. schemathesis/core/jsonschema/bundler.py +183 -0
  55. schemathesis/core/jsonschema/keywords.py +40 -0
  56. schemathesis/core/jsonschema/references.py +222 -0
  57. schemathesis/core/jsonschema/types.py +41 -0
  58. schemathesis/core/lazy_import.py +15 -0
  59. schemathesis/core/loaders.py +107 -0
  60. schemathesis/core/marks.py +66 -0
  61. schemathesis/core/media_types.py +79 -0
  62. schemathesis/core/output/__init__.py +46 -0
  63. schemathesis/core/output/sanitization.py +54 -0
  64. schemathesis/core/parameters.py +45 -0
  65. schemathesis/core/rate_limit.py +60 -0
  66. schemathesis/core/registries.py +34 -0
  67. schemathesis/core/result.py +27 -0
  68. schemathesis/core/schema_analysis.py +17 -0
  69. schemathesis/core/shell.py +203 -0
  70. schemathesis/core/transforms.py +144 -0
  71. schemathesis/core/transport.py +223 -0
  72. schemathesis/core/validation.py +73 -0
  73. schemathesis/core/version.py +7 -0
  74. schemathesis/engine/__init__.py +28 -0
  75. schemathesis/engine/context.py +152 -0
  76. schemathesis/engine/control.py +44 -0
  77. schemathesis/engine/core.py +201 -0
  78. schemathesis/engine/errors.py +446 -0
  79. schemathesis/engine/events.py +284 -0
  80. schemathesis/engine/observations.py +42 -0
  81. schemathesis/engine/phases/__init__.py +108 -0
  82. schemathesis/engine/phases/analysis.py +28 -0
  83. schemathesis/engine/phases/probes.py +172 -0
  84. schemathesis/engine/phases/stateful/__init__.py +68 -0
  85. schemathesis/engine/phases/stateful/_executor.py +364 -0
  86. schemathesis/engine/phases/stateful/context.py +85 -0
  87. schemathesis/engine/phases/unit/__init__.py +220 -0
  88. schemathesis/engine/phases/unit/_executor.py +459 -0
  89. schemathesis/engine/phases/unit/_pool.py +82 -0
  90. schemathesis/engine/recorder.py +254 -0
  91. schemathesis/errors.py +47 -0
  92. schemathesis/filters.py +395 -0
  93. schemathesis/generation/__init__.py +25 -0
  94. schemathesis/generation/case.py +478 -0
  95. schemathesis/generation/coverage.py +1528 -0
  96. schemathesis/generation/hypothesis/__init__.py +121 -0
  97. schemathesis/generation/hypothesis/builder.py +992 -0
  98. schemathesis/generation/hypothesis/examples.py +56 -0
  99. schemathesis/generation/hypothesis/given.py +66 -0
  100. schemathesis/generation/hypothesis/reporting.py +285 -0
  101. schemathesis/generation/meta.py +227 -0
  102. schemathesis/generation/metrics.py +93 -0
  103. schemathesis/generation/modes.py +20 -0
  104. schemathesis/generation/overrides.py +127 -0
  105. schemathesis/generation/stateful/__init__.py +37 -0
  106. schemathesis/generation/stateful/state_machine.py +294 -0
  107. schemathesis/graphql/__init__.py +15 -0
  108. schemathesis/graphql/checks.py +109 -0
  109. schemathesis/graphql/loaders.py +285 -0
  110. schemathesis/hooks.py +270 -91
  111. schemathesis/openapi/__init__.py +13 -0
  112. schemathesis/openapi/checks.py +467 -0
  113. schemathesis/openapi/generation/__init__.py +0 -0
  114. schemathesis/openapi/generation/filters.py +72 -0
  115. schemathesis/openapi/loaders.py +315 -0
  116. schemathesis/pytest/__init__.py +5 -0
  117. schemathesis/pytest/control_flow.py +7 -0
  118. schemathesis/pytest/lazy.py +341 -0
  119. schemathesis/pytest/loaders.py +36 -0
  120. schemathesis/pytest/plugin.py +357 -0
  121. schemathesis/python/__init__.py +0 -0
  122. schemathesis/python/asgi.py +12 -0
  123. schemathesis/python/wsgi.py +12 -0
  124. schemathesis/schemas.py +683 -247
  125. schemathesis/specs/graphql/__init__.py +0 -1
  126. schemathesis/specs/graphql/nodes.py +27 -0
  127. schemathesis/specs/graphql/scalars.py +86 -0
  128. schemathesis/specs/graphql/schemas.py +395 -123
  129. schemathesis/specs/graphql/validation.py +33 -0
  130. schemathesis/specs/openapi/__init__.py +9 -1
  131. schemathesis/specs/openapi/_hypothesis.py +578 -317
  132. schemathesis/specs/openapi/adapter/__init__.py +10 -0
  133. schemathesis/specs/openapi/adapter/parameters.py +729 -0
  134. schemathesis/specs/openapi/adapter/protocol.py +59 -0
  135. schemathesis/specs/openapi/adapter/references.py +19 -0
  136. schemathesis/specs/openapi/adapter/responses.py +368 -0
  137. schemathesis/specs/openapi/adapter/security.py +144 -0
  138. schemathesis/specs/openapi/adapter/v2.py +30 -0
  139. schemathesis/specs/openapi/adapter/v3_0.py +30 -0
  140. schemathesis/specs/openapi/adapter/v3_1.py +30 -0
  141. schemathesis/specs/openapi/analysis.py +96 -0
  142. schemathesis/specs/openapi/checks.py +753 -74
  143. schemathesis/specs/openapi/converter.py +176 -37
  144. schemathesis/specs/openapi/definitions.py +599 -4
  145. schemathesis/specs/openapi/examples.py +581 -165
  146. schemathesis/specs/openapi/expressions/__init__.py +52 -5
  147. schemathesis/specs/openapi/expressions/extractors.py +25 -0
  148. schemathesis/specs/openapi/expressions/lexer.py +34 -31
  149. schemathesis/specs/openapi/expressions/nodes.py +97 -46
  150. schemathesis/specs/openapi/expressions/parser.py +35 -13
  151. schemathesis/specs/openapi/formats.py +122 -0
  152. schemathesis/specs/openapi/media_types.py +75 -0
  153. schemathesis/specs/openapi/negative/__init__.py +117 -68
  154. schemathesis/specs/openapi/negative/mutations.py +294 -104
  155. schemathesis/specs/openapi/negative/utils.py +3 -6
  156. schemathesis/specs/openapi/patterns.py +458 -0
  157. schemathesis/specs/openapi/references.py +60 -81
  158. schemathesis/specs/openapi/schemas.py +648 -650
  159. schemathesis/specs/openapi/serialization.py +53 -30
  160. schemathesis/specs/openapi/stateful/__init__.py +404 -69
  161. schemathesis/specs/openapi/stateful/control.py +87 -0
  162. schemathesis/specs/openapi/stateful/dependencies/__init__.py +232 -0
  163. schemathesis/specs/openapi/stateful/dependencies/inputs.py +428 -0
  164. schemathesis/specs/openapi/stateful/dependencies/models.py +341 -0
  165. schemathesis/specs/openapi/stateful/dependencies/naming.py +491 -0
  166. schemathesis/specs/openapi/stateful/dependencies/outputs.py +34 -0
  167. schemathesis/specs/openapi/stateful/dependencies/resources.py +339 -0
  168. schemathesis/specs/openapi/stateful/dependencies/schemas.py +447 -0
  169. schemathesis/specs/openapi/stateful/inference.py +254 -0
  170. schemathesis/specs/openapi/stateful/links.py +219 -78
  171. schemathesis/specs/openapi/types/__init__.py +3 -0
  172. schemathesis/specs/openapi/types/common.py +23 -0
  173. schemathesis/specs/openapi/types/v2.py +129 -0
  174. schemathesis/specs/openapi/types/v3.py +134 -0
  175. schemathesis/specs/openapi/utils.py +7 -6
  176. schemathesis/specs/openapi/warnings.py +75 -0
  177. schemathesis/transport/__init__.py +224 -0
  178. schemathesis/transport/asgi.py +26 -0
  179. schemathesis/transport/prepare.py +126 -0
  180. schemathesis/transport/requests.py +278 -0
  181. schemathesis/transport/serialization.py +329 -0
  182. schemathesis/transport/wsgi.py +175 -0
  183. schemathesis-4.4.2.dist-info/METADATA +213 -0
  184. schemathesis-4.4.2.dist-info/RECORD +192 -0
  185. {schemathesis-3.13.0.dist-info → schemathesis-4.4.2.dist-info}/WHEEL +1 -1
  186. schemathesis-4.4.2.dist-info/entry_points.txt +6 -0
  187. {schemathesis-3.13.0.dist-info → schemathesis-4.4.2.dist-info/licenses}/LICENSE +1 -1
  188. schemathesis/_compat.py +0 -41
  189. schemathesis/_hypothesis.py +0 -115
  190. schemathesis/cli/callbacks.py +0 -188
  191. schemathesis/cli/cassettes.py +0 -253
  192. schemathesis/cli/context.py +0 -36
  193. schemathesis/cli/debug.py +0 -21
  194. schemathesis/cli/handlers.py +0 -11
  195. schemathesis/cli/junitxml.py +0 -41
  196. schemathesis/cli/options.py +0 -51
  197. schemathesis/cli/output/__init__.py +0 -1
  198. schemathesis/cli/output/default.py +0 -508
  199. schemathesis/cli/output/short.py +0 -40
  200. schemathesis/constants.py +0 -79
  201. schemathesis/exceptions.py +0 -207
  202. schemathesis/extra/_aiohttp.py +0 -27
  203. schemathesis/extra/_flask.py +0 -10
  204. schemathesis/extra/_server.py +0 -16
  205. schemathesis/extra/pytest_plugin.py +0 -216
  206. schemathesis/failures.py +0 -131
  207. schemathesis/fixups/__init__.py +0 -29
  208. schemathesis/fixups/fast_api.py +0 -30
  209. schemathesis/lazy.py +0 -227
  210. schemathesis/models.py +0 -1041
  211. schemathesis/parameters.py +0 -88
  212. schemathesis/runner/__init__.py +0 -460
  213. schemathesis/runner/events.py +0 -240
  214. schemathesis/runner/impl/__init__.py +0 -3
  215. schemathesis/runner/impl/core.py +0 -755
  216. schemathesis/runner/impl/solo.py +0 -85
  217. schemathesis/runner/impl/threadpool.py +0 -367
  218. schemathesis/runner/serialization.py +0 -189
  219. schemathesis/serializers.py +0 -233
  220. schemathesis/service/__init__.py +0 -3
  221. schemathesis/service/client.py +0 -46
  222. schemathesis/service/constants.py +0 -12
  223. schemathesis/service/events.py +0 -39
  224. schemathesis/service/handler.py +0 -39
  225. schemathesis/service/models.py +0 -7
  226. schemathesis/service/serialization.py +0 -153
  227. schemathesis/service/worker.py +0 -40
  228. schemathesis/specs/graphql/loaders.py +0 -215
  229. schemathesis/specs/openapi/constants.py +0 -7
  230. schemathesis/specs/openapi/expressions/context.py +0 -12
  231. schemathesis/specs/openapi/expressions/pointers.py +0 -29
  232. schemathesis/specs/openapi/filters.py +0 -44
  233. schemathesis/specs/openapi/links.py +0 -302
  234. schemathesis/specs/openapi/loaders.py +0 -453
  235. schemathesis/specs/openapi/parameters.py +0 -413
  236. schemathesis/specs/openapi/security.py +0 -129
  237. schemathesis/specs/openapi/validation.py +0 -24
  238. schemathesis/stateful.py +0 -349
  239. schemathesis/targets.py +0 -32
  240. schemathesis/types.py +0 -38
  241. schemathesis/utils.py +0 -436
  242. schemathesis-3.13.0.dist-info/METADATA +0 -202
  243. schemathesis-3.13.0.dist-info/RECORD +0 -91
  244. schemathesis-3.13.0.dist-info/entry_points.txt +0 -6
  245. /schemathesis/{extra → cli/ext}/__init__.py +0 -0
@@ -1,7 +1,10 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
- from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union
4
+ from typing import Any, Callable, Dict, Generator, List
3
5
 
4
- from ...utils import compose
6
+ from schemathesis.core.parameters import LOCATION_TO_CONTAINER
7
+ from schemathesis.schemas import APIOperation
5
8
 
6
9
  Generated = Dict[str, Any]
7
10
  Definition = Dict[str, Any]
@@ -9,21 +12,38 @@ DefinitionList = List[Definition]
9
12
  MapFunction = Callable[[Generated], Generated]
10
13
 
11
14
 
15
+ def get_serializers_for_operation(operation: APIOperation) -> dict[str, Callable]:
16
+ serializers = {}
17
+ for location, container in LOCATION_TO_CONTAINER.items():
18
+ serializer = operation.get_parameter_serializer(location)
19
+ if serializer is not None:
20
+ serializers[container] = serializer
21
+ return serializers
22
+
23
+
12
24
  def make_serializer(
13
- func: Callable[[DefinitionList], Generator[Optional[Callable], None, None]]
14
- ) -> Callable[[DefinitionList], Optional[Callable]]:
25
+ func: Callable[[DefinitionList], Generator[Callable | None, None, None]],
26
+ ) -> Callable[[DefinitionList], Callable | None]:
15
27
  """A maker function to avoid code duplication."""
16
28
 
17
- def _wrapper(definitions: DefinitionList) -> Optional[Callable]:
18
- conversions = list(func(definitions))
19
- if conversions:
20
- return compose(*[conv for conv in conversions if conv is not None])
21
- return None
29
+ def _wrapper(definitions: DefinitionList) -> Callable | None:
30
+ functions = list(func(definitions))
31
+ if not functions:
32
+ return None
33
+
34
+ def composed(x: Any) -> Any:
35
+ result = x
36
+ for func in reversed(functions):
37
+ if func is not None:
38
+ result = func(result)
39
+ return result
40
+
41
+ return composed
22
42
 
23
43
  return _wrapper
24
44
 
25
45
 
26
- def _serialize_openapi3(definitions: DefinitionList) -> Generator[Optional[Callable], None, None]:
46
+ def _serialize_openapi3(definitions: DefinitionList) -> Generator[Callable | None, None, None]:
27
47
  """Different collection styles for Open API 3.0."""
28
48
  for definition in definitions:
29
49
  name = definition["name"]
@@ -37,7 +57,11 @@ def _serialize_openapi3(definitions: DefinitionList) -> Generator[Optional[Calla
37
57
  # Simple serialization
38
58
  style = definition.get("style")
39
59
  explode = definition.get("explode")
40
- type_ = definition.get("schema", {}).get("type")
60
+ schema = definition.get("schema", {})
61
+ if isinstance(schema, dict):
62
+ type_ = schema.get("type")
63
+ else:
64
+ type_ = None
41
65
  if definition["in"] == "path":
42
66
  yield from _serialize_path_openapi3(name, type_, style, explode)
43
67
  elif definition["in"] == "query":
@@ -49,9 +73,8 @@ def _serialize_openapi3(definitions: DefinitionList) -> Generator[Optional[Calla
49
73
 
50
74
 
51
75
  def _serialize_path_openapi3(
52
- name: str, type_: str, style: Optional[str], explode: Optional[bool]
53
- ) -> Generator[Optional[Callable], None, None]:
54
- # pylint: disable=too-many-branches
76
+ name: str, type_: str | None, style: str | None, explode: bool | None
77
+ ) -> Generator[Callable | None, None, None]:
55
78
  if style == "simple":
56
79
  if type_ == "object":
57
80
  if explode is False:
@@ -77,8 +100,8 @@ def _serialize_path_openapi3(
77
100
 
78
101
 
79
102
  def _serialize_query_openapi3(
80
- name: str, type_: str, style: Optional[str], explode: Optional[bool]
81
- ) -> Generator[Optional[Callable], None, None]:
103
+ name: str, type_: str | None, style: str | None, explode: bool | None
104
+ ) -> Generator[Callable | None, None, None]:
82
105
  if type_ == "object":
83
106
  if style == "deepObject":
84
107
  yield deep_object(name)
@@ -97,8 +120,8 @@ def _serialize_query_openapi3(
97
120
 
98
121
 
99
122
  def _serialize_header_openapi3(
100
- name: str, type_: str, explode: Optional[bool]
101
- ) -> Generator[Optional[Callable], None, None]:
123
+ name: str, type_: str | None, explode: bool | None
124
+ ) -> Generator[Callable | None, None, None]:
102
125
  # Headers should be coerced to a string so we can check it for validity later
103
126
  yield to_string(name)
104
127
  # Header parameters always use the "simple" style, that is, comma-separated values
@@ -112,8 +135,8 @@ def _serialize_header_openapi3(
112
135
 
113
136
 
114
137
  def _serialize_cookie_openapi3(
115
- name: str, type_: str, explode: Optional[bool]
116
- ) -> Generator[Optional[Callable], None, None]:
138
+ name: str, type_: str | None, explode: bool | None
139
+ ) -> Generator[Callable | None, None, None]:
117
140
  # Cookies should be coerced to a string so we can check it for validity later
118
141
  yield to_string(name)
119
142
  # Cookie parameters always use the "form" style
@@ -130,7 +153,7 @@ def _serialize_cookie_openapi3(
130
153
  yield comma_delimited_object(name)
131
154
 
132
155
 
133
- def _serialize_swagger2(definitions: DefinitionList) -> Generator[Optional[Callable], None, None]:
156
+ def _serialize_swagger2(definitions: DefinitionList) -> Generator[Callable | None, None, None]:
134
157
  """Different collection formats for Open API 2.0."""
135
158
  for definition in definitions:
136
159
  name = definition["name"]
@@ -166,11 +189,11 @@ def conversion(func: Callable[..., None]) -> Callable:
166
189
  return _wrapper
167
190
 
168
191
 
169
- def make_delimited(data: Optional[Dict[str, Any]], delimiter: str = ",") -> str:
192
+ def make_delimited(data: dict[str, Any] | None, delimiter: str = ",") -> str:
170
193
  return delimiter.join(f"{key}={value}" for key, value in force_dict(data or {}).items())
171
194
 
172
195
 
173
- def force_iterable(value: Any) -> Union[List, Tuple]:
196
+ def force_iterable(value: Any) -> list | tuple:
174
197
  """Converts the value to a list or a tuple.
175
198
 
176
199
  Only relevant for negative test scenarios where the original types might be changed.
@@ -180,7 +203,7 @@ def force_iterable(value: Any) -> Union[List, Tuple]:
180
203
  return [value]
181
204
 
182
205
 
183
- def force_dict(value: Any) -> Dict:
206
+ def force_dict(value: Any) -> dict:
184
207
  """Converts the value to a dictionary.
185
208
 
186
209
  Only relevant for negative test scenarios where the original types might be changed.
@@ -198,7 +221,7 @@ def to_json(item: Generated, name: str) -> None:
198
221
 
199
222
  @conversion
200
223
  def delimited(item: Generated, name: str, delimiter: str) -> None:
201
- item[name] = delimiter.join(map(str, force_iterable(item[name] or ())))
224
+ item[name] = delimiter.join(map(str, force_iterable(item[name] if item[name] is not None else ())))
202
225
 
203
226
 
204
227
  @conversion
@@ -228,7 +251,7 @@ def delimited_object(item: Generated, name: str) -> None:
228
251
  def extracted_object(item: Generated, name: str) -> None:
229
252
  """Merge a child node to the parent one."""
230
253
  generated = item.pop(name)
231
- if generated:
254
+ if generated and isinstance(generated, dict):
232
255
  item.update(generated)
233
256
  else:
234
257
  item[name] = ""
@@ -248,7 +271,7 @@ def label_primitive(item: Generated, name: str) -> None:
248
271
 
249
272
 
250
273
  @conversion
251
- def label_array(item: Generated, name: str, explode: Optional[bool]) -> None:
274
+ def label_array(item: Generated, name: str, explode: bool | None) -> None:
252
275
  """Serialize an array with the `label` style.
253
276
 
254
277
  Explode=True
@@ -271,7 +294,7 @@ def label_array(item: Generated, name: str, explode: Optional[bool]) -> None:
271
294
 
272
295
 
273
296
  @conversion
274
- def label_object(item: Generated, name: str, explode: Optional[bool]) -> None:
297
+ def label_object(item: Generated, name: str, explode: bool | None) -> None:
275
298
  """Serialize an object with the `label` style.
276
299
 
277
300
  Explode=True
@@ -307,7 +330,7 @@ def matrix_primitive(item: Generated, name: str) -> None:
307
330
 
308
331
 
309
332
  @conversion
310
- def matrix_array(item: Generated, name: str, explode: Optional[bool]) -> None:
333
+ def matrix_array(item: Generated, name: str, explode: bool | None) -> None:
311
334
  """Serialize an array with the `matrix` style.
312
335
 
313
336
  Explode=True
@@ -329,7 +352,7 @@ def matrix_array(item: Generated, name: str, explode: Optional[bool]) -> None:
329
352
 
330
353
 
331
354
  @conversion
332
- def matrix_object(item: Generated, name: str, explode: Optional[bool]) -> None:
355
+ def matrix_object(item: Generated, name: str, explode: bool | None) -> None:
333
356
  """Serialize an object with the `matrix` style.
334
357
 
335
358
  Explode=True