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
schemathesis/utils.py DELETED
@@ -1,436 +0,0 @@
1
- import cgi
2
- import functools
3
- import pathlib
4
- import re
5
- import sys
6
- import traceback
7
- import warnings
8
- from contextlib import contextmanager
9
- from inspect import getfullargspec
10
- from json import JSONDecodeError
11
- from typing import (
12
- Any,
13
- Callable,
14
- Dict,
15
- Generator,
16
- Generic,
17
- List,
18
- NoReturn,
19
- Optional,
20
- Set,
21
- Tuple,
22
- Type,
23
- TypeVar,
24
- Union,
25
- overload,
26
- )
27
-
28
- import pytest
29
- import requests
30
- import yaml
31
- import yarl
32
- from hypothesis.core import is_invalid_test
33
- from hypothesis.reporting import with_reporter
34
- from hypothesis.strategies import SearchStrategy
35
- from hypothesis.utils.conventions import InferType
36
- from requests.auth import HTTPDigestAuth
37
- from requests.exceptions import InvalidHeader # type: ignore
38
- from requests.utils import check_header_validity # type: ignore
39
- from werkzeug.wrappers import Response as BaseResponse
40
- from werkzeug.wrappers.json import JSONMixin
41
-
42
- from .constants import USER_AGENT, DataGenerationMethod
43
- from .exceptions import UsageError
44
- from .types import DataGenerationMethodInput, Filter, GenericTest, NotSet, RawAuth
45
-
46
- try:
47
- from yaml import CSafeLoader as SafeLoader
48
- except ImportError:
49
- # pylint: disable=unused-import
50
- from yaml import SafeLoader # type: ignore
51
-
52
-
53
- NOT_SET = NotSet()
54
-
55
-
56
- def file_exists(path: str) -> bool:
57
- try:
58
- return pathlib.Path(path).is_file()
59
- except OSError:
60
- # For example, path could be too long
61
- return False
62
-
63
-
64
- def is_latin_1_encodable(value: str) -> bool:
65
- """Header values are encoded to latin-1 before sending."""
66
- try:
67
- value.encode("latin-1")
68
- return True
69
- except UnicodeEncodeError:
70
- return False
71
-
72
-
73
- # Adapted from http.client._is_illegal_header_value
74
- INVALID_HEADER_RE = re.compile(r"\n(?![ \t])|\r(?![ \t\n])") # pragma: no mutate
75
-
76
-
77
- def has_invalid_characters(name: str, value: str) -> bool:
78
- try:
79
- check_header_validity((name, value))
80
- return bool(INVALID_HEADER_RE.search(value))
81
- except InvalidHeader:
82
- return True
83
-
84
-
85
- def is_schemathesis_test(func: Callable) -> bool:
86
- """Check whether test is parametrized with schemathesis."""
87
- try:
88
- from .schemas import BaseSchema # pylint: disable=import-outside-toplevel
89
-
90
- item = getattr(func, PARAMETRIZE_MARKER, None)
91
- # Comparison is needed to avoid false-positives when mocks are collected by pytest
92
- return isinstance(item, BaseSchema)
93
- except Exception:
94
- return False
95
-
96
-
97
- def fail_on_no_matches(node_id: str) -> NoReturn: # type: ignore
98
- pytest.fail(f"Test function {node_id} does not match any API operations and therefore has no effect")
99
-
100
-
101
- def force_tuple(item: Filter) -> Union[List, Set, Tuple]:
102
- if not isinstance(item, (list, set, tuple)):
103
- return (item,)
104
- return item
105
-
106
-
107
- def dict_true_values(**kwargs: Any) -> Dict[str, Any]:
108
- """Create a dict with given kwargs while skipping items where bool(value) evaluates to False."""
109
- return {key: value for key, value in kwargs.items() if bool(value)}
110
-
111
-
112
- def dict_not_none_values(**kwargs: Any) -> Dict[str, Any]:
113
- return {key: value for key, value in kwargs.items() if value is not None}
114
-
115
-
116
- IGNORED_PATTERNS = (
117
- "Falsifying example: ",
118
- "You can add @seed",
119
- "Failed to reproduce exception. Expected:",
120
- "Flaky example!",
121
- "Traceback (most recent call last):",
122
- "You can reproduce this example by temporarily",
123
- )
124
-
125
-
126
- @contextmanager
127
- def capture_hypothesis_output() -> Generator[List[str], None, None]:
128
- """Capture all output of Hypothesis into a list of strings.
129
-
130
- It allows us to have more granular control over Schemathesis output.
131
-
132
- Usage::
133
-
134
- @given(i=st.integers())
135
- def test(i):
136
- assert 0
137
-
138
- with capture_hypothesis_output() as output:
139
- test() # hypothesis test
140
- # output == ["Falsifying example: test(i=0)"]
141
- """
142
- output = []
143
-
144
- def get_output(value: str) -> None:
145
- # Drop messages that could be confusing in the Schemathesis context
146
- if value.startswith(IGNORED_PATTERNS):
147
- return
148
- output.append(value)
149
-
150
- # the following context manager is untyped
151
- with with_reporter(get_output): # type: ignore
152
- yield output
153
-
154
-
155
- def format_exception(error: Exception, include_traceback: bool = False) -> str:
156
- """Format exception as text."""
157
- error_type = type(error)
158
- if include_traceback:
159
- lines = traceback.format_exception(error_type, error, error.__traceback__)
160
- else:
161
- lines = traceback.format_exception_only(error_type, error)
162
- return "".join(lines)
163
-
164
-
165
- def parse_content_type(content_type: str) -> Tuple[str, str]:
166
- """Parse Content Type and return main type and subtype."""
167
- try:
168
- content_type, _ = cgi.parse_header(content_type)
169
- main_type, sub_type = content_type.split("/", 1)
170
- except ValueError as exc:
171
- raise ValueError(f"Malformed media type: `{content_type}`") from exc
172
- return main_type.lower(), sub_type.lower()
173
-
174
-
175
- def is_json_media_type(value: str) -> bool:
176
- """Detect whether the content type is JSON-compatible.
177
-
178
- For example - ``application/problem+json`` matches.
179
- """
180
- main, sub = parse_content_type(value)
181
- return main == "application" and (sub == "json" or sub.endswith("+json"))
182
-
183
-
184
- def is_plain_text_media_type(value: str) -> bool:
185
- """Detect variations of the ``text/plain`` media type."""
186
- return parse_content_type(value) == ("text", "plain")
187
-
188
-
189
- def are_content_types_equal(source: str, target: str) -> bool:
190
- """Check if two content types are the same excluding options."""
191
- return parse_content_type(source) == parse_content_type(target)
192
-
193
-
194
- def make_loader(*tags_to_remove: str) -> Type[yaml.SafeLoader]:
195
- """Create a YAML loader, that doesn't parse specific tokens into Python objects."""
196
- cls: Type[yaml.SafeLoader] = type("YAMLLoader", (SafeLoader,), {})
197
- cls.yaml_implicit_resolvers = {
198
- key: [(tag, regexp) for tag, regexp in mapping if tag not in tags_to_remove]
199
- for key, mapping in cls.yaml_implicit_resolvers.copy().items()
200
- }
201
-
202
- # Fix pyyaml scientific notation parse bug
203
- # See PR: https://github.com/yaml/pyyaml/pull/174 for upstream fix
204
- cls.add_implicit_resolver( # type: ignore
205
- "tag:yaml.org,2002:float",
206
- re.compile(
207
- r"""^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+]?[0-9]+)?
208
- |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
209
- |\.[0-9_]+(?:[eE][-+]?[0-9]+)?
210
- |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
211
- |[-+]?\.(?:inf|Inf|INF)
212
- |\.(?:nan|NaN|NAN))$""",
213
- re.X,
214
- ),
215
- list("-+0123456789."),
216
- )
217
-
218
- return cls
219
-
220
-
221
- StringDatesYAMLLoader = make_loader("tag:yaml.org,2002:timestamp")
222
-
223
-
224
- class WSGIResponse(BaseResponse, JSONMixin): # pylint: disable=too-many-ancestors
225
- # We store "requests" request to build a reproduction code
226
- request: requests.PreparedRequest
227
-
228
- def on_json_loading_failed(self, e: JSONDecodeError) -> NoReturn:
229
- # We don't need a werkzeug-specific exception when JSON parsing error happens
230
- raise e
231
-
232
-
233
- def get_requests_auth(auth: Optional[RawAuth], auth_type: Optional[str]) -> Optional[Union[HTTPDigestAuth, RawAuth]]:
234
- if auth and auth_type == "digest":
235
- return HTTPDigestAuth(*auth)
236
- return auth
237
-
238
-
239
- GenericResponse = Union[requests.Response, WSGIResponse] # pragma: no mutate
240
-
241
-
242
- def get_response_payload(response: GenericResponse) -> str:
243
- if isinstance(response, requests.Response):
244
- return response.text
245
- return response.get_data(as_text=True)
246
-
247
-
248
- def import_app(path: str) -> Any:
249
- """Import an application from a string."""
250
- path, name = (re.split(r":(?![\\/])", path, 1) + [""])[:2]
251
- __import__(path)
252
- # accessing the module from sys.modules returns a proper module, while `__import__`
253
- # may return a parent module (system dependent)
254
- module = sys.modules[path]
255
- return getattr(module, name)
256
-
257
-
258
- Schema = Union[Dict[str, Any], List, str, float, int]
259
-
260
-
261
- @overload
262
- def traverse_schema(schema: Dict[str, Any], callback: Callable, *args: Any, **kwargs: Any) -> Dict[str, Any]:
263
- pass
264
-
265
-
266
- @overload
267
- def traverse_schema(schema: List, callback: Callable, *args: Any, **kwargs: Any) -> List:
268
- pass
269
-
270
-
271
- @overload
272
- def traverse_schema(schema: str, callback: Callable, *args: Any, **kwargs: Any) -> str:
273
- pass
274
-
275
-
276
- @overload
277
- def traverse_schema(schema: float, callback: Callable, *args: Any, **kwargs: Any) -> float:
278
- pass
279
-
280
-
281
- def traverse_schema(schema: Schema, callback: Callable[..., Dict[str, Any]], *args: Any, **kwargs: Any) -> Schema:
282
- """Apply callback recursively to the given schema."""
283
- if isinstance(schema, dict):
284
- schema = callback(schema, *args, **kwargs)
285
- for key, sub_item in schema.items():
286
- schema[key] = traverse_schema(sub_item, callback, *args, **kwargs)
287
- elif isinstance(schema, list):
288
- schema = [traverse_schema(sub_item, callback, *args, **kwargs) for sub_item in schema]
289
- return schema
290
-
291
-
292
- def _warn_deprecation(*, thing: str, removed_in: str, replacement: str) -> None:
293
- warnings.warn(
294
- f"Property `{thing}` is deprecated and will be removed in Schemathesis {removed_in}. "
295
- f"Use `{replacement}` instead.",
296
- DeprecationWarning,
297
- )
298
-
299
-
300
- def deprecated_property(*, removed_in: str, replacement: str) -> Callable:
301
- def wrapper(prop: Callable) -> Callable:
302
- @property # type: ignore
303
- def inner(self: Any) -> Any:
304
- _warn_deprecation(thing=prop.__name__, removed_in=removed_in, replacement=replacement)
305
- return prop(self)
306
-
307
- return inner
308
-
309
- return wrapper
310
-
311
-
312
- def deprecated(*, removed_in: str, replacement: str) -> Callable:
313
- def wrapper(func: Callable) -> Callable:
314
- def inner(*args: Any, **kwargs: Any) -> Any:
315
- _warn_deprecation(thing=func.__name__, removed_in=removed_in, replacement=replacement)
316
- return func(*args, **kwargs)
317
-
318
- return inner
319
-
320
- return wrapper
321
-
322
-
323
- def setup_headers(kwargs: Dict[str, Any]) -> None:
324
- headers = kwargs.setdefault("headers", {})
325
- if "user-agent" not in {header.lower() for header in headers}:
326
- kwargs["headers"]["User-Agent"] = USER_AGENT
327
-
328
-
329
- def require_relative_url(url: str) -> None:
330
- """Raise an error if the URL is not relative."""
331
- if yarl.URL(url).is_absolute():
332
- raise ValueError("Schema path should be relative for WSGI/ASGI loaders")
333
-
334
-
335
- T = TypeVar("T")
336
- E = TypeVar("E", bound=Exception)
337
-
338
-
339
- class Ok(Generic[T]):
340
- __slots__ = ("_value",)
341
-
342
- def __init__(self, value: T):
343
- self._value = value
344
-
345
- def ok(self) -> T:
346
- return self._value
347
-
348
-
349
- class Err(Generic[E]):
350
- __slots__ = ("_error",)
351
-
352
- def __init__(self, error: E):
353
- self._error = error
354
-
355
- def err(self) -> E:
356
- return self._error
357
-
358
-
359
- Result = Union[Ok[T], Err[E]]
360
- GivenInput = Union[SearchStrategy, InferType]
361
- PARAMETRIZE_MARKER = "_schemathesis_test"
362
- GIVEN_ARGS_MARKER = "_schemathesis_given_args"
363
- GIVEN_KWARGS_MARKER = "_schemathesis_given_kwargs"
364
-
365
-
366
- def get_given_args(func: GenericTest) -> Tuple:
367
- return getattr(func, GIVEN_ARGS_MARKER, ())
368
-
369
-
370
- def get_given_kwargs(func: GenericTest) -> Dict[str, Any]:
371
- return getattr(func, GIVEN_KWARGS_MARKER, {})
372
-
373
-
374
- def is_given_applied(func: GenericTest) -> bool:
375
- return hasattr(func, GIVEN_ARGS_MARKER) or hasattr(func, GIVEN_KWARGS_MARKER)
376
-
377
-
378
- def given_proxy(*args: GivenInput, **kwargs: GivenInput) -> Callable[[GenericTest], GenericTest]:
379
- """Proxy Hypothesis strategies to ``hypothesis.given``."""
380
-
381
- def wrapper(func: GenericTest) -> GenericTest:
382
- if hasattr(func, GIVEN_ARGS_MARKER):
383
-
384
- def wrapped_test(*_: Any, **__: Any) -> NoReturn:
385
- raise UsageError(
386
- f"You have applied `given` to the `{func.__name__}` test more than once, which "
387
- "overrides the previous decorator. You need to pass all arguments to the same `given` call."
388
- )
389
-
390
- return wrapped_test
391
-
392
- setattr(func, GIVEN_ARGS_MARKER, args)
393
- setattr(func, GIVEN_KWARGS_MARKER, kwargs)
394
- return func
395
-
396
- return wrapper
397
-
398
-
399
- def merge_given_args(func: GenericTest, args: Tuple, kwargs: Dict[str, Any]) -> Dict[str, Any]:
400
- """Merge positional arguments to ``@schema.given`` into a dictionary with keyword arguments.
401
-
402
- Kwargs are modified inplace.
403
- """
404
- if args:
405
- argspec = getfullargspec(func)
406
- for name, strategy in zip(reversed([arg for arg in argspec.args if arg != "case"]), reversed(args)):
407
- kwargs[name] = strategy
408
- return kwargs
409
-
410
-
411
- def validate_given_args(func: GenericTest, args: Tuple, kwargs: Dict[str, Any]) -> Optional[Callable]:
412
- argspec = getfullargspec(func)
413
- return is_invalid_test(func, argspec, args, kwargs) # type: ignore
414
-
415
-
416
- def compose(*functions: Callable) -> Callable:
417
- """Compose multiple functions into a single one."""
418
-
419
- def noop(x: Any) -> Any:
420
- return x
421
-
422
- return functools.reduce(lambda f, g: lambda x: f(g(x)), functions, noop)
423
-
424
-
425
- def maybe_set_assertion_message(exc: AssertionError, check_name: str) -> str:
426
- message = str(exc)
427
- if not message:
428
- message = f"Check '{check_name}' failed"
429
- exc.args = (message,)
430
- return message
431
-
432
-
433
- def prepare_data_generation_methods(data_generation_methods: DataGenerationMethodInput) -> List[DataGenerationMethod]:
434
- if isinstance(data_generation_methods, DataGenerationMethod):
435
- return [data_generation_methods]
436
- return list(data_generation_methods)
@@ -1,202 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: schemathesis
3
- Version: 3.13.0
4
- Summary: Property-based testing framework for Open API and GraphQL based apps
5
- Home-page: https://github.com/schemathesis/schemathesis
6
- License: MIT
7
- Keywords: pytest,hypothesis,openapi,swagger,graphql,testing
8
- Author: Dmitry Dygalo
9
- Author-email: dadygalo@gmail.com
10
- Maintainer: Dmitry Dygalo
11
- Maintainer-email: dadygalo@gmail.com
12
- Requires-Python: >=3.7,<4.0
13
- Classifier: Development Status :: 5 - Production/Stable
14
- Classifier: Environment :: Console
15
- Classifier: Framework :: Hypothesis
16
- Classifier: Framework :: Pytest
17
- Classifier: Intended Audience :: Developers
18
- Classifier: License :: OSI Approved :: MIT License
19
- Classifier: Operating System :: OS Independent
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3 :: Only
22
- Classifier: Programming Language :: Python :: 3.10
23
- Classifier: Programming Language :: Python :: 3.7
24
- Classifier: Programming Language :: Python :: 3.8
25
- Classifier: Programming Language :: Python :: 3.9
26
- Classifier: Programming Language :: Python :: Implementation :: CPython
27
- Classifier: Topic :: Software Development :: Testing
28
- Requires-Dist: attrs (>=19.2)
29
- Requires-Dist: click (>=8.0,<9.0)
30
- Requires-Dist: colorama (>=0.4,<0.5)
31
- Requires-Dist: curlify (>=2.2.1,<3.0.0)
32
- Requires-Dist: hypothesis (>=6.13.3,<7.0)
33
- Requires-Dist: hypothesis_graphql (>=0.5.0)
34
- Requires-Dist: hypothesis_jsonschema (>=0.22.0)
35
- Requires-Dist: importlib_metadata (>=1.1,!=3.8); python_version < "3.8"
36
- Requires-Dist: jsonschema (>=4.3.2,<5.0.0)
37
- Requires-Dist: junit-xml (>=1.9,<2.0)
38
- Requires-Dist: pytest (>4.6.4)
39
- Requires-Dist: pytest-subtests (>=0.2.1,<1.0)
40
- Requires-Dist: pyyaml (>=6.0,<7.0)
41
- Requires-Dist: requests (>=2.22,<3.0)
42
- Requires-Dist: starlette (>=0.13,<1)
43
- Requires-Dist: typing-extensions (>=3.7,<5)
44
- Requires-Dist: werkzeug (>=0.16.0)
45
- Requires-Dist: yarl (>=1.5,<2.0)
46
- Project-URL: Change Log, https://github.com/schemathesis/schemathesis/blob/master/docs/changelog.rst
47
- Project-URL: Documentation, https://schemathesis.readthedocs.io/en/stable/
48
- Project-URL: Funding, https://github.com/sponsors/Stranger6667
49
- Project-URL: Repository, https://github.com/schemathesis/schemathesis
50
- Project-URL: Source Code, https://github.com/schemathesis/schemathesis
51
- Description-Content-Type: text/x-rst
52
-
53
- Schemathesis
54
- ============
55
-
56
- |Build| |Coverage| |Version| |Python versions| |Docs| |Chat| |License|
57
-
58
- Schemathesis is a modern API testing tool for web applications built with Open API and GraphQL specifications.
59
-
60
- It reads the application schema and generates test cases, which will ensure that your application is compliant with its schema (read more about how it works in `our research paper <https://arxiv.org/abs/2112.10328>`_).
61
-
62
- The application under test could be written in any language; the only thing you need is a valid API schema in a supported format.
63
-
64
- Simple to use and yet powerful to uncover hard-to-find errors thanks to the property-based testing approach backed by state-of-the-art `Hypothesis <http://hypothesis.works/>`_ library.
65
-
66
- Features
67
- --------
68
-
69
- - Content-Type, schema, and status code conformance checks for Open API;
70
- - Testing of explicit examples from the input schema;
71
- - Stateful testing via Open API links;
72
- - Concurrent test execution;
73
- - Targeted testing;
74
- - Storing and replaying network requests;
75
- - Built-in ASGI / WSGI application support;
76
- - Code samples for easy failure reproduction;
77
- - Ready-to-go Docker image;
78
- - Configurable with user-defined checks, string formats, hooks, and targets.
79
-
80
- 📣 Schemathesis as a Service 📣
81
- -------------------------------
82
-
83
- Schemathesis will be available as `SaaS <https://schemathesis.io/?utm_source=github>`_ soon!
84
-
85
- It is freemium with much better visuals for debugging, more checks, and static analysis :)
86
-
87
- `Signup <http://eepurl.com/hN-0H1>`_ to get notified when it is ready!
88
-
89
- Installation
90
- ------------
91
-
92
- To install Schemathesis via ``pip`` run the following command:
93
-
94
- .. code:: bash
95
-
96
- pip install schemathesis
97
-
98
- You can also use our Docker image without installing Schemathesis as a Python package.
99
-
100
- 📣 **Please fill out our** `quick survey <https://forms.gle/dv4s5SXAYWzvuwFWA>`_ so that we can learn how satisfied you are with Schemathesis, and what improvements we should make. Thank you!
101
-
102
- Usage
103
- -----
104
-
105
- You can use Schemathesis in the command line directly:
106
-
107
- .. code:: bash
108
-
109
- schemathesis run --stateful=links --checks all http://0.0.0.0:8081/schema.yaml
110
-
111
- Or via Docker:
112
-
113
- .. code:: bash
114
-
115
- docker run schemathesis/schemathesis:stable run \
116
- --stateful=links --checks all http://0.0.0.0:8081/schema.yaml
117
-
118
- .. image:: https://raw.githubusercontent.com/schemathesis/schemathesis/master/img/schemathesis.gif
119
-
120
- Or in your Python tests:
121
-
122
- .. code:: python
123
-
124
- import schemathesis
125
-
126
- schema = schemathesis.from_uri("http://0.0.0.0:8081/schema.yaml")
127
-
128
-
129
- @schema.parametrize()
130
- def test_api(case):
131
- case.call_and_validate()
132
-
133
- CLI is simple to use and requires no coding; the in-code approach gives more flexibility.
134
-
135
- Both examples above will run hundreds of requests against the API under test and report all found failures and inconsistencies along with instructions to reproduce them.
136
-
137
- 💡 See a complete working example project in the ``/example`` directory. 💡
138
-
139
- Contributing
140
- ------------
141
-
142
- Any contribution to development, testing, or any other area is highly appreciated and useful to the project.
143
- For guidance on how to contribute to Schemathesis, see the `contributing guidelines <https://github.com/schemathesis/schemathesis/blob/master/CONTRIBUTING.rst>`_.
144
-
145
- Support this project
146
- --------------------
147
-
148
- Hi, my name is Dmitry! I started this project during my work at `Kiwi.com <https://kiwi.com/>`_. I am grateful to them for all the support they
149
- provided to this project during its early days and for the opportunity to evolve Schemathesis independently.
150
-
151
- In order to grow the community of contributors and users, and allow me to devote more time to this project, please `donate today <https://github.com/sponsors/Stranger6667>`_.
152
-
153
- Also, I occasionally write posts about Schemathesis in `my blog <https://dygalo.dev/>`_.
154
-
155
- Links
156
- -----
157
-
158
- - **Documentation**: https://schemathesis.readthedocs.io/en/stable/
159
- - **Releases**: https://pypi.org/project/schemathesis/
160
- - **Code**: https://github.com/schemathesis/schemathesis
161
- - **Issue tracker**: https://github.com/schemathesis/schemathesis/issues
162
- - **Chat**: https://gitter.im/schemathesis/schemathesis
163
-
164
- Additional content:
165
-
166
- - Research paper: `Deriving Semantics-Aware Fuzzers from Web API Schemas <https://arxiv.org/abs/2112.10328>`_ by **@Zac-HD** and **@Stranger6667**
167
- - `An article <https://dygalo.dev/blog/schemathesis-property-based-testing-for-api-schemas/>`_ about Schemathesis by **@Stranger6667**
168
- - `Effective API schemas testing <https://youtu.be/VVLZ25JgjD4>`_ from DevConf.cz by **@Stranger6667**
169
- - `A video <https://www.youtube.com/watch?v=9FHRwrv-xuQ>`_ from EuroPython 2020 by **@hultner**
170
- - `Schemathesis tutorial <https://appdev.consulting.redhat.com/tracks/contract-first/automated-testing-with-schemathesis.html>`_ with an accompanying `video <https://www.youtube.com/watch?v=4r7OC-lBKMg>`_ by Red Hat
171
- - `Using Hypothesis and Schemathesis to Test FastAPI <https://testdriven.io/blog/fastapi-hypothesis/>`_ by **@amalshaji**
172
-
173
- Non-English content:
174
-
175
- - `A tutorial <https://habr.com/ru/company/oleg-bunin/blog/576496/>`_ (RUS) about Schemathesis by **@Stranger6667**
176
-
177
- License
178
- -------
179
-
180
- The code in this project is licensed under `MIT license`_.
181
- By contributing to Schemathesis, you agree that your contributions will be licensed under its MIT license.
182
-
183
- .. |Build| image:: https://github.com/schemathesis/schemathesis/workflows/build/badge.svg
184
- :target: https://github.com/schemathesis/schemathesis/actions
185
- .. |Coverage| image:: https://codecov.io/gh/schemathesis/schemathesis/branch/master/graph/badge.svg
186
- :target: https://codecov.io/gh/schemathesis/schemathesis/branch/master
187
- :alt: codecov.io status for master branch
188
- .. |Version| image:: https://img.shields.io/pypi/v/schemathesis.svg
189
- :target: https://pypi.org/project/schemathesis/
190
- .. |Python versions| image:: https://img.shields.io/pypi/pyversions/schemathesis.svg
191
- :target: https://pypi.org/project/schemathesis/
192
- .. |License| image:: https://img.shields.io/pypi/l/schemathesis.svg
193
- :target: https://opensource.org/licenses/MIT
194
- .. |Chat| image:: https://img.shields.io/gitter/room/schemathesis/schemathesis.svg
195
- :target: https://gitter.im/schemathesis/schemathesis
196
- :alt: Gitter
197
- .. |Docs| image:: https://readthedocs.org/projects/schemathesis/badge/?version=stable
198
- :target: https://schemathesis.readthedocs.io/en/stable/?badge=stable
199
- :alt: Documentation Status
200
-
201
- .. _MIT license: https://opensource.org/licenses/MIT
202
-