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,27 +1,89 @@
1
- from copy import deepcopy
2
- from itertools import chain
3
- from typing import Any, Callable, Dict, List
1
+ from __future__ import annotations
4
2
 
5
- from ...utils import traverse_schema
3
+ from typing import Any, Callable, overload
4
+
5
+ from schemathesis.core.jsonschema.bundler import BUNDLE_STORAGE_KEY
6
+ from schemathesis.core.jsonschema.types import JsonSchema
7
+ from schemathesis.core.transforms import deepclone
8
+ from schemathesis.specs.openapi.patterns import update_quantifier
9
+
10
+
11
+ @overload
12
+ def to_json_schema(
13
+ schema: dict[str, Any],
14
+ nullable_keyword: str,
15
+ is_response_schema: bool = False,
16
+ update_quantifiers: bool = True,
17
+ clone: bool = True,
18
+ ) -> dict[str, Any]: ... # pragma: no cover
19
+
20
+
21
+ @overload
22
+ def to_json_schema(
23
+ schema: bool,
24
+ nullable_keyword: str,
25
+ is_response_schema: bool = False,
26
+ update_quantifiers: bool = True,
27
+ clone: bool = True,
28
+ ) -> bool: ... # pragma: no cover
6
29
 
7
30
 
8
31
  def to_json_schema(
9
- schema: Dict[str, Any], *, nullable_name: str, copy: bool = True, is_response_schema: bool = False
10
- ) -> Dict[str, Any]:
11
- """Convert Open API parameters to JSON Schema.
12
-
13
- NOTE. This function is applied to all keywords (including nested) during a schema resolving, thus it is not recursive.
14
- See a recursive version below.
15
- """
16
- if copy:
17
- schema = deepcopy(schema)
18
- if schema.get(nullable_name) is True:
19
- del schema[nullable_name]
32
+ schema: dict[str, Any] | bool,
33
+ nullable_keyword: str,
34
+ is_response_schema: bool = False,
35
+ update_quantifiers: bool = True,
36
+ clone: bool = True,
37
+ ) -> dict[str, Any] | bool:
38
+ if isinstance(schema, bool):
39
+ return schema
40
+ if clone:
41
+ schema = deepclone(schema)
42
+ return _to_json_schema(
43
+ schema,
44
+ nullable_keyword=nullable_keyword,
45
+ is_response_schema=is_response_schema,
46
+ update_quantifiers=update_quantifiers,
47
+ )
48
+
49
+
50
+ def _to_json_schema(
51
+ schema: JsonSchema,
52
+ *,
53
+ nullable_keyword: str,
54
+ is_response_schema: bool = False,
55
+ update_quantifiers: bool = True,
56
+ ) -> JsonSchema:
57
+ if isinstance(schema, bool):
58
+ return schema
59
+
60
+ if schema.get(nullable_keyword) is True:
61
+ del schema[nullable_keyword]
62
+ bundled = schema.pop(BUNDLE_STORAGE_KEY, None)
20
63
  schema = {"anyOf": [schema, {"type": "null"}]}
64
+ if bundled:
65
+ schema[BUNDLE_STORAGE_KEY] = bundled
21
66
  schema_type = schema.get("type")
22
67
  if schema_type == "file":
23
68
  schema["type"] = "string"
24
69
  schema["format"] = "binary"
70
+ if update_quantifiers:
71
+ update_pattern_in_schema(schema)
72
+ # Sometimes `required` is incorrectly has a boolean value
73
+ properties = schema.get("properties")
74
+ if isinstance(properties, dict):
75
+ for name, subschema in properties.items():
76
+ if not isinstance(subschema, dict):
77
+ continue
78
+ is_required = subschema.get("required")
79
+ if is_required is True:
80
+ schema.setdefault("required", []).append(name)
81
+ del subschema["required"]
82
+ elif is_required is False:
83
+ if "required" in schema and name in schema["required"]:
84
+ schema["required"].remove(name)
85
+ del subschema["required"]
86
+
25
87
  if schema_type == "object":
26
88
  if is_response_schema:
27
89
  # Write-only properties should not occur in responses
@@ -29,43 +91,120 @@ def to_json_schema(
29
91
  else:
30
92
  # Read-only properties should not occur in requests
31
93
  rewrite_properties(schema, is_read_only)
94
+
95
+ ensure_required_properties(schema)
96
+
97
+ for keyword, value in schema.items():
98
+ if keyword in IN_VALUE and isinstance(value, dict):
99
+ schema[keyword] = _to_json_schema(
100
+ value,
101
+ nullable_keyword=nullable_keyword,
102
+ is_response_schema=is_response_schema,
103
+ update_quantifiers=update_quantifiers,
104
+ )
105
+ elif keyword in IN_ITEM and isinstance(value, list):
106
+ for idx, subschema in enumerate(value):
107
+ value[idx] = _to_json_schema(
108
+ subschema,
109
+ nullable_keyword=nullable_keyword,
110
+ is_response_schema=is_response_schema,
111
+ update_quantifiers=update_quantifiers,
112
+ )
113
+ elif keyword in IN_CHILD and isinstance(value, dict):
114
+ for name, subschema in value.items():
115
+ value[name] = _to_json_schema(
116
+ subschema,
117
+ nullable_keyword=nullable_keyword,
118
+ is_response_schema=is_response_schema,
119
+ update_quantifiers=update_quantifiers,
120
+ )
121
+
32
122
  return schema
33
123
 
34
124
 
35
- def rewrite_properties(schema: Dict[str, Any], predicate: Callable[[Dict[str, Any]], bool]) -> None:
125
+ def ensure_required_properties(schema: dict[str, Any]) -> None:
126
+ if schema.get("additionalProperties") is not False:
127
+ return
128
+
129
+ required = schema.get("required")
130
+ if not required or not isinstance(required, list):
131
+ return
132
+
133
+ properties = schema.setdefault("properties", {})
134
+
135
+ # Add missing required properties as empty schemas
136
+ for name in required:
137
+ if name not in properties:
138
+ properties[name] = {}
139
+
140
+
141
+ IN_VALUE = frozenset(
142
+ (
143
+ "additionalProperties",
144
+ "contains",
145
+ "contentSchema",
146
+ "else",
147
+ "if",
148
+ "items",
149
+ "not",
150
+ "propertyNames",
151
+ "then",
152
+ "unevaluatedItems",
153
+ "unevaluatedProperties",
154
+ )
155
+ )
156
+ IN_ITEM = frozenset(
157
+ (
158
+ "allOf",
159
+ "anyOf",
160
+ "oneOf",
161
+ )
162
+ )
163
+ IN_CHILD = frozenset(
164
+ (
165
+ "prefixItems",
166
+ "$defs",
167
+ "definitions",
168
+ "dependentSchemas",
169
+ "patternProperties",
170
+ "properties",
171
+ BUNDLE_STORAGE_KEY,
172
+ )
173
+ )
174
+
175
+
176
+ def update_pattern_in_schema(schema: dict[str, Any]) -> None:
177
+ pattern = schema.get("pattern")
178
+ min_length = schema.get("minLength")
179
+ max_length = schema.get("maxLength")
180
+ if pattern and (min_length or max_length):
181
+ new_pattern = update_quantifier(pattern, min_length, max_length)
182
+ if new_pattern != pattern:
183
+ schema.pop("minLength", None)
184
+ schema.pop("maxLength", None)
185
+ schema["pattern"] = new_pattern
186
+
187
+
188
+ def rewrite_properties(schema: dict[str, Any], predicate: Callable[[dict[str, Any]], bool]) -> None:
36
189
  required = schema.get("required", [])
37
- forbidden = []
38
190
  for name, subschema in list(schema.get("properties", {}).items()):
39
191
  if predicate(subschema):
40
192
  if name in required:
41
193
  required.remove(name)
42
- del schema["properties"][name]
43
- forbidden.append(name)
44
- if forbidden:
45
- forbid_properties(schema, forbidden)
194
+ schema["properties"][name] = {"not": {}}
46
195
  if not schema.get("required"):
47
196
  schema.pop("required", None)
48
197
  if not schema.get("properties"):
49
198
  schema.pop("properties", None)
50
199
 
51
200
 
52
- def forbid_properties(schema: Dict[str, Any], forbidden: List[str]) -> None:
53
- """Explicitly forbid properties via the `not` keyword."""
54
- not_schema = schema.setdefault("not", {})
55
- already_forbidden = not_schema.setdefault("required", [])
56
- already_forbidden.extend(forbidden)
57
- not_schema["required"] = list(set(chain(already_forbidden, forbidden)))
58
-
59
-
60
- def is_write_only(schema: Dict[str, Any]) -> bool:
201
+ def is_write_only(schema: dict[str, Any] | bool) -> bool:
202
+ if isinstance(schema, bool):
203
+ return False
61
204
  return schema.get("writeOnly", False) or schema.get("x-writeOnly", False)
62
205
 
63
206
 
64
- def is_read_only(schema: Dict[str, Any]) -> bool:
207
+ def is_read_only(schema: dict[str, Any] | bool) -> bool:
208
+ if isinstance(schema, bool):
209
+ return False
65
210
  return schema.get("readOnly", False)
66
-
67
-
68
- def to_json_schema_recursive(
69
- schema: Dict[str, Any], nullable_name: str, is_response_schema: bool = False
70
- ) -> Dict[str, Any]:
71
- return traverse_schema(schema, to_json_schema, nullable_name=nullable_name, is_response_schema=is_response_schema)