schemathesis 3.25.6__py3-none-any.whl → 3.39.7__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.
- schemathesis/__init__.py +6 -6
- schemathesis/_compat.py +2 -2
- schemathesis/_dependency_versions.py +4 -2
- schemathesis/_hypothesis.py +369 -56
- schemathesis/_lazy_import.py +1 -0
- schemathesis/_override.py +5 -4
- schemathesis/_patches.py +21 -0
- schemathesis/_rate_limiter.py +7 -0
- schemathesis/_xml.py +75 -22
- schemathesis/auths.py +78 -16
- schemathesis/checks.py +21 -9
- schemathesis/cli/__init__.py +783 -432
- schemathesis/cli/__main__.py +4 -0
- schemathesis/cli/callbacks.py +58 -13
- schemathesis/cli/cassettes.py +233 -47
- schemathesis/cli/constants.py +8 -2
- schemathesis/cli/context.py +22 -5
- schemathesis/cli/debug.py +2 -1
- schemathesis/cli/handlers.py +4 -1
- schemathesis/cli/junitxml.py +103 -22
- schemathesis/cli/options.py +15 -4
- schemathesis/cli/output/default.py +258 -112
- schemathesis/cli/output/short.py +23 -8
- schemathesis/cli/reporting.py +79 -0
- schemathesis/cli/sanitization.py +6 -0
- schemathesis/code_samples.py +5 -3
- schemathesis/constants.py +1 -0
- schemathesis/contrib/openapi/__init__.py +1 -1
- schemathesis/contrib/openapi/fill_missing_examples.py +3 -1
- schemathesis/contrib/openapi/formats/uuid.py +2 -1
- schemathesis/contrib/unique_data.py +3 -3
- schemathesis/exceptions.py +76 -65
- schemathesis/experimental/__init__.py +35 -0
- schemathesis/extra/_aiohttp.py +1 -0
- schemathesis/extra/_flask.py +4 -1
- schemathesis/extra/_server.py +1 -0
- schemathesis/extra/pytest_plugin.py +17 -25
- schemathesis/failures.py +77 -9
- schemathesis/filters.py +185 -8
- schemathesis/fixups/__init__.py +1 -0
- schemathesis/fixups/fast_api.py +2 -2
- schemathesis/fixups/utf8_bom.py +1 -2
- schemathesis/generation/__init__.py +20 -36
- schemathesis/generation/_hypothesis.py +59 -0
- schemathesis/generation/_methods.py +44 -0
- schemathesis/generation/coverage.py +931 -0
- schemathesis/graphql.py +0 -1
- schemathesis/hooks.py +89 -12
- schemathesis/internal/checks.py +84 -0
- schemathesis/internal/copy.py +22 -3
- schemathesis/internal/deprecation.py +6 -2
- schemathesis/internal/diff.py +15 -0
- schemathesis/internal/extensions.py +27 -0
- schemathesis/internal/jsonschema.py +2 -1
- schemathesis/internal/output.py +68 -0
- schemathesis/internal/result.py +1 -1
- schemathesis/internal/transformation.py +11 -0
- schemathesis/lazy.py +138 -25
- schemathesis/loaders.py +7 -5
- schemathesis/models.py +318 -211
- schemathesis/parameters.py +4 -0
- schemathesis/runner/__init__.py +50 -15
- schemathesis/runner/events.py +65 -5
- schemathesis/runner/impl/context.py +104 -0
- schemathesis/runner/impl/core.py +388 -177
- schemathesis/runner/impl/solo.py +19 -29
- schemathesis/runner/impl/threadpool.py +70 -79
- schemathesis/runner/probes.py +11 -9
- schemathesis/runner/serialization.py +150 -17
- schemathesis/sanitization.py +5 -1
- schemathesis/schemas.py +170 -102
- schemathesis/serializers.py +7 -2
- schemathesis/service/ci.py +1 -0
- schemathesis/service/client.py +39 -6
- schemathesis/service/events.py +5 -1
- schemathesis/service/extensions.py +224 -0
- schemathesis/service/hosts.py +6 -2
- schemathesis/service/metadata.py +25 -0
- schemathesis/service/models.py +211 -2
- schemathesis/service/report.py +6 -6
- schemathesis/service/serialization.py +45 -71
- schemathesis/service/usage.py +1 -0
- schemathesis/specs/graphql/_cache.py +26 -0
- schemathesis/specs/graphql/loaders.py +25 -5
- schemathesis/specs/graphql/nodes.py +1 -0
- schemathesis/specs/graphql/scalars.py +2 -2
- schemathesis/specs/graphql/schemas.py +130 -100
- schemathesis/specs/graphql/validation.py +1 -2
- schemathesis/specs/openapi/__init__.py +1 -0
- schemathesis/specs/openapi/_cache.py +123 -0
- schemathesis/specs/openapi/_hypothesis.py +78 -60
- schemathesis/specs/openapi/checks.py +504 -25
- schemathesis/specs/openapi/converter.py +31 -4
- schemathesis/specs/openapi/definitions.py +10 -17
- schemathesis/specs/openapi/examples.py +126 -12
- schemathesis/specs/openapi/expressions/__init__.py +37 -2
- schemathesis/specs/openapi/expressions/context.py +1 -1
- schemathesis/specs/openapi/expressions/extractors.py +26 -0
- schemathesis/specs/openapi/expressions/lexer.py +20 -18
- schemathesis/specs/openapi/expressions/nodes.py +29 -6
- schemathesis/specs/openapi/expressions/parser.py +26 -5
- schemathesis/specs/openapi/formats.py +44 -0
- schemathesis/specs/openapi/links.py +125 -42
- schemathesis/specs/openapi/loaders.py +77 -36
- schemathesis/specs/openapi/media_types.py +34 -0
- schemathesis/specs/openapi/negative/__init__.py +6 -3
- schemathesis/specs/openapi/negative/mutations.py +21 -6
- schemathesis/specs/openapi/parameters.py +39 -25
- schemathesis/specs/openapi/patterns.py +137 -0
- schemathesis/specs/openapi/references.py +37 -7
- schemathesis/specs/openapi/schemas.py +360 -241
- schemathesis/specs/openapi/security.py +25 -7
- schemathesis/specs/openapi/serialization.py +1 -0
- schemathesis/specs/openapi/stateful/__init__.py +198 -70
- schemathesis/specs/openapi/stateful/statistic.py +198 -0
- schemathesis/specs/openapi/stateful/types.py +14 -0
- schemathesis/specs/openapi/utils.py +6 -1
- schemathesis/specs/openapi/validation.py +1 -0
- schemathesis/stateful/__init__.py +35 -21
- schemathesis/stateful/config.py +97 -0
- schemathesis/stateful/context.py +135 -0
- schemathesis/stateful/events.py +274 -0
- schemathesis/stateful/runner.py +309 -0
- schemathesis/stateful/sink.py +68 -0
- schemathesis/stateful/state_machine.py +67 -38
- schemathesis/stateful/statistic.py +22 -0
- schemathesis/stateful/validation.py +100 -0
- schemathesis/targets.py +33 -1
- schemathesis/throttling.py +25 -5
- schemathesis/transports/__init__.py +354 -0
- schemathesis/transports/asgi.py +7 -0
- schemathesis/transports/auth.py +25 -2
- schemathesis/transports/content_types.py +3 -1
- schemathesis/transports/headers.py +2 -1
- schemathesis/transports/responses.py +9 -4
- schemathesis/types.py +9 -0
- schemathesis/utils.py +11 -16
- schemathesis-3.39.7.dist-info/METADATA +293 -0
- schemathesis-3.39.7.dist-info/RECORD +160 -0
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/WHEEL +1 -1
- schemathesis/specs/openapi/filters.py +0 -49
- schemathesis/specs/openapi/stateful/links.py +0 -92
- schemathesis-3.25.6.dist-info/METADATA +0 -356
- schemathesis-3.25.6.dist-info/RECORD +0 -134
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/entry_points.txt +0 -0
- {schemathesis-3.25.6.dist-info → schemathesis-3.39.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
|
|
2
3
|
from dataclasses import asdict
|
|
3
|
-
from typing import Any, Callable, Dict, Optional, TypeVar, cast
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, cast
|
|
4
5
|
|
|
5
|
-
from ..models import Response
|
|
6
|
-
from ..runner import events
|
|
7
|
-
from ..runner.serialization import SerializedCase
|
|
8
6
|
from ..internal.transformation import merge_recursively
|
|
7
|
+
from ..runner import events
|
|
8
|
+
from ..runner.serialization import _serialize_check
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..stateful import events as stateful_events
|
|
9
12
|
|
|
10
13
|
S = TypeVar("S", bound=events.ExecutionEvent)
|
|
11
14
|
SerializeFunc = Callable[[S], Optional[Dict[str, Any]]]
|
|
@@ -28,32 +31,19 @@ def serialize_after_probing(event: events.AfterProbing) -> dict[str, Any] | None
|
|
|
28
31
|
return {"probes": [probe.serialize() for probe in probes]}
|
|
29
32
|
|
|
30
33
|
|
|
31
|
-
def
|
|
32
|
-
return
|
|
33
|
-
"correlation_id": event.correlation_id,
|
|
34
|
-
"verbose_name": event.verbose_name,
|
|
35
|
-
"data_generation_method": event.data_generation_method,
|
|
36
|
-
}
|
|
34
|
+
def serialize_before_analysis(_: events.BeforeAnalysis) -> None:
|
|
35
|
+
return None
|
|
37
36
|
|
|
38
37
|
|
|
39
|
-
def
|
|
40
|
-
return
|
|
41
|
-
"verbose_name": case.verbose_name,
|
|
42
|
-
"path_template": case.path_template,
|
|
43
|
-
"path_parameters": stringify_path_parameters(case.path_parameters),
|
|
44
|
-
"query": prepare_query(case.query),
|
|
45
|
-
"cookies": case.cookies,
|
|
46
|
-
"media_type": case.media_type,
|
|
47
|
-
}
|
|
38
|
+
def serialize_after_analysis(event: events.AfterAnalysis) -> dict[str, Any] | None:
|
|
39
|
+
return event._serialize()
|
|
48
40
|
|
|
49
41
|
|
|
50
|
-
def
|
|
42
|
+
def serialize_before_execution(event: events.BeforeExecution) -> dict[str, Any] | None:
|
|
51
43
|
return {
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"encoding": response.encoding,
|
|
56
|
-
"elapsed": response.elapsed,
|
|
44
|
+
"correlation_id": event.correlation_id,
|
|
45
|
+
"verbose_name": event.verbose_name,
|
|
46
|
+
"data_generation_method": event.data_generation_method,
|
|
57
47
|
}
|
|
58
48
|
|
|
59
49
|
|
|
@@ -65,27 +55,7 @@ def serialize_after_execution(event: events.AfterExecution) -> dict[str, Any] |
|
|
|
65
55
|
"elapsed_time": event.elapsed_time,
|
|
66
56
|
"data_generation_method": event.data_generation_method,
|
|
67
57
|
"result": {
|
|
68
|
-
"checks": [
|
|
69
|
-
{
|
|
70
|
-
"name": check.name,
|
|
71
|
-
"value": check.value,
|
|
72
|
-
"request": {
|
|
73
|
-
"method": check.request.method,
|
|
74
|
-
"uri": check.request.uri,
|
|
75
|
-
"body": check.request.body,
|
|
76
|
-
"headers": check.request.headers,
|
|
77
|
-
},
|
|
78
|
-
"response": _serialize_response(check.response) if check.response is not None else None,
|
|
79
|
-
"example": _serialize_case(check.example),
|
|
80
|
-
"message": check.message,
|
|
81
|
-
"context": asdict(check.context) if check.context is not None else None, # type: ignore
|
|
82
|
-
"history": [
|
|
83
|
-
{"case": _serialize_case(entry.case), "response": _serialize_response(entry.response)}
|
|
84
|
-
for entry in check.history
|
|
85
|
-
],
|
|
86
|
-
}
|
|
87
|
-
for check in event.result.checks
|
|
88
|
-
],
|
|
58
|
+
"checks": [_serialize_check(check) for check in event.result.checks],
|
|
89
59
|
"errors": [asdict(error) for error in event.result.errors],
|
|
90
60
|
"skip_reason": event.result.skip_reason,
|
|
91
61
|
},
|
|
@@ -123,14 +93,35 @@ def serialize_finished(event: events.Finished) -> dict[str, Any] | None:
|
|
|
123
93
|
}
|
|
124
94
|
|
|
125
95
|
|
|
96
|
+
def serialize_stateful_event(event: events.StatefulEvent) -> dict[str, Any] | None:
|
|
97
|
+
return _serialize_stateful_event(event.data)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _serialize_stateful_event(event: stateful_events.StatefulEvent) -> dict[str, Any] | None:
|
|
101
|
+
return {"data": {event.__class__.__name__: event.asdict()}}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def serialize_after_stateful_execution(event: events.AfterStatefulExecution) -> dict[str, Any] | None:
|
|
105
|
+
return {
|
|
106
|
+
"status": event.status,
|
|
107
|
+
"data_generation_method": event.data_generation_method,
|
|
108
|
+
"result": asdict(event.result),
|
|
109
|
+
"elapsed_time": event.elapsed_time,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
126
113
|
SERIALIZER_MAP = {
|
|
127
114
|
events.Initialized: serialize_initialized,
|
|
128
115
|
events.BeforeProbing: serialize_before_probing,
|
|
129
116
|
events.AfterProbing: serialize_after_probing,
|
|
117
|
+
events.BeforeAnalysis: serialize_before_analysis,
|
|
118
|
+
events.AfterAnalysis: serialize_after_analysis,
|
|
130
119
|
events.BeforeExecution: serialize_before_execution,
|
|
131
120
|
events.AfterExecution: serialize_after_execution,
|
|
132
121
|
events.Interrupted: serialize_interrupted,
|
|
133
122
|
events.InternalError: serialize_internal_error,
|
|
123
|
+
events.StatefulEvent: serialize_stateful_event,
|
|
124
|
+
events.AfterStatefulExecution: serialize_after_stateful_execution,
|
|
134
125
|
events.Finished: serialize_finished,
|
|
135
126
|
}
|
|
136
127
|
|
|
@@ -141,10 +132,14 @@ def serialize_event(
|
|
|
141
132
|
on_initialized: SerializeFunc | None = None,
|
|
142
133
|
on_before_probing: SerializeFunc | None = None,
|
|
143
134
|
on_after_probing: SerializeFunc | None = None,
|
|
135
|
+
on_before_analysis: SerializeFunc | None = None,
|
|
136
|
+
on_after_analysis: SerializeFunc | None = None,
|
|
144
137
|
on_before_execution: SerializeFunc | None = None,
|
|
145
138
|
on_after_execution: SerializeFunc | None = None,
|
|
146
139
|
on_interrupted: SerializeFunc | None = None,
|
|
147
140
|
on_internal_error: SerializeFunc | None = None,
|
|
141
|
+
on_stateful_event: SerializeFunc | None = None,
|
|
142
|
+
on_after_stateful_execution: SerializeFunc | None = None,
|
|
148
143
|
on_finished: SerializeFunc | None = None,
|
|
149
144
|
extra: dict[str, Any] | None = None,
|
|
150
145
|
) -> dict[str, dict[str, Any] | None]:
|
|
@@ -154,10 +149,14 @@ def serialize_event(
|
|
|
154
149
|
events.Initialized: on_initialized,
|
|
155
150
|
events.BeforeProbing: on_before_probing,
|
|
156
151
|
events.AfterProbing: on_after_probing,
|
|
152
|
+
events.BeforeAnalysis: on_before_analysis,
|
|
153
|
+
events.AfterAnalysis: on_after_analysis,
|
|
157
154
|
events.BeforeExecution: on_before_execution,
|
|
158
155
|
events.AfterExecution: on_after_execution,
|
|
159
156
|
events.Interrupted: on_interrupted,
|
|
160
157
|
events.InternalError: on_internal_error,
|
|
158
|
+
events.StatefulEvent: on_stateful_event,
|
|
159
|
+
events.AfterStatefulExecution: on_after_stateful_execution,
|
|
161
160
|
events.Finished: on_finished,
|
|
162
161
|
}.get(event.__class__)
|
|
163
162
|
if serializer is None:
|
|
@@ -172,28 +171,3 @@ def serialize_event(
|
|
|
172
171
|
data = merge_recursively(data, extra)
|
|
173
172
|
# Externally tagged structure
|
|
174
173
|
return {event.__class__.__name__: data}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def stringify_path_parameters(path_parameters: dict[str, Any] | None) -> dict[str, str]:
|
|
178
|
-
"""Cast all path parameter values to strings.
|
|
179
|
-
|
|
180
|
-
Path parameter values may be of arbitrary type, but to display them properly they should be casted to strings.
|
|
181
|
-
"""
|
|
182
|
-
return {key: str(value) for key, value in (path_parameters or {}).items()}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def prepare_query(query: dict[str, Any] | None) -> dict[str, list[str]]:
|
|
186
|
-
"""Convert all query values to list of strings.
|
|
187
|
-
|
|
188
|
-
Query parameters may be generated in different shapes, including integers, strings, list of strings, etc.
|
|
189
|
-
It can also be an object, if the schema contains an object, but `style` and `explode` combo is not applicable.
|
|
190
|
-
"""
|
|
191
|
-
|
|
192
|
-
def to_list_of_strings(value: Any) -> list[str]:
|
|
193
|
-
if isinstance(value, list):
|
|
194
|
-
return list(map(str, value))
|
|
195
|
-
if isinstance(value, str):
|
|
196
|
-
return [value]
|
|
197
|
-
return [str(value)]
|
|
198
|
-
|
|
199
|
-
return {key: to_list_of_strings(value) for key, value in (query or {}).items()}
|
schemathesis/service/usage.py
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ...models import APIOperation
|
|
8
|
+
from ...schemas import APIOperationMap
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class OperationCache:
|
|
13
|
+
_maps: dict[str, APIOperationMap] = field(default_factory=dict)
|
|
14
|
+
_operations: dict[str, APIOperation] = field(default_factory=dict)
|
|
15
|
+
|
|
16
|
+
def get_map(self, key: str) -> APIOperationMap | None:
|
|
17
|
+
return self._maps.get(key)
|
|
18
|
+
|
|
19
|
+
def insert_map(self, key: str, value: APIOperationMap) -> None:
|
|
20
|
+
self._maps[key] = value
|
|
21
|
+
|
|
22
|
+
def get_operation(self, key: str) -> APIOperation | None:
|
|
23
|
+
return self._operations.get(key)
|
|
24
|
+
|
|
25
|
+
def insert_operation(self, key: str, value: APIOperation) -> None:
|
|
26
|
+
self._operations[key] = value
|
|
@@ -7,7 +7,7 @@ from json import JSONDecodeError
|
|
|
7
7
|
from typing import IO, TYPE_CHECKING, Any, Callable, Dict, NoReturn, cast
|
|
8
8
|
|
|
9
9
|
from ...code_samples import CodeSampleStyle
|
|
10
|
-
from ...constants import WAIT_FOR_SCHEMA_INTERVAL
|
|
10
|
+
from ...constants import DEFAULT_RESPONSE_TIMEOUT, WAIT_FOR_SCHEMA_INTERVAL
|
|
11
11
|
from ...exceptions import SchemaError, SchemaErrorType
|
|
12
12
|
from ...generation import (
|
|
13
13
|
DEFAULT_DATA_GENERATION_METHODS,
|
|
@@ -16,11 +16,12 @@ from ...generation import (
|
|
|
16
16
|
GenerationConfig,
|
|
17
17
|
)
|
|
18
18
|
from ...hooks import HookContext, dispatch
|
|
19
|
+
from ...internal.output import OutputConfig
|
|
19
20
|
from ...internal.validation import require_relative_url
|
|
20
21
|
from ...loaders import load_schema_from_url
|
|
21
22
|
from ...throttling import build_limiter
|
|
22
23
|
from ...transports.headers import setup_default_headers
|
|
23
|
-
from ...types import PathLike
|
|
24
|
+
from ...types import PathLike, Specification
|
|
24
25
|
|
|
25
26
|
if TYPE_CHECKING:
|
|
26
27
|
from graphql import DocumentNode
|
|
@@ -52,6 +53,7 @@ def from_path(
|
|
|
52
53
|
base_url: str | None = None,
|
|
53
54
|
data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
|
|
54
55
|
generation_config: GenerationConfig | None = None,
|
|
56
|
+
output_config: OutputConfig | None = None,
|
|
55
57
|
code_sample_style: str = CodeSampleStyle.default().name,
|
|
56
58
|
rate_limit: str | None = None,
|
|
57
59
|
encoding: str = "utf8",
|
|
@@ -69,6 +71,8 @@ def from_path(
|
|
|
69
71
|
base_url=base_url,
|
|
70
72
|
data_generation_methods=data_generation_methods,
|
|
71
73
|
code_sample_style=code_sample_style,
|
|
74
|
+
generation_config=generation_config,
|
|
75
|
+
output_config=output_config,
|
|
72
76
|
location=pathlib.Path(path).absolute().as_uri(),
|
|
73
77
|
rate_limit=rate_limit,
|
|
74
78
|
sanitize_output=sanitize_output,
|
|
@@ -135,11 +139,12 @@ def from_url(
|
|
|
135
139
|
interval=WAIT_FOR_SCHEMA_INTERVAL,
|
|
136
140
|
)
|
|
137
141
|
def _load_schema(_uri: str, **_kwargs: Any) -> requests.Response:
|
|
138
|
-
return requests.post(_uri, **
|
|
142
|
+
return requests.post(_uri, **_kwargs)
|
|
139
143
|
|
|
140
144
|
else:
|
|
141
145
|
_load_schema = requests.post
|
|
142
146
|
|
|
147
|
+
kwargs.setdefault("timeout", DEFAULT_RESPONSE_TIMEOUT / 1000)
|
|
143
148
|
response = load_schema_from_url(lambda: _load_schema(url, **kwargs))
|
|
144
149
|
raw_schema = extract_schema_from_response(response)
|
|
145
150
|
return from_dict(
|
|
@@ -161,6 +166,7 @@ def from_file(
|
|
|
161
166
|
base_url: str | None = None,
|
|
162
167
|
data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
|
|
163
168
|
generation_config: GenerationConfig | None = None,
|
|
169
|
+
output_config: OutputConfig | None = None,
|
|
164
170
|
code_sample_style: str = CodeSampleStyle.default().name,
|
|
165
171
|
location: str | None = None,
|
|
166
172
|
rate_limit: str | None = None,
|
|
@@ -198,6 +204,8 @@ def from_file(
|
|
|
198
204
|
app=app,
|
|
199
205
|
base_url=base_url,
|
|
200
206
|
data_generation_methods=data_generation_methods,
|
|
207
|
+
generation_config=generation_config,
|
|
208
|
+
output_config=output_config,
|
|
201
209
|
code_sample_style=code_sample_style,
|
|
202
210
|
location=location,
|
|
203
211
|
rate_limit=rate_limit,
|
|
@@ -221,6 +229,7 @@ def from_dict(
|
|
|
221
229
|
location: str | None = None,
|
|
222
230
|
data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
|
|
223
231
|
generation_config: GenerationConfig | None = None,
|
|
232
|
+
output_config: OutputConfig | None = None,
|
|
224
233
|
code_sample_style: str = CodeSampleStyle.default().name,
|
|
225
234
|
rate_limit: str | None = None,
|
|
226
235
|
sanitize_output: bool = True,
|
|
@@ -233,6 +242,7 @@ def from_dict(
|
|
|
233
242
|
:param app: A WSGI app instance.
|
|
234
243
|
:return: GraphQLSchema
|
|
235
244
|
"""
|
|
245
|
+
from ... import transports
|
|
236
246
|
from .schemas import GraphQLSchema
|
|
237
247
|
|
|
238
248
|
_code_sample_style = CodeSampleStyle.from_str(code_sample_style)
|
|
@@ -245,13 +255,17 @@ def from_dict(
|
|
|
245
255
|
rate_limiter = build_limiter(rate_limit)
|
|
246
256
|
instance = GraphQLSchema(
|
|
247
257
|
raw_schema,
|
|
258
|
+
specification=Specification.GRAPHQL,
|
|
248
259
|
location=location,
|
|
249
260
|
base_url=base_url,
|
|
250
261
|
app=app,
|
|
251
262
|
data_generation_methods=DataGenerationMethod.ensure_list(data_generation_methods),
|
|
263
|
+
generation_config=generation_config or GenerationConfig(),
|
|
264
|
+
output_config=output_config or OutputConfig(),
|
|
252
265
|
code_sample_style=_code_sample_style,
|
|
253
266
|
rate_limiter=rate_limiter,
|
|
254
267
|
sanitize_output=sanitize_output,
|
|
268
|
+
transport=transports.get(app),
|
|
255
269
|
) # type: ignore
|
|
256
270
|
dispatch("after_load_schema", hook_context, instance)
|
|
257
271
|
return instance
|
|
@@ -264,6 +278,7 @@ def from_wsgi(
|
|
|
264
278
|
base_url: str | None = None,
|
|
265
279
|
data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
|
|
266
280
|
generation_config: GenerationConfig | None = None,
|
|
281
|
+
output_config: OutputConfig | None = None,
|
|
267
282
|
code_sample_style: str = CodeSampleStyle.default().name,
|
|
268
283
|
rate_limit: str | None = None,
|
|
269
284
|
sanitize_output: bool = True,
|
|
@@ -292,6 +307,8 @@ def from_wsgi(
|
|
|
292
307
|
base_url=base_url,
|
|
293
308
|
app=app,
|
|
294
309
|
data_generation_methods=data_generation_methods,
|
|
310
|
+
generation_config=generation_config,
|
|
311
|
+
output_config=output_config,
|
|
295
312
|
code_sample_style=code_sample_style,
|
|
296
313
|
rate_limit=rate_limit,
|
|
297
314
|
sanitize_output=sanitize_output,
|
|
@@ -305,6 +322,7 @@ def from_asgi(
|
|
|
305
322
|
base_url: str | None = None,
|
|
306
323
|
data_generation_methods: DataGenerationMethodInput = DEFAULT_DATA_GENERATION_METHODS,
|
|
307
324
|
generation_config: GenerationConfig | None = None,
|
|
325
|
+
output_config: OutputConfig | None = None,
|
|
308
326
|
code_sample_style: str = CodeSampleStyle.default().name,
|
|
309
327
|
rate_limit: str | None = None,
|
|
310
328
|
sanitize_output: bool = True,
|
|
@@ -330,6 +348,8 @@ def from_asgi(
|
|
|
330
348
|
base_url=base_url,
|
|
331
349
|
app=app,
|
|
332
350
|
data_generation_methods=data_generation_methods,
|
|
351
|
+
generation_config=generation_config,
|
|
352
|
+
output_config=output_config,
|
|
333
353
|
code_sample_style=code_sample_style,
|
|
334
354
|
rate_limit=rate_limit,
|
|
335
355
|
sanitize_output=sanitize_output,
|
|
@@ -337,8 +357,8 @@ def from_asgi(
|
|
|
337
357
|
|
|
338
358
|
|
|
339
359
|
def get_loader_for_app(app: Any) -> Callable:
|
|
340
|
-
from
|
|
360
|
+
from ...transports.asgi import is_asgi_app
|
|
341
361
|
|
|
342
|
-
if
|
|
362
|
+
if is_asgi_app(app):
|
|
343
363
|
return from_asgi
|
|
344
364
|
return from_wsgi
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
from functools import lru_cache
|
|
4
4
|
from typing import TYPE_CHECKING
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
from ...exceptions import UsageError
|
|
8
7
|
|
|
9
8
|
if TYPE_CHECKING:
|
|
@@ -31,9 +30,10 @@ def scalar(name: str, strategy: st.SearchStrategy[graphql.ValueNode]) -> None:
|
|
|
31
30
|
@lru_cache
|
|
32
31
|
def get_extra_scalar_strategies() -> dict[str, st.SearchStrategy]:
|
|
33
32
|
"""Get all extra GraphQL strategies."""
|
|
34
|
-
from . import nodes
|
|
35
33
|
from hypothesis import strategies as st
|
|
36
34
|
|
|
35
|
+
from . import nodes
|
|
36
|
+
|
|
37
37
|
dates = st.dates().map(str)
|
|
38
38
|
times = st.times().map("%sZ".__mod__)
|
|
39
39
|
|