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
@@ -0,0 +1,285 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from functools import lru_cache
5
+ from os import PathLike
6
+ from pathlib import Path
7
+ from typing import IO, TYPE_CHECKING, Any, Callable, Dict, NoReturn, TypeVar, cast
8
+
9
+ from schemathesis.config import SchemathesisConfig
10
+ from schemathesis.core.errors import LoaderError, LoaderErrorKind
11
+ from schemathesis.core.loaders import load_from_url, prepare_request_kwargs, raise_for_status, require_relative_url
12
+ from schemathesis.hooks import HookContext, dispatch
13
+ from schemathesis.python import asgi, wsgi
14
+
15
+ if TYPE_CHECKING:
16
+ from graphql import DocumentNode
17
+
18
+ from schemathesis.specs.graphql.schemas import GraphQLSchema
19
+
20
+
21
+ def from_asgi(path: str, app: Any, *, config: SchemathesisConfig | None = None, **kwargs: Any) -> GraphQLSchema:
22
+ """Load GraphQL schema from an ASGI application via introspection.
23
+
24
+ Args:
25
+ path: Relative URL path to the GraphQL endpoint (e.g., "/graphql")
26
+ app: ASGI application instance
27
+ config: Custom configuration. If `None`, uses auto-discovered config
28
+ **kwargs: Additional request parameters passed to the ASGI test client.
29
+
30
+ Example:
31
+ ```python
32
+ from fastapi import FastAPI
33
+ import schemathesis
34
+
35
+ app = FastAPI()
36
+ schema = schemathesis.graphql.from_asgi("/graphql", app)
37
+ ```
38
+
39
+ """
40
+ require_relative_url(path)
41
+ kwargs.setdefault("json", {"query": get_introspection_query()})
42
+ client = asgi.get_client(app)
43
+ response = load_from_url(client.post, url=path, **kwargs)
44
+ schema = extract_schema_from_response(response, lambda r: r.json())
45
+ loaded = from_dict(schema=schema, config=config)
46
+ loaded.app = app
47
+ loaded.location = path
48
+ return loaded
49
+
50
+
51
+ def from_wsgi(path: str, app: Any, *, config: SchemathesisConfig | None = None, **kwargs: Any) -> GraphQLSchema:
52
+ """Load GraphQL schema from a WSGI application via introspection.
53
+
54
+ Args:
55
+ path: Relative URL path to the GraphQL endpoint (e.g., "/graphql")
56
+ app: WSGI application instance
57
+ config: Custom configuration. If `None`, uses auto-discovered config
58
+ **kwargs: Additional request parameters passed to the WSGI test client.
59
+
60
+ Example:
61
+ ```python
62
+ from flask import Flask
63
+ import schemathesis
64
+
65
+ app = Flask(__name__)
66
+ schema = schemathesis.graphql.from_wsgi("/graphql", app)
67
+ ```
68
+
69
+ """
70
+ require_relative_url(path)
71
+ prepare_request_kwargs(kwargs)
72
+ kwargs.setdefault("json", {"query": get_introspection_query()})
73
+ client = wsgi.get_client(app)
74
+ response = client.post(path=path, **kwargs)
75
+ raise_for_status(response)
76
+ schema = extract_schema_from_response(response, lambda r: r.json)
77
+ loaded = from_dict(schema=schema, config=config)
78
+ loaded.app = app
79
+ loaded.location = path
80
+ return loaded
81
+
82
+
83
+ def from_url(
84
+ url: str, *, config: SchemathesisConfig | None = None, wait_for_schema: float | None = None, **kwargs: Any
85
+ ) -> GraphQLSchema:
86
+ """Load GraphQL schema from a URL via introspection query.
87
+
88
+ Args:
89
+ url: Full URL to the GraphQL endpoint
90
+ config: Custom configuration. If `None`, uses auto-discovered config
91
+ wait_for_schema: Maximum time in seconds to wait for schema availability
92
+ **kwargs: Additional parameters passed to `requests.post()` (headers, timeout, auth, etc.).
93
+
94
+ Example:
95
+ ```python
96
+ import schemathesis
97
+
98
+ # Basic usage
99
+ schema = schemathesis.graphql.from_url("https://api.example.com/graphql")
100
+
101
+ # With authentication and timeout
102
+ schema = schemathesis.graphql.from_url(
103
+ "https://api.example.com/graphql",
104
+ headers={"Authorization": "Bearer token"},
105
+ timeout=30,
106
+ wait_for_schema=10.0
107
+ )
108
+ ```
109
+
110
+ """
111
+ import requests
112
+
113
+ kwargs.setdefault("json", {"query": get_introspection_query()})
114
+ response = load_from_url(requests.post, url=url, wait_for_schema=wait_for_schema, **kwargs)
115
+ schema = extract_schema_from_response(response, lambda r: r.json())
116
+ loaded = from_dict(schema, config=config)
117
+ loaded.location = url
118
+ return loaded
119
+
120
+
121
+ def from_path(
122
+ path: PathLike | str, *, config: SchemathesisConfig | None = None, encoding: str = "utf-8"
123
+ ) -> GraphQLSchema:
124
+ """Load GraphQL schema from a filesystem path.
125
+
126
+ Args:
127
+ path: File path to the GraphQL schema file (.graphql, .gql)
128
+ config: Custom configuration. If `None`, uses auto-discovered config
129
+ encoding: Text encoding for reading the file
130
+
131
+ Example:
132
+ ```python
133
+ import schemathesis
134
+
135
+ # Load from GraphQL SDL file
136
+ schema = schemathesis.graphql.from_path("./schema.graphql")
137
+ ```
138
+
139
+ """
140
+ with open(path, encoding=encoding) as file:
141
+ loaded = from_file(file=file, config=config)
142
+ loaded.location = Path(path).absolute().as_uri()
143
+ return loaded
144
+
145
+
146
+ def from_file(file: IO[str] | str, *, config: SchemathesisConfig | None = None) -> GraphQLSchema:
147
+ """Load GraphQL schema from a file-like object or string.
148
+
149
+ Args:
150
+ file: File-like object or raw string containing GraphQL SDL
151
+ config: Custom configuration. If `None`, uses auto-discovered config
152
+
153
+ Example:
154
+ ```python
155
+ import schemathesis
156
+
157
+ # From GraphQL SDL string
158
+ schema_sdl = '''
159
+ type Query {
160
+ user(id: ID!): User
161
+ }
162
+ type User {
163
+ id: ID!
164
+ name: String!
165
+ }
166
+ '''
167
+ schema = schemathesis.graphql.from_file(schema_sdl)
168
+
169
+ # From file object
170
+ with open("schema.graphql") as f:
171
+ schema = schemathesis.graphql.from_file(f)
172
+ ```
173
+
174
+ """
175
+ import graphql
176
+
177
+ if isinstance(file, str):
178
+ data = file
179
+ else:
180
+ data = file.read()
181
+ try:
182
+ document = graphql.build_schema(data)
183
+ result = graphql.execute(document, get_introspection_query_ast())
184
+ # TYPES: We don't pass `is_awaitable` above, therefore `result` is of the `ExecutionResult` type
185
+ result = cast(graphql.ExecutionResult, result)
186
+ # TYPES:
187
+ # - `document` is a valid schema, because otherwise `build_schema` will rise an error;
188
+ # - `INTROSPECTION_QUERY` is a valid query - it is known upfront;
189
+ # Therefore the execution result is always valid at this point and `result.data` is not `None`
190
+ schema = cast(Dict[str, Any], result.data)
191
+ except Exception as exc:
192
+ try:
193
+ schema = json.loads(data)
194
+ if not isinstance(schema, dict) or "__schema" not in schema:
195
+ _on_invalid_schema(exc)
196
+ except json.JSONDecodeError:
197
+ _on_invalid_schema(exc, extras=[entry for entry in str(exc).splitlines() if entry])
198
+ return from_dict(schema, config=config)
199
+
200
+
201
+ def from_dict(schema: dict[str, Any], *, config: SchemathesisConfig | None = None) -> GraphQLSchema:
202
+ """Load GraphQL schema from a dictionary containing introspection result.
203
+
204
+ Args:
205
+ schema: Dictionary containing GraphQL introspection result or wrapped in 'data' key
206
+ config: Custom configuration. If `None`, uses auto-discovered config
207
+
208
+ Example:
209
+ ```python
210
+ import schemathesis
211
+
212
+ # From introspection result
213
+ introspection = {
214
+ "__schema": {
215
+ "types": [...],
216
+ "queryType": {"name": "Query"},
217
+ # ... rest of introspection result
218
+ }
219
+ }
220
+ schema = schemathesis.graphql.from_dict(introspection)
221
+
222
+ # From GraphQL response format (with 'data' wrapper)
223
+ response_data = {
224
+ "data": {
225
+ "__schema": {
226
+ "types": [...],
227
+ "queryType": {"name": "Query"}
228
+ }
229
+ }
230
+ }
231
+ schema = schemathesis.graphql.from_dict(response_data)
232
+ ```
233
+
234
+ """
235
+ from schemathesis.specs.graphql.schemas import GraphQLSchema
236
+
237
+ if "data" in schema:
238
+ schema = schema["data"]
239
+ hook_context = HookContext()
240
+ dispatch("before_load_schema", hook_context, schema)
241
+
242
+ if config is None:
243
+ config = SchemathesisConfig.discover()
244
+ project_config = config.projects.get(schema)
245
+ instance = GraphQLSchema(schema, config=project_config)
246
+ instance.filter_set = project_config.operations.filter_set_with(include=instance.filter_set)
247
+ dispatch("after_load_schema", hook_context, instance)
248
+ return instance
249
+
250
+
251
+ @lru_cache
252
+ def get_introspection_query() -> str:
253
+ import graphql
254
+
255
+ return graphql.get_introspection_query()
256
+
257
+
258
+ @lru_cache
259
+ def get_introspection_query_ast() -> DocumentNode:
260
+ import graphql
261
+
262
+ query = get_introspection_query()
263
+ return graphql.parse(query)
264
+
265
+
266
+ R = TypeVar("R")
267
+
268
+
269
+ def extract_schema_from_response(response: R, callback: Callable[[R], Any]) -> dict[str, Any]:
270
+ try:
271
+ decoded = callback(response)
272
+ except json.JSONDecodeError as exc:
273
+ raise LoaderError(
274
+ LoaderErrorKind.UNEXPECTED_CONTENT_TYPE,
275
+ "Received unsupported content while expecting a JSON payload for GraphQL",
276
+ ) from exc
277
+ return decoded
278
+
279
+
280
+ def _on_invalid_schema(exc: Exception, extras: list[str] | None = None) -> NoReturn:
281
+ raise LoaderError(
282
+ LoaderErrorKind.GRAPHQL_INVALID_SCHEMA,
283
+ "The provided API schema does not appear to be a valid GraphQL schema",
284
+ extras=extras or [],
285
+ ) from exc