schemathesis 3.15.4__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 (251) 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 -1219
  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 +682 -257
  125. schemathesis/specs/graphql/__init__.py +0 -1
  126. schemathesis/specs/graphql/nodes.py +26 -2
  127. schemathesis/specs/graphql/scalars.py +77 -12
  128. schemathesis/specs/graphql/schemas.py +367 -148
  129. schemathesis/specs/graphql/validation.py +33 -0
  130. schemathesis/specs/openapi/__init__.py +9 -1
  131. schemathesis/specs/openapi/_hypothesis.py +555 -318
  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 +748 -82
  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 +93 -73
  154. schemathesis/specs/openapi/negative/mutations.py +294 -103
  155. schemathesis/specs/openapi/negative/utils.py +0 -9
  156. schemathesis/specs/openapi/patterns.py +458 -0
  157. schemathesis/specs/openapi/references.py +60 -81
  158. schemathesis/specs/openapi/schemas.py +647 -666
  159. schemathesis/specs/openapi/serialization.py +53 -30
  160. schemathesis/specs/openapi/stateful/__init__.py +403 -68
  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.15.4.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.15.4.dist-info → schemathesis-4.4.2.dist-info/licenses}/LICENSE +1 -1
  188. schemathesis/_compat.py +0 -57
  189. schemathesis/_hypothesis.py +0 -123
  190. schemathesis/auth.py +0 -214
  191. schemathesis/cli/callbacks.py +0 -240
  192. schemathesis/cli/cassettes.py +0 -351
  193. schemathesis/cli/context.py +0 -38
  194. schemathesis/cli/debug.py +0 -21
  195. schemathesis/cli/handlers.py +0 -11
  196. schemathesis/cli/junitxml.py +0 -41
  197. schemathesis/cli/options.py +0 -70
  198. schemathesis/cli/output/__init__.py +0 -1
  199. schemathesis/cli/output/default.py +0 -521
  200. schemathesis/cli/output/short.py +0 -40
  201. schemathesis/constants.py +0 -88
  202. schemathesis/exceptions.py +0 -257
  203. schemathesis/extra/_aiohttp.py +0 -27
  204. schemathesis/extra/_flask.py +0 -10
  205. schemathesis/extra/_server.py +0 -16
  206. schemathesis/extra/pytest_plugin.py +0 -251
  207. schemathesis/failures.py +0 -145
  208. schemathesis/fixups/__init__.py +0 -29
  209. schemathesis/fixups/fast_api.py +0 -30
  210. schemathesis/graphql.py +0 -5
  211. schemathesis/internal.py +0 -6
  212. schemathesis/lazy.py +0 -301
  213. schemathesis/models.py +0 -1113
  214. schemathesis/parameters.py +0 -91
  215. schemathesis/runner/__init__.py +0 -470
  216. schemathesis/runner/events.py +0 -242
  217. schemathesis/runner/impl/__init__.py +0 -3
  218. schemathesis/runner/impl/core.py +0 -791
  219. schemathesis/runner/impl/solo.py +0 -85
  220. schemathesis/runner/impl/threadpool.py +0 -367
  221. schemathesis/runner/serialization.py +0 -206
  222. schemathesis/serializers.py +0 -253
  223. schemathesis/service/__init__.py +0 -18
  224. schemathesis/service/auth.py +0 -10
  225. schemathesis/service/client.py +0 -62
  226. schemathesis/service/constants.py +0 -25
  227. schemathesis/service/events.py +0 -39
  228. schemathesis/service/handler.py +0 -46
  229. schemathesis/service/hosts.py +0 -74
  230. schemathesis/service/metadata.py +0 -42
  231. schemathesis/service/models.py +0 -21
  232. schemathesis/service/serialization.py +0 -184
  233. schemathesis/service/worker.py +0 -39
  234. schemathesis/specs/graphql/loaders.py +0 -215
  235. schemathesis/specs/openapi/constants.py +0 -7
  236. schemathesis/specs/openapi/expressions/context.py +0 -12
  237. schemathesis/specs/openapi/expressions/pointers.py +0 -29
  238. schemathesis/specs/openapi/filters.py +0 -44
  239. schemathesis/specs/openapi/links.py +0 -303
  240. schemathesis/specs/openapi/loaders.py +0 -453
  241. schemathesis/specs/openapi/parameters.py +0 -430
  242. schemathesis/specs/openapi/security.py +0 -129
  243. schemathesis/specs/openapi/validation.py +0 -24
  244. schemathesis/stateful.py +0 -358
  245. schemathesis/targets.py +0 -32
  246. schemathesis/types.py +0 -38
  247. schemathesis/utils.py +0 -475
  248. schemathesis-3.15.4.dist-info/METADATA +0 -202
  249. schemathesis-3.15.4.dist-info/RECORD +0 -99
  250. schemathesis-3.15.4.dist-info/entry_points.txt +0 -7
  251. /schemathesis/{extra → cli/ext}/__init__.py +0 -0
schemathesis/stateful.py DELETED
@@ -1,358 +0,0 @@
1
- import enum
2
- import json
3
- import time
4
- from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Generator, List, Optional, Tuple
5
-
6
- import attr
7
- import hypothesis
8
- from hypothesis.stateful import RuleBasedStateMachine
9
- from requests.structures import CaseInsensitiveDict
10
- from starlette.applications import Starlette
11
-
12
- from .constants import DataGenerationMethod
13
- from .exceptions import InvalidSchema
14
- from .models import APIOperation, Case, CheckFunction
15
- from .utils import NOT_SET, GenericResponse, Ok, Result
16
-
17
- if TYPE_CHECKING:
18
- from .schemas import BaseSchema
19
-
20
-
21
- @enum.unique
22
- class Stateful(enum.Enum):
23
- none = 1
24
- links = 2
25
-
26
-
27
- @attr.s(slots=True, hash=False) # pragma: no mutate
28
- class ParsedData:
29
- """A structure that holds information parsed from a test outcome.
30
-
31
- It is used later to create a new version of an API operation that will reuse this data.
32
- """
33
-
34
- parameters: Dict[str, Any] = attr.ib() # pragma: no mutate
35
- body: Any = attr.ib(default=NOT_SET) # pragma: no mutate
36
-
37
- def __hash__(self) -> int:
38
- """Custom hash simplifies deduplication of parsed data."""
39
- value = hash(tuple(self.parameters.items())) # parameters never contain nested dicts / lists
40
- if self.body is not NOT_SET:
41
- if isinstance(self.body, (dict, list)):
42
- # The simplest way to get a hash of a potentially nested structure
43
- value ^= hash(json.dumps(self.body, sort_keys=True))
44
- else:
45
- # These types should be hashable
46
- value ^= hash(self.body)
47
- return value
48
-
49
-
50
- @attr.s(slots=True) # pragma: no mutate
51
- class StatefulTest:
52
- """A template for a test that will be executed after another one by reusing the outcomes from it."""
53
-
54
- name: str = attr.ib() # pragma: no mutate
55
-
56
- def parse(self, case: Case, response: GenericResponse) -> ParsedData:
57
- raise NotImplementedError
58
-
59
- def make_operation(self, collected: List[ParsedData]) -> APIOperation:
60
- raise NotImplementedError
61
-
62
-
63
- @attr.s(slots=True) # pragma: no mutate
64
- class StatefulData:
65
- """Storage for data that will be used in later tests."""
66
-
67
- stateful_test: StatefulTest = attr.ib() # pragma: no mutate
68
- container: List[ParsedData] = attr.ib(factory=list) # pragma: no mutate
69
-
70
- def make_operation(self) -> APIOperation:
71
- return self.stateful_test.make_operation(self.container)
72
-
73
- def store(self, case: Case, response: GenericResponse) -> None:
74
- """Parse and store data for a stateful test."""
75
- parsed = self.stateful_test.parse(case, response)
76
- self.container.append(parsed)
77
-
78
-
79
- @attr.s(slots=True) # pragma: no mutate
80
- class Feedback:
81
- """Handler for feedback from tests.
82
-
83
- Provides a way to control runner's behavior from tests.
84
- """
85
-
86
- stateful: Optional[Stateful] = attr.ib() # pragma: no mutate
87
- operation: APIOperation = attr.ib(repr=False) # pragma: no mutate
88
- stateful_tests: Dict[str, StatefulData] = attr.ib(factory=dict, repr=False) # pragma: no mutate
89
-
90
- def add_test_case(self, case: Case, response: GenericResponse) -> None:
91
- """Store test data to reuse it in the future additional tests."""
92
- for stateful_test in case.operation.get_stateful_tests(response, self.stateful):
93
- data = self.stateful_tests.setdefault(stateful_test.name, StatefulData(stateful_test))
94
- data.store(case, response)
95
-
96
- def get_stateful_tests(
97
- self, test: Callable, settings: Optional[hypothesis.settings], seed: Optional[int]
98
- ) -> Generator[Tuple[Result[Tuple[APIOperation, Callable], InvalidSchema], DataGenerationMethod], None, None]:
99
- """Generate additional tests that use data from the previous ones."""
100
- from ._hypothesis import create_test # pylint: disable=import-outside-toplevel
101
-
102
- for data in self.stateful_tests.values():
103
- operation = data.make_operation()
104
- for data_generation_method in operation.schema.data_generation_methods:
105
- test_function = create_test(
106
- operation=operation,
107
- test=test,
108
- settings=settings,
109
- seed=seed,
110
- data_generation_method=data_generation_method,
111
- )
112
- yield Ok((operation, test_function)), data_generation_method
113
-
114
-
115
- @attr.s(slots=True) # pragma: no mutate
116
- class StepResult:
117
- """Output from a single transition of a state machine."""
118
-
119
- response: GenericResponse = attr.ib() # pragma: no mutate
120
- case: Case = attr.ib() # pragma: no mutate
121
- elapsed: float = attr.ib() # pragma: no mutate
122
-
123
-
124
- class Direction:
125
- name: str
126
- status_code: str
127
- operation: APIOperation
128
-
129
- def set_data(self, case: Case, elapsed: float, **kwargs: Any) -> None:
130
- raise NotImplementedError
131
-
132
-
133
- def _print_case(case: Case) -> str:
134
- operation = f"state.schema['{case.operation.path}']['{case.operation.method.upper()}']"
135
- data = [
136
- f"{name}={repr(getattr(case, name))}"
137
- for name in ("path_parameters", "headers", "cookies", "query", "body", "media_type")
138
- if getattr(case, name) not in (None, NOT_SET)
139
- ]
140
- return f"{operation}.make_case({', '.join(data)})"
141
-
142
-
143
- @attr.s(slots=True, repr=False) # pragma: no mutate
144
- class _DirectionWrapper:
145
- """Purely to avoid modification of `Direction.__repr__`."""
146
-
147
- direction: Direction = attr.ib() # pragma: no mutate
148
-
149
- def __repr__(self) -> str:
150
- path = self.direction.operation.path
151
- method = self.direction.operation.method.upper()
152
- return f"state.schema['{path}']['{method}'].links['{self.direction.status_code}']['{self.direction.name}']"
153
-
154
-
155
- class APIStateMachine(RuleBasedStateMachine):
156
- """The base class for state machines generated from API schemas.
157
-
158
- Exposes additional extension points in the testing process.
159
- """
160
-
161
- # This is a convenience attribute, which happened to clash with `RuleBasedStateMachine` instance level attribute
162
- # They don't interfere, since it is properly overridden on the Hypothesis side, but it is likely that this
163
- # attribute will be renamed in the future
164
- bundles: ClassVar[Dict[str, CaseInsensitiveDict]] # type: ignore
165
- schema: "BaseSchema"
166
-
167
- def __init__(self) -> None:
168
- super().__init__() # type: ignore
169
- self.setup()
170
-
171
- def _pretty_print(self, value: Any) -> str:
172
- if isinstance(value, Case):
173
- return _print_case(value)
174
- if isinstance(value, tuple) and len(value) == 2:
175
- result, direction = value
176
- wrapper = _DirectionWrapper(direction)
177
- return super()._pretty_print((result, wrapper)) # type: ignore
178
- return super()._pretty_print(value) # type: ignore
179
-
180
- def setup(self) -> None:
181
- """Hook method that runs unconditionally in the beginning of each test scenario.
182
-
183
- Does nothing by default.
184
- """
185
-
186
- def teardown(self) -> None:
187
- pass
188
-
189
- # To provide the return type in the rendered documentation
190
- teardown.__doc__ = RuleBasedStateMachine.teardown.__doc__
191
-
192
- def transform(self, result: StepResult, direction: Direction, case: Case) -> Case:
193
- raise NotImplementedError
194
-
195
- def _step(self, case: Case, previous: Optional[Tuple[StepResult, Direction]] = None) -> StepResult:
196
- # This method is a proxy that is used under the hood during the state machine initialization.
197
- # The whole point of having it is to make it possible to override `step`; otherwise, custom "step" is ignored.
198
- # It happens because, at the point of initialization, the final class is not yet created.
199
- __tracebackhide__ = True # pylint: disable=unused-variable
200
- return self.step(case, previous)
201
-
202
- def step(self, case: Case, previous: Optional[Tuple[StepResult, Direction]] = None) -> StepResult:
203
- """A single state machine step.
204
-
205
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
206
- :param previous: Optional result from the previous step and the direction in which this step should be done.
207
-
208
- Schemathesis prepares data, makes a call and validates the received response.
209
- It is the most high-level point to extend the testing process. You probably don't need it in most cases.
210
- """
211
- __tracebackhide__ = True # pylint: disable=unused-variable
212
- if previous is not None:
213
- result, direction = previous
214
- case = self.transform(result, direction, case)
215
- self.before_call(case)
216
- kwargs = self.get_call_kwargs(case)
217
- start = time.monotonic()
218
- response = self.call(case, **kwargs)
219
- elapsed = time.monotonic() - start
220
- self.after_call(response, case)
221
- self.validate_response(response, case)
222
- return self.store_result(response, case, elapsed)
223
-
224
- def before_call(self, case: Case) -> None:
225
- """Hook method for modifying the case data before making a request.
226
-
227
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
228
-
229
- Use it if you want to inject static data, for example,
230
- a query parameter that should always be used in API calls:
231
-
232
- .. code-block:: python
233
-
234
- class APIWorkflow(schema.as_state_machine()):
235
- def before_call(self, case):
236
- case.query = case.query or {}
237
- case.query["test"] = "true"
238
-
239
- You can also modify data only for some operations:
240
-
241
- .. code-block:: python
242
-
243
- class APIWorkflow(schema.as_state_machine()):
244
- def before_call(self, case):
245
- if case.method == "PUT" and case.path == "/items":
246
- case.body["is_fake"] = True
247
- """
248
-
249
- def after_call(self, response: GenericResponse, case: Case) -> None:
250
- """Hook method for additional actions with case or response instances.
251
-
252
- :param response: Response from the application under test.
253
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
254
-
255
- For example, you can log all response statuses by using this hook:
256
-
257
- .. code-block:: python
258
-
259
- import logging
260
-
261
- logger = logging.getLogger(__file__)
262
- logger.setLevel(logging.INFO)
263
-
264
-
265
- class APIWorkflow(schema.as_state_machine()):
266
- def after_call(self, response, case):
267
- logger.info(
268
- "%s %s -> %d",
269
- case.method,
270
- case.path,
271
- response.status_code,
272
- )
273
-
274
-
275
- # POST /users/ -> 201
276
- # GET /users/{user_id} -> 200
277
- # PATCH /users/{user_id} -> 200
278
- # GET /users/{user_id} -> 200
279
- # PATCH /users/{user_id} -> 500
280
- """
281
-
282
- def call(self, case: Case, **kwargs: Any) -> GenericResponse:
283
- """Make a request to the API.
284
-
285
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
286
- :param kwargs: Keyword arguments that will be passed to the appropriate ``case.call_*`` method.
287
- :return: Response from the application under test.
288
-
289
- Note that WSGI/ASGI applications are detected automatically in this method. Depending on the result of this
290
- detection the state machine will call ``call``, ``call_wsgi`` or ``call_asgi`` methods.
291
-
292
- Usually, you don't need to override this method unless you are building a different state machine on top of this
293
- one and want to customize the transport layer itself.
294
- """
295
- method = self._get_call_method(case)
296
- return method(**kwargs)
297
-
298
- def get_call_kwargs(self, case: Case) -> Dict[str, Any]:
299
- """Create custom keyword arguments that will be passed to the :meth:`Case.call` method.
300
-
301
- Mostly they are proxied to the :func:`requests.request` call.
302
-
303
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
304
-
305
- .. code-block:: python
306
-
307
- class APIWorkflow(schema.as_state_machine()):
308
- def get_call_kwargs(self, case):
309
- return {"verify": False}
310
-
311
- The above example disables the server's TLS certificate verification.
312
- """
313
- return {}
314
-
315
- def _get_call_method(self, case: Case) -> Callable:
316
- if case.app is not None:
317
- if isinstance(case.app, Starlette):
318
- return case.call_asgi
319
- return case.call_wsgi
320
- return case.call
321
-
322
- def validate_response(
323
- self, response: GenericResponse, case: Case, additional_checks: Tuple[CheckFunction, ...] = ()
324
- ) -> None:
325
- """Validate an API response.
326
-
327
- :param response: Response from the application under test.
328
- :param Case case: Generated test case data that should be sent in an API call to the tested API operation.
329
- :param additional_checks: A list of checks that will be run together with the default ones.
330
- :raises CheckFailed: If any of the supplied checks failed.
331
-
332
- If you need to change the default checks or provide custom validation rules, you can do it here.
333
-
334
- .. code-block:: python
335
-
336
- def my_check(response, case):
337
- ... # some assertions
338
-
339
-
340
- class APIWorkflow(schema.as_state_machine()):
341
- def validate_response(self, response, case):
342
- case.validate_response(response, checks=(my_check,))
343
-
344
- The state machine from the example above will execute only the ``my_check`` check instead of all
345
- available checks.
346
-
347
- Each check function should accept ``response`` as the first argument and ``case`` as the second one and raise
348
- ``AssertionError`` if the check fails.
349
-
350
- **Note** that it is preferred to pass check functions as an argument to ``case.validate_response``.
351
- In this case, all checks will be executed, and you'll receive a grouped exception that contains results from
352
- all provided checks rather than only the first encountered exception.
353
- """
354
- __tracebackhide__ = True # pylint: disable=unused-variable
355
- case.validate_response(response, additional_checks=additional_checks)
356
-
357
- def store_result(self, response: GenericResponse, case: Case, elapsed: float) -> StepResult:
358
- return StepResult(response, case, elapsed)
schemathesis/targets.py DELETED
@@ -1,32 +0,0 @@
1
- from typing import TYPE_CHECKING, Callable, Tuple
2
-
3
- import attr
4
-
5
- from .utils import GenericResponse
6
-
7
- if TYPE_CHECKING:
8
- from .models import Case
9
-
10
-
11
- @attr.s(slots=True) # pragma: no mutate
12
- class TargetContext:
13
- """Context for targeted testing.
14
-
15
- :ivar Case case: Generated example that is being processed.
16
- :ivar GenericResponse response: API response.
17
- :ivar float response_time: API response time.
18
- """
19
-
20
- case: "Case" = attr.ib() # pragma: no mutate
21
- response: GenericResponse = attr.ib() # pragma: no mutate
22
- response_time: float = attr.ib() # pragma: no mutate
23
-
24
-
25
- def response_time(context: TargetContext) -> float:
26
- return context.response_time
27
-
28
-
29
- Target = Callable[[TargetContext], float]
30
- DEFAULT_TARGETS = ()
31
- OPTIONAL_TARGETS = (response_time,)
32
- ALL_TARGETS: Tuple[Target, ...] = DEFAULT_TARGETS + OPTIONAL_TARGETS
schemathesis/types.py DELETED
@@ -1,38 +0,0 @@
1
- from pathlib import Path
2
- from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Set, Tuple, Union
3
-
4
- from hypothesis.strategies import SearchStrategy
5
-
6
- if TYPE_CHECKING:
7
- from . import DataGenerationMethod
8
- from .hooks import HookContext
9
-
10
- PathLike = Union[Path, str] # pragma: no mutate
11
-
12
- Query = Dict[str, Any] # pragma: no mutate
13
- # Body can be of any Python type that corresponds to JSON Schema types + `bytes`
14
- Body = Union[List, Dict[str, Any], str, int, float, bool, bytes] # pragma: no mutate
15
- PathParameters = Dict[str, Any] # pragma: no mutate
16
- Headers = Dict[str, Any] # pragma: no mutate
17
- Cookies = Dict[str, Any] # pragma: no mutate
18
- FormData = Dict[str, Any] # pragma: no mutate
19
-
20
-
21
- class NotSet:
22
- pass
23
-
24
-
25
- RequestCert = Union[str, Tuple[str, str]]
26
-
27
-
28
- # A filter for path / method
29
- Filter = Union[str, List[str], Tuple[str], Set[str], NotSet] # pragma: no mutate
30
-
31
- Hook = Union[
32
- Callable[[SearchStrategy], SearchStrategy], Callable[[SearchStrategy, "HookContext"], SearchStrategy]
33
- ] # pragma: no mutate
34
-
35
- RawAuth = Tuple[str, str] # pragma: no mutate
36
- # Generic test with any arguments and no return
37
- GenericTest = Callable[..., None] # pragma: no mutate
38
- DataGenerationMethodInput = Union["DataGenerationMethod", Iterable["DataGenerationMethod"]]