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
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, Collection
4
+
5
+ from schemathesis.transport import SerializationContext
6
+ from schemathesis.transport.asgi import ASGI_TRANSPORT
7
+ from schemathesis.transport.requests import REQUESTS_TRANSPORT
8
+ from schemathesis.transport.wsgi import WSGI_TRANSPORT
9
+
10
+ if TYPE_CHECKING:
11
+ from hypothesis import strategies as st
12
+
13
+
14
+ MEDIA_TYPES: dict[str, st.SearchStrategy[bytes]] = {}
15
+
16
+
17
+ def register_media_type(name: str, strategy: st.SearchStrategy[bytes], *, aliases: Collection[str] = ()) -> None:
18
+ r"""Register a custom Hypothesis strategy for generating media type content.
19
+
20
+ Args:
21
+ name: Media type name that matches your OpenAPI requestBody content type
22
+ strategy: Hypothesis strategy that generates bytes for this media type
23
+ aliases: Additional media type names that use the same strategy
24
+
25
+ Example:
26
+ ```python
27
+ import schemathesis
28
+ from hypothesis import strategies as st
29
+
30
+ # Register PDF file strategy
31
+ pdf_strategy = st.sampled_from([
32
+ b"%PDF-1.4\n1 0 obj\n<<\n/Type /Catalog\n>>\nendobj\n%%EOF",
33
+ b"%PDF-1.5\n%\xe2\xe3\xcf\xd3\n1 0 obj\n<<\n/Type /Catalog\n>>\nendobj\n%%EOF"
34
+ ])
35
+ schemathesis.openapi.media_type("application/pdf", pdf_strategy)
36
+
37
+ # Dynamic content generation
38
+ @st.composite
39
+ def xml_content(draw):
40
+ tag = draw(st.text(min_size=3, max_size=10))
41
+ content = draw(st.text(min_size=1, max_size=50))
42
+ return f"<?xml version='1.0'?><{tag}>{content}</{tag}>".encode()
43
+
44
+ schemathesis.openapi.media_type("application/xml", xml_content())
45
+ ```
46
+
47
+ Schema usage:
48
+ ```yaml
49
+ requestBody:
50
+ content:
51
+ application/pdf: # Uses your PDF strategy
52
+ schema:
53
+ type: string
54
+ format: binary
55
+ application/xml: # Uses your XML strategy
56
+ schema:
57
+ type: string
58
+ format: binary
59
+ ```
60
+
61
+ """
62
+
63
+ @REQUESTS_TRANSPORT.serializer(name, *aliases)
64
+ @ASGI_TRANSPORT.serializer(name, *aliases)
65
+ @WSGI_TRANSPORT.serializer(name, *aliases)
66
+ def serialize(ctx: SerializationContext, value: Any) -> dict[str, Any]:
67
+ return {"data": value}
68
+
69
+ MEDIA_TYPES[name] = strategy
70
+ for alias in aliases:
71
+ MEDIA_TYPES[alias] = strategy
72
+
73
+
74
+ def unregister_all() -> None:
75
+ MEDIA_TYPES.clear()
@@ -1,86 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
1
4
  from functools import lru_cache
2
- from typing import Any, Dict, Optional, Tuple
5
+ from typing import TYPE_CHECKING, Any
3
6
  from urllib.parse import urlencode
4
7
 
5
- import attr
6
8
  import jsonschema
7
9
  from hypothesis import strategies as st
8
10
  from hypothesis_jsonschema import from_schema
9
11
 
10
- from .mutations import MutationContext
11
- from .types import Draw, Schema
12
+ from schemathesis.config import GenerationConfig
13
+ from schemathesis.core.jsonschema import ALL_KEYWORDS
14
+ from schemathesis.core.jsonschema.types import JsonSchema
15
+ from schemathesis.core.parameters import ParameterLocation
16
+
17
+ from .mutations import MutationContext, MutationMetadata
18
+
19
+ if TYPE_CHECKING:
20
+ from .types import Draw, Schema
21
+
22
+
23
+ @dataclass
24
+ class GeneratedValue:
25
+ """Wrapper for generated values with optional mutation metadata.
26
+
27
+ This allows us to pass both the value and metadata through the generation pipeline
28
+ without using tuples, making the code cleaner and type-safe.
29
+ """
30
+
31
+ value: Any
32
+ meta: MutationMetadata | None
12
33
 
34
+ __slots__ = ("value", "meta")
13
35
 
14
- @attr.s(slots=True, hash=False)
36
+
37
+ @dataclass
15
38
  class CacheKey:
16
39
  """A cache key for API Operation / location.
17
40
 
18
41
  Carries the schema around but don't use it for hashing to simplify LRU cache usage.
19
42
  """
20
43
 
21
- operation_name: str = attr.ib()
22
- location: str = attr.ib()
23
- schema: Schema = attr.ib()
44
+ operation_name: str
45
+ location: str
46
+ schema: JsonSchema
47
+ validator_cls: type[jsonschema.Validator]
48
+
49
+ __slots__ = ("operation_name", "location", "schema", "validator_cls")
24
50
 
25
51
  def __hash__(self) -> int:
26
52
  return hash((self.operation_name, self.location))
27
53
 
28
54
 
29
- @lru_cache()
30
- def get_validator(cache_key: CacheKey) -> jsonschema.Draft4Validator:
55
+ @lru_cache
56
+ def get_validator(cache_key: CacheKey) -> jsonschema.Validator:
31
57
  """Get JSON Schema validator for the given schema."""
32
58
  # Each operation / location combo has only a single schema, therefore could be cached
33
- return jsonschema.Draft4Validator(cache_key.schema)
34
-
35
-
36
- ALL_KEYWORDS = {
37
- "additionalItems",
38
- "additionalProperties",
39
- "allOf",
40
- "anyOf",
41
- "const",
42
- "contains",
43
- "contentEncoding",
44
- "contentMediaType",
45
- "dependencies",
46
- "enum",
47
- "else",
48
- "exclusiveMaximum",
49
- "exclusiveMinimum",
50
- "format",
51
- "if",
52
- "items",
53
- "maxItems",
54
- "maxLength",
55
- "maxProperties",
56
- "maximum",
57
- "minItems",
58
- "minLength",
59
- "minProperties",
60
- "minimum",
61
- "multipleOf",
62
- "not",
63
- "oneOf",
64
- "pattern",
65
- "patternProperties",
66
- "properties",
67
- "propertyNames",
68
- "$ref",
69
- "required",
70
- "then",
71
- "type",
72
- "uniqueItems",
73
- }
74
-
75
-
76
- @lru_cache()
77
- def split_schema(cache_key: CacheKey) -> Tuple[Schema, Schema]:
59
+ return cache_key.validator_cls(cache_key.schema)
60
+
61
+
62
+ @lru_cache
63
+ def split_schema(cache_key: CacheKey) -> tuple[Schema, Schema]:
78
64
  """Split the schema in two parts.
79
65
 
80
66
  The first one contains only validation JSON Schema keywords, the second one everything else.
81
67
  """
82
68
  keywords, non_keywords = {}, {}
83
- for keyword, value in cache_key.schema.items():
69
+ schema = {} if isinstance(cache_key.schema, bool) else cache_key.schema
70
+ for keyword, value in schema.items():
84
71
  if keyword in ALL_KEYWORDS:
85
72
  keywords[keyword] = value
86
73
  else:
@@ -89,39 +76,60 @@ def split_schema(cache_key: CacheKey) -> Tuple[Schema, Schema]:
89
76
 
90
77
 
91
78
  def negative_schema(
92
- schema: Schema,
79
+ schema: JsonSchema,
93
80
  operation_name: str,
94
- location: str,
95
- media_type: Optional[str],
81
+ location: ParameterLocation,
82
+ media_type: str | None,
83
+ generation_config: GenerationConfig,
96
84
  *,
97
- custom_formats: Dict[str, st.SearchStrategy[str]],
85
+ custom_formats: dict[str, st.SearchStrategy[str]],
86
+ validator_cls: type[jsonschema.Validator],
98
87
  ) -> st.SearchStrategy:
99
88
  """A strategy for instances that DO NOT match the input schema.
100
89
 
101
90
  It is used to cover the input space that is not possible to cover with the "positive" strategy.
91
+
92
+ Returns a strategy that produces GeneratedValue instances with mutation metadata.
102
93
  """
103
94
  # The mutated schema is passed to `from_schema` and guarded against producing instances valid against
104
95
  # the original schema.
105
- cache_key = CacheKey(operation_name, location, schema)
96
+ cache_key = CacheKey(operation_name, location, schema, validator_cls)
106
97
  validator = get_validator(cache_key)
107
98
  keywords, non_keywords = split_schema(cache_key)
108
99
 
109
- if location == "query":
100
+ if location == ParameterLocation.QUERY:
110
101
 
111
- def filter_values(value: Dict[str, Any]) -> bool:
102
+ def filter_values(value: dict[str, Any]) -> bool:
112
103
  return is_non_empty_query(value) and not validator.is_valid(value)
113
104
 
114
105
  else:
115
106
 
116
- def filter_values(value: Dict[str, Any]) -> bool:
107
+ def filter_values(value: dict[str, Any]) -> bool:
117
108
  return not validator.is_valid(value)
118
109
 
119
- return mutated(keywords, non_keywords, location, media_type).flatmap(
120
- lambda s: from_schema(s, custom_formats=custom_formats).filter(filter_values)
121
- )
122
-
123
-
124
- def is_non_empty_query(query: Dict[str, Any]) -> bool:
110
+ def generate_value_with_metadata(value: tuple[dict, MutationMetadata]) -> st.SearchStrategy:
111
+ schema, metadata = value
112
+ return (
113
+ from_schema(
114
+ schema,
115
+ custom_formats=custom_formats,
116
+ allow_x00=generation_config.allow_x00,
117
+ codec=generation_config.codec,
118
+ )
119
+ .filter(filter_values)
120
+ .map(lambda value: GeneratedValue(value, metadata))
121
+ )
122
+
123
+ return mutated(
124
+ keywords=keywords,
125
+ non_keywords=non_keywords,
126
+ location=location,
127
+ media_type=media_type,
128
+ allow_extra_parameters=generation_config.allow_extra_parameters,
129
+ ).flatmap(generate_value_with_metadata)
130
+
131
+
132
+ def is_non_empty_query(query: dict[str, Any]) -> bool:
125
133
  # Whether this query parameters will be encoded to a non-empty query string
126
134
  result = []
127
135
  for key, values in query.items():
@@ -138,8 +146,20 @@ def is_non_empty_query(query: Dict[str, Any]) -> bool:
138
146
  return urlencode(result, doseq=True) != ""
139
147
 
140
148
 
141
- @st.composite # type: ignore
142
- def mutated(draw: Draw, keywords: Schema, non_keywords: Schema, location: str, media_type: Optional[str]) -> Any:
149
+ @st.composite # type: ignore[misc]
150
+ def mutated(
151
+ draw: Draw,
152
+ *,
153
+ keywords: Schema,
154
+ non_keywords: Schema,
155
+ location: ParameterLocation,
156
+ media_type: str | None,
157
+ allow_extra_parameters: bool,
158
+ ) -> Any:
143
159
  return MutationContext(
144
- keywords=keywords, non_keywords=non_keywords, location=location, media_type=media_type
160
+ keywords=keywords,
161
+ non_keywords=non_keywords,
162
+ location=location,
163
+ media_type=media_type,
164
+ allow_extra_parameters=allow_extra_parameters,
145
165
  ).mutate(draw)