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
@@ -1,453 +0,0 @@
1
- import io
2
- import pathlib
3
- from typing import IO, Any, Callable, Dict, List, Optional, Tuple, Union, cast
4
- from urllib.parse import urljoin
5
-
6
- import jsonschema
7
- import requests
8
- import yaml
9
- from jsonschema import ValidationError
10
- from starlette.applications import Starlette
11
- from starlette.testclient import TestClient as ASGIClient
12
- from werkzeug.test import Client
13
- from yarl import URL
14
-
15
- from ...constants import DEFAULT_DATA_GENERATION_METHODS, CodeSampleStyle
16
- from ...exceptions import HTTPError, SchemaLoadingError
17
- from ...hooks import HookContext, dispatch
18
- from ...lazy import LazySchema
19
- from ...types import DataGenerationMethodInput, Filter, NotSet, PathLike
20
- from ...utils import (
21
- NOT_SET,
22
- StringDatesYAMLLoader,
23
- WSGIResponse,
24
- prepare_data_generation_methods,
25
- require_relative_url,
26
- setup_headers,
27
- )
28
- from . import definitions, validation
29
- from .schemas import BaseOpenAPISchema, OpenApi30, SwaggerV20
30
-
31
-
32
- def from_path(
33
- path: PathLike,
34
- *,
35
- app: Any = None,
36
- base_url: Optional[str] = None,
37
- method: Optional[Filter] = None,
38
- endpoint: Optional[Filter] = None,
39
- tag: Optional[Filter] = None,
40
- operation_id: Optional[Filter] = None,
41
- skip_deprecated_operations: bool = False,
42
- validate_schema: bool = True,
43
- force_schema_version: Optional[str] = None,
44
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
45
- code_sample_style: str = CodeSampleStyle.default().name,
46
- encoding: str = "utf8",
47
- ) -> BaseOpenAPISchema:
48
- """Load Open API schema via a file from an OS path.
49
-
50
- :param path: A path to the schema file.
51
- :param encoding: The name of the encoding used to decode the file.
52
- """
53
- with open(path, encoding=encoding) as fd:
54
- return from_file(
55
- fd,
56
- app=app,
57
- base_url=base_url,
58
- method=method,
59
- endpoint=endpoint,
60
- tag=tag,
61
- operation_id=operation_id,
62
- skip_deprecated_operations=skip_deprecated_operations,
63
- validate_schema=validate_schema,
64
- force_schema_version=force_schema_version,
65
- data_generation_methods=data_generation_methods,
66
- code_sample_style=code_sample_style,
67
- location=pathlib.Path(path).absolute().as_uri(),
68
- )
69
-
70
-
71
- def from_uri(
72
- uri: str,
73
- *,
74
- app: Any = None,
75
- base_url: Optional[str] = None,
76
- port: Optional[int] = None,
77
- method: Optional[Filter] = None,
78
- endpoint: Optional[Filter] = None,
79
- tag: Optional[Filter] = None,
80
- operation_id: Optional[Filter] = None,
81
- skip_deprecated_operations: bool = False,
82
- validate_schema: bool = True,
83
- force_schema_version: Optional[str] = None,
84
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
85
- code_sample_style: str = CodeSampleStyle.default().name,
86
- **kwargs: Any,
87
- ) -> BaseOpenAPISchema:
88
- """Load Open API schema from the network.
89
-
90
- :param str uri: Schema URL.
91
- """
92
- setup_headers(kwargs)
93
- if not base_url and port:
94
- base_url = str(URL(uri).with_port(port))
95
- response = requests.get(uri, **kwargs)
96
- HTTPError.raise_for_status(response)
97
- try:
98
- return from_file(
99
- response.text,
100
- app=app,
101
- base_url=base_url,
102
- method=method,
103
- endpoint=endpoint,
104
- tag=tag,
105
- operation_id=operation_id,
106
- skip_deprecated_operations=skip_deprecated_operations,
107
- validate_schema=validate_schema,
108
- force_schema_version=force_schema_version,
109
- data_generation_methods=data_generation_methods,
110
- code_sample_style=code_sample_style,
111
- location=uri,
112
- )
113
- except SchemaLoadingError as exc:
114
- content_type = response.headers.get("Content-Type")
115
- if content_type is not None:
116
- raise SchemaLoadingError(f"{exc.args[0]}. The actual response has `{content_type}` Content-Type") from exc
117
- raise
118
-
119
-
120
- YAML_LOADING_ERROR = (
121
- "It seems like the schema you are trying to load is malformed. "
122
- "Schemathesis expects API schemas in JSON or YAML formats"
123
- )
124
-
125
-
126
- def from_file(
127
- file: Union[IO[str], str],
128
- *,
129
- app: Any = None,
130
- base_url: Optional[str] = None,
131
- method: Optional[Filter] = None,
132
- endpoint: Optional[Filter] = None,
133
- tag: Optional[Filter] = None,
134
- operation_id: Optional[Filter] = None,
135
- skip_deprecated_operations: bool = False,
136
- validate_schema: bool = True,
137
- force_schema_version: Optional[str] = None,
138
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
139
- code_sample_style: str = CodeSampleStyle.default().name,
140
- location: Optional[str] = None,
141
- **kwargs: Any, # needed in the runner to have compatible API across all loaders
142
- ) -> BaseOpenAPISchema:
143
- """Load Open API schema from a file descriptor, string or bytes.
144
-
145
- :param file: Could be a file descriptor, string or bytes.
146
- """
147
- try:
148
- raw = yaml.load(file, StringDatesYAMLLoader)
149
- return from_dict(
150
- raw,
151
- app=app,
152
- base_url=base_url,
153
- method=method,
154
- endpoint=endpoint,
155
- tag=tag,
156
- operation_id=operation_id,
157
- skip_deprecated_operations=skip_deprecated_operations,
158
- validate_schema=validate_schema,
159
- force_schema_version=force_schema_version,
160
- data_generation_methods=data_generation_methods,
161
- code_sample_style=code_sample_style,
162
- location=location,
163
- )
164
- except yaml.YAMLError as exc:
165
- raise SchemaLoadingError(YAML_LOADING_ERROR) from exc
166
-
167
-
168
- def from_dict(
169
- raw_schema: Dict[str, Any],
170
- *,
171
- app: Any = None,
172
- base_url: Optional[str] = None,
173
- method: Optional[Filter] = None,
174
- endpoint: Optional[Filter] = None,
175
- tag: Optional[Filter] = None,
176
- operation_id: Optional[Filter] = None,
177
- skip_deprecated_operations: bool = False,
178
- validate_schema: bool = True,
179
- force_schema_version: Optional[str] = None,
180
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
181
- code_sample_style: str = CodeSampleStyle.default().name,
182
- location: Optional[str] = None,
183
- ) -> BaseOpenAPISchema:
184
- """Load Open API schema from a Python dictionary.
185
-
186
- :param dict raw_schema: A schema to load.
187
- """
188
- _code_sample_style = CodeSampleStyle.from_str(code_sample_style)
189
- dispatch("before_load_schema", HookContext(), raw_schema)
190
-
191
- def init_openapi_2() -> SwaggerV20:
192
- _maybe_validate_schema(raw_schema, definitions.SWAGGER_20_VALIDATOR, validate_schema)
193
- return SwaggerV20(
194
- raw_schema,
195
- app=app,
196
- base_url=base_url,
197
- method=method,
198
- endpoint=endpoint,
199
- tag=tag,
200
- operation_id=operation_id,
201
- skip_deprecated_operations=skip_deprecated_operations,
202
- validate_schema=validate_schema,
203
- data_generation_methods=prepare_data_generation_methods(data_generation_methods),
204
- code_sample_style=_code_sample_style,
205
- location=location,
206
- )
207
-
208
- def init_openapi_3() -> OpenApi30:
209
- _maybe_validate_schema(raw_schema, definitions.OPENAPI_30_VALIDATOR, validate_schema)
210
- return OpenApi30(
211
- raw_schema,
212
- app=app,
213
- base_url=base_url,
214
- method=method,
215
- endpoint=endpoint,
216
- tag=tag,
217
- operation_id=operation_id,
218
- skip_deprecated_operations=skip_deprecated_operations,
219
- validate_schema=validate_schema,
220
- data_generation_methods=prepare_data_generation_methods(data_generation_methods),
221
- code_sample_style=_code_sample_style,
222
- location=location,
223
- )
224
-
225
- if force_schema_version == "20":
226
- return init_openapi_2()
227
- if force_schema_version == "30":
228
- return init_openapi_3()
229
- if "swagger" in raw_schema:
230
- return init_openapi_2()
231
- if "openapi" in raw_schema:
232
- return init_openapi_3()
233
- raise SchemaLoadingError("Unsupported schema type")
234
-
235
-
236
- # It is a common case when API schemas are stored in the YAML format and HTTP status codes are numbers
237
- # The Open API spec requires HTTP status codes as strings
238
- DOC_ENTRY = "https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#patterned-fields-1"
239
- NUMERIC_STATUS_CODES_MESSAGE = f"""The input schema contains HTTP status codes as numbers.
240
- The Open API spec requires them to be strings:
241
- {DOC_ENTRY}
242
- Please, stringify the following status codes:"""
243
- NON_STRING_OBJECT_KEY = "The input schema contains non-string keys in sub-schemas"
244
-
245
-
246
- def _format_status_codes(status_codes: List[Tuple[int, List[Union[str, int]]]]) -> str:
247
- buffer = io.StringIO()
248
- for status_code, path in status_codes:
249
- buffer.write(f" - {status_code} at schema['paths']")
250
- for chunk in path:
251
- buffer.write(f"[{repr(chunk)}]")
252
- buffer.write("['responses']\n")
253
- return buffer.getvalue().rstrip()
254
-
255
-
256
- def _maybe_validate_schema(
257
- instance: Dict[str, Any], validator: jsonschema.validators.Draft4Validator, validate_schema: bool
258
- ) -> None:
259
- if validate_schema:
260
- try:
261
- validator.validate(instance)
262
- except TypeError as exc:
263
- if validation.is_pattern_error(exc):
264
- status_codes = validation.find_numeric_http_status_codes(instance)
265
- if status_codes:
266
- message = _format_status_codes(status_codes)
267
- raise SchemaLoadingError(f"{NUMERIC_STATUS_CODES_MESSAGE}\n{message}") from exc
268
- # Some other pattern error
269
- raise SchemaLoadingError(NON_STRING_OBJECT_KEY) from exc
270
- raise SchemaLoadingError("Invalid schema") from exc
271
- except ValidationError as exc:
272
- raise SchemaLoadingError("The input schema is not a valid Open API schema") from exc
273
-
274
-
275
- def from_pytest_fixture(
276
- fixture_name: str,
277
- *,
278
- app: Any = NOT_SET,
279
- base_url: Union[Optional[str], NotSet] = NOT_SET,
280
- method: Optional[Filter] = NOT_SET,
281
- endpoint: Optional[Filter] = NOT_SET,
282
- tag: Optional[Filter] = NOT_SET,
283
- operation_id: Optional[Filter] = NOT_SET,
284
- skip_deprecated_operations: bool = False,
285
- validate_schema: bool = True,
286
- data_generation_methods: Union[DataGenerationMethodInput, NotSet] = NOT_SET,
287
- code_sample_style: str = CodeSampleStyle.default().name,
288
- ) -> LazySchema:
289
- """Load schema from a ``pytest`` fixture.
290
-
291
- It is useful if you don't want to make network requests during module loading. With this loader you can defer it
292
- to a fixture.
293
-
294
- Note, the fixture should return a ``BaseSchema`` instance loaded with another loader.
295
-
296
- :param str fixture_name: The name of a fixture to load.
297
- """
298
- _code_sample_style = CodeSampleStyle.from_str(code_sample_style)
299
- _data_generation_methods: Union[DataGenerationMethodInput, NotSet]
300
- if data_generation_methods is not NOT_SET:
301
- data_generation_methods = cast(DataGenerationMethodInput, data_generation_methods)
302
- _data_generation_methods = prepare_data_generation_methods(data_generation_methods)
303
- else:
304
- _data_generation_methods = data_generation_methods
305
- return LazySchema(
306
- fixture_name,
307
- app=app,
308
- base_url=base_url,
309
- method=method,
310
- endpoint=endpoint,
311
- tag=tag,
312
- operation_id=operation_id,
313
- skip_deprecated_operations=skip_deprecated_operations,
314
- validate_schema=validate_schema,
315
- data_generation_methods=_data_generation_methods,
316
- code_sample_style=_code_sample_style,
317
- )
318
-
319
-
320
- def from_wsgi(
321
- schema_path: str,
322
- app: Any,
323
- *,
324
- base_url: Optional[str] = None,
325
- method: Optional[Filter] = None,
326
- endpoint: Optional[Filter] = None,
327
- tag: Optional[Filter] = None,
328
- operation_id: Optional[Filter] = None,
329
- skip_deprecated_operations: bool = False,
330
- validate_schema: bool = True,
331
- force_schema_version: Optional[str] = None,
332
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
333
- code_sample_style: str = CodeSampleStyle.default().name,
334
- **kwargs: Any,
335
- ) -> BaseOpenAPISchema:
336
- """Load Open API schema from a WSGI app.
337
-
338
- :param str schema_path: An in-app relative URL to the schema.
339
- :param app: A WSGI app instance.
340
- """
341
- require_relative_url(schema_path)
342
- setup_headers(kwargs)
343
- client = Client(app, WSGIResponse)
344
- response = client.get(schema_path, **kwargs)
345
- HTTPError.check_response(response, schema_path)
346
- return from_file(
347
- response.data,
348
- app=app,
349
- base_url=base_url,
350
- method=method,
351
- endpoint=endpoint,
352
- tag=tag,
353
- operation_id=operation_id,
354
- skip_deprecated_operations=skip_deprecated_operations,
355
- validate_schema=validate_schema,
356
- force_schema_version=force_schema_version,
357
- data_generation_methods=data_generation_methods,
358
- code_sample_style=code_sample_style,
359
- location=schema_path,
360
- )
361
-
362
-
363
- def get_loader_for_app(app: Any) -> Callable:
364
- if isinstance(app, Starlette):
365
- return from_asgi
366
- if app.__class__.__module__.startswith("aiohttp."):
367
- return from_aiohttp
368
- return from_wsgi
369
-
370
-
371
- def from_aiohttp(
372
- schema_path: str,
373
- app: Any,
374
- *,
375
- base_url: Optional[str] = None,
376
- method: Optional[Filter] = None,
377
- endpoint: Optional[Filter] = None,
378
- tag: Optional[Filter] = None,
379
- operation_id: Optional[Filter] = None,
380
- skip_deprecated_operations: bool = False,
381
- validate_schema: bool = True,
382
- force_schema_version: Optional[str] = None,
383
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
384
- code_sample_style: str = CodeSampleStyle.default().name,
385
- **kwargs: Any,
386
- ) -> BaseOpenAPISchema:
387
- """Load Open API schema from an AioHTTP app.
388
-
389
- :param str schema_path: An in-app relative URL to the schema.
390
- :param app: An AioHTTP app instance.
391
- """
392
- from ...extra._aiohttp import run_server # pylint: disable=import-outside-toplevel
393
-
394
- port = run_server(app)
395
- app_url = f"http://127.0.0.1:{port}/"
396
- url = urljoin(app_url, schema_path)
397
- return from_uri(
398
- url,
399
- base_url=base_url,
400
- method=method,
401
- endpoint=endpoint,
402
- tag=tag,
403
- operation_id=operation_id,
404
- skip_deprecated_operations=skip_deprecated_operations,
405
- validate_schema=validate_schema,
406
- force_schema_version=force_schema_version,
407
- data_generation_methods=data_generation_methods,
408
- code_sample_style=code_sample_style,
409
- **kwargs,
410
- )
411
-
412
-
413
- def from_asgi(
414
- schema_path: str,
415
- app: Any,
416
- *,
417
- base_url: Optional[str] = None,
418
- method: Optional[Filter] = None,
419
- endpoint: Optional[Filter] = None,
420
- tag: Optional[Filter] = None,
421
- operation_id: Optional[Filter] = None,
422
- skip_deprecated_operations: bool = False,
423
- validate_schema: bool = True,
424
- force_schema_version: Optional[str] = None,
425
- data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
426
- code_sample_style: str = CodeSampleStyle.default().name,
427
- **kwargs: Any,
428
- ) -> BaseOpenAPISchema:
429
- """Load Open API schema from an ASGI app.
430
-
431
- :param str schema_path: An in-app relative URL to the schema.
432
- :param app: An ASGI app instance.
433
- """
434
- require_relative_url(schema_path)
435
- setup_headers(kwargs)
436
- client = ASGIClient(app)
437
- response = client.get(schema_path, **kwargs)
438
- HTTPError.check_response(response, schema_path)
439
- return from_file(
440
- response.text,
441
- app=app,
442
- base_url=base_url,
443
- method=method,
444
- endpoint=endpoint,
445
- tag=tag,
446
- operation_id=operation_id,
447
- skip_deprecated_operations=skip_deprecated_operations,
448
- validate_schema=validate_schema,
449
- force_schema_version=force_schema_version,
450
- data_generation_methods=data_generation_methods,
451
- code_sample_style=code_sample_style,
452
- location=schema_path,
453
- )