schemathesis 3.35.1__py3-none-any.whl → 3.35.3__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/_hypothesis.py +12 -14
- schemathesis/cli/__init__.py +424 -412
- schemathesis/cli/context.py +7 -3
- schemathesis/cli/output/default.py +13 -2
- schemathesis/generation/coverage.py +57 -14
- schemathesis/models.py +23 -2
- schemathesis/runner/events.py +6 -1
- schemathesis/runner/impl/core.py +1 -2
- schemathesis/runner/serialization.py +10 -2
- schemathesis/schemas.py +3 -9
- schemathesis/specs/graphql/loaders.py +2 -1
- schemathesis/specs/openapi/links.py +11 -2
- schemathesis/specs/openapi/loaders.py +3 -1
- schemathesis/specs/openapi/parameters.py +16 -9
- schemathesis/stateful/context.py +3 -0
- schemathesis/stateful/runner.py +8 -1
- schemathesis/types.py +8 -0
- {schemathesis-3.35.1.dist-info → schemathesis-3.35.3.dist-info}/METADATA +69 -168
- {schemathesis-3.35.1.dist-info → schemathesis-3.35.3.dist-info}/RECORD +22 -22
- {schemathesis-3.35.1.dist-info → schemathesis-3.35.3.dist-info}/WHEEL +0 -0
- {schemathesis-3.35.1.dist-info → schemathesis-3.35.3.dist-info}/entry_points.txt +0 -0
- {schemathesis-3.35.1.dist-info → schemathesis-3.35.3.dist-info}/licenses/LICENSE +0 -0
schemathesis/cli/__init__.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import base64
|
|
4
|
-
import enum
|
|
5
4
|
import io
|
|
6
5
|
import os
|
|
7
6
|
import sys
|
|
@@ -126,10 +125,10 @@ def reset_targets() -> None:
|
|
|
126
125
|
|
|
127
126
|
|
|
128
127
|
@click.group(context_settings=CONTEXT_SETTINGS)
|
|
129
|
-
@click.option("--pre-run", help="A module to execute before running the tests
|
|
128
|
+
@click.option("--pre-run", help="[DEPRECATED] A module to execute before running the tests", type=str, hidden=True)
|
|
130
129
|
@click.version_option()
|
|
131
130
|
def schemathesis(pre_run: str | None = None) -> None:
|
|
132
|
-
"""
|
|
131
|
+
"""Property-based API testing for OpenAPI and GraphQL."""
|
|
133
132
|
# Don't use `envvar=HOOKS_MODULE_ENV_VAR` arg to raise a deprecation warning for hooks
|
|
134
133
|
hooks: str | None
|
|
135
134
|
if pre_run:
|
|
@@ -141,76 +140,89 @@ def schemathesis(pre_run: str | None = None) -> None:
|
|
|
141
140
|
load_hook(hooks)
|
|
142
141
|
|
|
143
142
|
|
|
144
|
-
|
|
145
|
-
filtering = "Testing scope", "Customize the scope of the API testing."
|
|
146
|
-
validation = "Response & Schema validation", "These options specify how API responses and schemas are validated."
|
|
147
|
-
hypothesis = "Hypothesis engine", "Configuration of the underlying Hypothesis engine."
|
|
148
|
-
generic = "Generic", None
|
|
143
|
+
GROUPS: list[str] = []
|
|
149
144
|
|
|
150
145
|
|
|
151
|
-
class
|
|
146
|
+
class CommandWithGroupedOptions(click.Command):
|
|
152
147
|
def format_options(self, ctx: click.Context, formatter: click.HelpFormatter) -> None:
|
|
153
|
-
# Group options first
|
|
154
148
|
groups = defaultdict(list)
|
|
155
149
|
for param in self.get_params(ctx):
|
|
156
150
|
rv = param.get_help_record(ctx)
|
|
157
151
|
if rv is not None:
|
|
152
|
+
(option_repr, message) = rv
|
|
153
|
+
if isinstance(param.type, click.Choice):
|
|
154
|
+
message += (
|
|
155
|
+
getattr(param.type, "choices_repr", None)
|
|
156
|
+
or f" [possible values: {', '.join(param.type.choices)}]"
|
|
157
|
+
)
|
|
158
|
+
|
|
158
159
|
if isinstance(param, GroupedOption):
|
|
159
160
|
group = param.group
|
|
160
161
|
else:
|
|
161
|
-
group =
|
|
162
|
-
groups[group].append(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
title, description = group.value
|
|
167
|
-
with formatter.section(title):
|
|
168
|
-
if description:
|
|
169
|
-
formatter.write_paragraph()
|
|
170
|
-
formatter.write_text(description)
|
|
171
|
-
formatter.write_paragraph()
|
|
172
|
-
formatter.write_dl(opts)
|
|
162
|
+
group = "Global options"
|
|
163
|
+
groups[group].append((option_repr, message))
|
|
164
|
+
for group in GROUPS:
|
|
165
|
+
with formatter.section(group or "Options"):
|
|
166
|
+
formatter.write_dl(groups[group], col_max=40)
|
|
173
167
|
|
|
174
168
|
|
|
175
169
|
class GroupedOption(click.Option):
|
|
176
|
-
def __init__(self, *args: Any, group:
|
|
170
|
+
def __init__(self, *args: Any, group: str | None = None, **kwargs: Any):
|
|
177
171
|
super().__init__(*args, **kwargs)
|
|
178
172
|
self.group = group
|
|
179
173
|
|
|
180
174
|
|
|
181
|
-
|
|
175
|
+
def group(name: str) -> Callable:
|
|
176
|
+
GROUPS.append(name)
|
|
177
|
+
|
|
178
|
+
def _inner(cmd: Callable) -> Callable:
|
|
179
|
+
for param in reversed(cmd.__click_params__): # type: ignore[attr-defined]
|
|
180
|
+
if not isinstance(param, GroupedOption) or param.group is not None:
|
|
181
|
+
break
|
|
182
|
+
param.group = name
|
|
183
|
+
return cmd
|
|
184
|
+
|
|
185
|
+
return _inner
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def grouped_option(*args: Any, **kwargs: Any) -> Callable:
|
|
189
|
+
kwargs.setdefault("cls", GroupedOption)
|
|
190
|
+
return click.option(*args, **kwargs)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
with_request_proxy = grouped_option(
|
|
182
194
|
"--request-proxy",
|
|
183
|
-
help="Set the proxy for all network requests
|
|
195
|
+
help="Set the proxy for all network requests",
|
|
184
196
|
type=str,
|
|
185
197
|
)
|
|
186
|
-
with_request_tls_verify =
|
|
198
|
+
with_request_tls_verify = grouped_option(
|
|
187
199
|
"--request-tls-verify",
|
|
188
|
-
help="Configures TLS certificate verification for server requests. Can specify path to CA_BUNDLE for custom certs
|
|
200
|
+
help="Configures TLS certificate verification for server requests. Can specify path to CA_BUNDLE for custom certs",
|
|
189
201
|
type=str,
|
|
190
202
|
default="true",
|
|
191
203
|
show_default=True,
|
|
192
204
|
callback=callbacks.convert_boolean_string,
|
|
193
205
|
)
|
|
194
|
-
with_request_cert =
|
|
206
|
+
with_request_cert = grouped_option(
|
|
195
207
|
"--request-cert",
|
|
196
208
|
help="File path of unencrypted client certificate for authentication. "
|
|
197
209
|
"The certificate can be bundled with a private key (e.g. PEM) or the private "
|
|
198
|
-
"key can be provided with the --request-cert-key argument
|
|
210
|
+
"key can be provided with the --request-cert-key argument",
|
|
199
211
|
type=click.Path(exists=True),
|
|
200
212
|
default=None,
|
|
201
213
|
show_default=False,
|
|
202
214
|
)
|
|
203
|
-
with_request_cert_key =
|
|
215
|
+
with_request_cert_key = grouped_option(
|
|
204
216
|
"--request-cert-key",
|
|
205
|
-
help="
|
|
217
|
+
help="Specify the file path of the private key for the client certificate",
|
|
206
218
|
type=click.Path(exists=True),
|
|
207
219
|
default=None,
|
|
208
220
|
show_default=False,
|
|
209
221
|
callback=callbacks.validate_request_cert_key,
|
|
210
222
|
)
|
|
211
|
-
with_hosts_file =
|
|
223
|
+
with_hosts_file = grouped_option(
|
|
212
224
|
"--hosts-file",
|
|
213
|
-
help="Path to a file to store the Schemathesis.io auth configuration
|
|
225
|
+
help="Path to a file to store the Schemathesis.io auth configuration",
|
|
214
226
|
type=click.Path(dir_okay=False, writable=True),
|
|
215
227
|
default=service.DEFAULT_HOSTS_PATH,
|
|
216
228
|
envvar=service.HOSTS_PATH_ENV_VAR,
|
|
@@ -230,13 +242,11 @@ def _with_filter(*, by: str, mode: Literal["include", "exclude"], modifier: Lite
|
|
|
230
242
|
param += f"-{modifier}"
|
|
231
243
|
prop += " pattern"
|
|
232
244
|
help_text = f"{prop} to {action} testing."
|
|
233
|
-
return
|
|
245
|
+
return grouped_option(
|
|
234
246
|
param,
|
|
235
247
|
help=help_text,
|
|
236
248
|
type=str,
|
|
237
249
|
multiple=modifier is None,
|
|
238
|
-
cls=GroupedOption,
|
|
239
|
-
group=ParameterGroup.filtering,
|
|
240
250
|
)
|
|
241
251
|
|
|
242
252
|
|
|
@@ -258,569 +268,549 @@ class ReportToService:
|
|
|
258
268
|
REPORT_TO_SERVICE = ReportToService()
|
|
259
269
|
|
|
260
270
|
|
|
261
|
-
@schemathesis.command(
|
|
271
|
+
@schemathesis.command(
|
|
272
|
+
short_help="Execute automated tests based on API specifications",
|
|
273
|
+
cls=CommandWithGroupedOptions,
|
|
274
|
+
context_settings={"terminal_width": output.default.get_terminal_width(), **CONTEXT_SETTINGS},
|
|
275
|
+
)
|
|
262
276
|
@click.argument("schema", type=str)
|
|
263
277
|
@click.argument("api_name", type=str, required=False, envvar=API_NAME_ENV_VAR)
|
|
264
|
-
@
|
|
278
|
+
@group("Options")
|
|
279
|
+
@grouped_option(
|
|
280
|
+
"--workers",
|
|
281
|
+
"-w",
|
|
282
|
+
"workers_num",
|
|
283
|
+
help="Number of concurrent workers for testing. Auto-adjusts if 'auto' is specified",
|
|
284
|
+
type=CustomHelpMessageChoice(
|
|
285
|
+
["auto"] + list(map(str, range(MIN_WORKERS, MAX_WORKERS + 1))),
|
|
286
|
+
choices_repr=f"[auto, {MIN_WORKERS}-{MAX_WORKERS}]",
|
|
287
|
+
),
|
|
288
|
+
default=str(DEFAULT_WORKERS),
|
|
289
|
+
show_default=True,
|
|
290
|
+
callback=callbacks.convert_workers,
|
|
291
|
+
metavar="",
|
|
292
|
+
)
|
|
293
|
+
@grouped_option(
|
|
294
|
+
"--dry-run",
|
|
295
|
+
"dry_run",
|
|
296
|
+
is_flag=True,
|
|
297
|
+
default=False,
|
|
298
|
+
help="Simulate test execution without making any actual requests, useful for validating data generation",
|
|
299
|
+
)
|
|
300
|
+
@grouped_option(
|
|
301
|
+
"--experimental",
|
|
302
|
+
"experiments",
|
|
303
|
+
help="Enable experimental features",
|
|
304
|
+
type=click.Choice(
|
|
305
|
+
[
|
|
306
|
+
experimental.OPEN_API_3_1.name,
|
|
307
|
+
experimental.SCHEMA_ANALYSIS.name,
|
|
308
|
+
experimental.STATEFUL_TEST_RUNNER.name,
|
|
309
|
+
experimental.STATEFUL_ONLY.name,
|
|
310
|
+
experimental.COVERAGE_PHASE.name,
|
|
311
|
+
]
|
|
312
|
+
),
|
|
313
|
+
callback=callbacks.convert_experimental,
|
|
314
|
+
multiple=True,
|
|
315
|
+
metavar="",
|
|
316
|
+
)
|
|
317
|
+
@grouped_option(
|
|
318
|
+
"--fixups",
|
|
319
|
+
help="Apply compatibility adjustments",
|
|
320
|
+
multiple=True,
|
|
321
|
+
type=click.Choice(list(ALL_FIXUPS) + ["all"]),
|
|
322
|
+
metavar="",
|
|
323
|
+
)
|
|
324
|
+
@group("API validation options")
|
|
325
|
+
@grouped_option(
|
|
265
326
|
"--checks",
|
|
266
327
|
"-c",
|
|
267
328
|
multiple=True,
|
|
268
|
-
help="
|
|
269
|
-
"Provide a comma-separated list of checks such as 'not_a_server_error,status_code_conformance', etc. "
|
|
270
|
-
f"Default is '{','.join(DEFAULT_CHECKS_NAMES)}'.",
|
|
329
|
+
help="Comma-separated list of checks to run against API responses",
|
|
271
330
|
type=CHECKS_TYPE,
|
|
272
331
|
default=DEFAULT_CHECKS_NAMES,
|
|
273
|
-
cls=GroupedOption,
|
|
274
|
-
group=ParameterGroup.validation,
|
|
275
332
|
callback=callbacks.convert_checks,
|
|
276
333
|
show_default=True,
|
|
334
|
+
metavar="",
|
|
277
335
|
)
|
|
278
|
-
@
|
|
336
|
+
@grouped_option(
|
|
279
337
|
"--exclude-checks",
|
|
280
338
|
multiple=True,
|
|
281
|
-
help="
|
|
282
|
-
"Provide a comma-separated list of checks you wish to bypass.",
|
|
339
|
+
help="Comma-separated list of checks to skip during testing",
|
|
283
340
|
type=EXCLUDE_CHECKS_TYPE,
|
|
284
341
|
default=[],
|
|
285
|
-
cls=GroupedOption,
|
|
286
|
-
group=ParameterGroup.validation,
|
|
287
342
|
callback=callbacks.convert_checks,
|
|
288
343
|
show_default=True,
|
|
344
|
+
metavar="",
|
|
289
345
|
)
|
|
290
|
-
@
|
|
291
|
-
"--data-generation-method",
|
|
292
|
-
"-D",
|
|
293
|
-
"data_generation_methods",
|
|
294
|
-
help="Specifies the approach Schemathesis uses to generate test data. "
|
|
295
|
-
"Use 'positive' for valid data, 'negative' for invalid data, or 'all' for both. "
|
|
296
|
-
"Default is 'positive'.",
|
|
297
|
-
type=DATA_GENERATION_METHOD_TYPE,
|
|
298
|
-
default=DataGenerationMethod.default().name,
|
|
299
|
-
callback=callbacks.convert_data_generation_method,
|
|
300
|
-
show_default=True,
|
|
301
|
-
)
|
|
302
|
-
@click.option(
|
|
346
|
+
@grouped_option(
|
|
303
347
|
"--max-response-time",
|
|
304
|
-
help="
|
|
305
|
-
"The test will fail if a response time exceeds this limit. "
|
|
306
|
-
"Provide the time in milliseconds.",
|
|
348
|
+
help="Time limit in milliseconds for API response times. "
|
|
349
|
+
"The test will fail if a response time exceeds this limit. ",
|
|
307
350
|
type=click.IntRange(min=1),
|
|
308
|
-
cls=GroupedOption,
|
|
309
|
-
group=ParameterGroup.validation,
|
|
310
|
-
)
|
|
311
|
-
@click.option(
|
|
312
|
-
"--target",
|
|
313
|
-
"-t",
|
|
314
|
-
"targets",
|
|
315
|
-
multiple=True,
|
|
316
|
-
help="Guides input generation to values more likely to expose bugs via targeted property-based testing.",
|
|
317
|
-
type=TARGETS_TYPE,
|
|
318
|
-
default=DEFAULT_TARGETS_NAMES,
|
|
319
|
-
show_default=True,
|
|
320
351
|
)
|
|
321
|
-
@
|
|
352
|
+
@grouped_option(
|
|
322
353
|
"-x",
|
|
323
354
|
"--exitfirst",
|
|
324
355
|
"exit_first",
|
|
325
356
|
is_flag=True,
|
|
326
357
|
default=False,
|
|
327
|
-
help="
|
|
358
|
+
help="Terminate the test suite immediately upon the first failure or error encountered",
|
|
328
359
|
show_default=True,
|
|
329
360
|
)
|
|
330
|
-
@
|
|
361
|
+
@grouped_option(
|
|
331
362
|
"--max-failures",
|
|
332
363
|
"max_failures",
|
|
333
364
|
type=click.IntRange(min=1),
|
|
334
|
-
help="
|
|
365
|
+
help="Terminate the test suite after reaching a specified number of failures or errors",
|
|
335
366
|
show_default=True,
|
|
336
367
|
)
|
|
337
|
-
@
|
|
338
|
-
|
|
339
|
-
"
|
|
340
|
-
|
|
341
|
-
default=False,
|
|
342
|
-
help="Simulates test execution without making any actual requests, useful for validating data generation.",
|
|
343
|
-
)
|
|
344
|
-
@click.option(
|
|
345
|
-
"--auth",
|
|
346
|
-
"-a",
|
|
347
|
-
help="Provides the server authentication details in the 'USER:PASSWORD' format.",
|
|
368
|
+
@group("Loader options")
|
|
369
|
+
@grouped_option(
|
|
370
|
+
"--app",
|
|
371
|
+
help="Specify the WSGI/ASGI application under test, provided as an importable Python path",
|
|
348
372
|
type=str,
|
|
349
|
-
callback=callbacks.
|
|
373
|
+
callback=callbacks.validate_app,
|
|
350
374
|
)
|
|
351
|
-
@
|
|
352
|
-
"--
|
|
353
|
-
"
|
|
354
|
-
type=click.
|
|
355
|
-
default=
|
|
356
|
-
|
|
357
|
-
show_default=True,
|
|
375
|
+
@grouped_option(
|
|
376
|
+
"--wait-for-schema",
|
|
377
|
+
help="Maximum duration, in seconds, to wait for the API schema to become available. Disabled by default",
|
|
378
|
+
type=click.FloatRange(1.0),
|
|
379
|
+
default=None,
|
|
380
|
+
envvar=WAIT_FOR_SCHEMA_ENV_VAR,
|
|
358
381
|
)
|
|
359
|
-
@
|
|
360
|
-
"--
|
|
361
|
-
"
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
callback=callbacks.validate_set_query,
|
|
382
|
+
@grouped_option(
|
|
383
|
+
"--validate-schema",
|
|
384
|
+
help="Validate input API schema. Set to 'true' to enable or 'false' to disable",
|
|
385
|
+
type=bool,
|
|
386
|
+
default=False,
|
|
387
|
+
show_default=True,
|
|
366
388
|
)
|
|
367
|
-
@
|
|
368
|
-
|
|
369
|
-
"
|
|
370
|
-
|
|
371
|
-
|
|
389
|
+
@group("Network requests options")
|
|
390
|
+
@grouped_option(
|
|
391
|
+
"--base-url",
|
|
392
|
+
"-b",
|
|
393
|
+
help="Base URL of the API, required when schema is provided as a file",
|
|
372
394
|
type=str,
|
|
373
|
-
callback=callbacks.
|
|
395
|
+
callback=callbacks.validate_base_url,
|
|
396
|
+
envvar=BASE_URL_ENV_VAR,
|
|
374
397
|
)
|
|
375
|
-
@
|
|
376
|
-
"--
|
|
377
|
-
"
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
type=str,
|
|
381
|
-
callback=callbacks.validate_set_cookie,
|
|
398
|
+
@grouped_option(
|
|
399
|
+
"--request-timeout",
|
|
400
|
+
help="Timeout limit, in milliseconds, for each network request during tests",
|
|
401
|
+
type=click.IntRange(1),
|
|
402
|
+
default=DEFAULT_RESPONSE_TIMEOUT,
|
|
382
403
|
)
|
|
383
|
-
@
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
404
|
+
@with_request_proxy
|
|
405
|
+
@with_request_tls_verify
|
|
406
|
+
@with_request_cert
|
|
407
|
+
@with_request_cert_key
|
|
408
|
+
@grouped_option(
|
|
409
|
+
"--rate-limit",
|
|
410
|
+
help="Specify a rate limit for test requests in '<limit>/<duration>' format. "
|
|
411
|
+
"Example - `100/m` for 100 requests per minute",
|
|
388
412
|
type=str,
|
|
389
|
-
callback=callbacks.
|
|
413
|
+
callback=callbacks.validate_rate_limit,
|
|
390
414
|
)
|
|
391
|
-
@
|
|
415
|
+
@grouped_option(
|
|
392
416
|
"--header",
|
|
393
417
|
"-H",
|
|
394
418
|
"headers",
|
|
395
|
-
help=r"
|
|
419
|
+
help=r"Add a custom HTTP header to all API requests. Format: 'Header-Name: Value'",
|
|
396
420
|
multiple=True,
|
|
397
421
|
type=str,
|
|
398
422
|
callback=callbacks.validate_headers,
|
|
399
423
|
)
|
|
424
|
+
@grouped_option(
|
|
425
|
+
"--auth",
|
|
426
|
+
"-a",
|
|
427
|
+
help="Provide the server authentication details in the 'USER:PASSWORD' format",
|
|
428
|
+
type=str,
|
|
429
|
+
callback=callbacks.validate_auth,
|
|
430
|
+
)
|
|
431
|
+
@grouped_option(
|
|
432
|
+
"--auth-type",
|
|
433
|
+
"-A",
|
|
434
|
+
type=click.Choice(["basic", "digest"], case_sensitive=False),
|
|
435
|
+
default="basic",
|
|
436
|
+
help="Specify the authentication method",
|
|
437
|
+
show_default=True,
|
|
438
|
+
metavar="",
|
|
439
|
+
)
|
|
440
|
+
@group("Filtering options")
|
|
400
441
|
@with_filters
|
|
401
|
-
@
|
|
442
|
+
@grouped_option(
|
|
402
443
|
"--include-by",
|
|
403
444
|
"include_by",
|
|
404
445
|
type=str,
|
|
405
446
|
help="Include API operations by expression",
|
|
406
|
-
cls=GroupedOption,
|
|
407
|
-
group=ParameterGroup.filtering,
|
|
408
447
|
)
|
|
409
|
-
@
|
|
448
|
+
@grouped_option(
|
|
410
449
|
"--exclude-by",
|
|
411
450
|
"exclude_by",
|
|
412
451
|
type=str,
|
|
413
452
|
help="Exclude API operations by expression",
|
|
414
|
-
cls=GroupedOption,
|
|
415
|
-
group=ParameterGroup.filtering,
|
|
416
453
|
)
|
|
417
|
-
@
|
|
454
|
+
@grouped_option(
|
|
418
455
|
"--exclude-deprecated",
|
|
419
|
-
help="Exclude deprecated API operations from testing
|
|
456
|
+
help="Exclude deprecated API operations from testing",
|
|
420
457
|
is_flag=True,
|
|
421
458
|
is_eager=True,
|
|
422
459
|
default=False,
|
|
423
460
|
show_default=True,
|
|
424
|
-
cls=GroupedOption,
|
|
425
|
-
group=ParameterGroup.filtering,
|
|
426
461
|
)
|
|
427
|
-
@
|
|
462
|
+
@grouped_option(
|
|
428
463
|
"--endpoint",
|
|
429
464
|
"-E",
|
|
430
465
|
"endpoints",
|
|
431
466
|
type=str,
|
|
432
467
|
multiple=True,
|
|
433
|
-
help=r"API operation path pattern (e.g., users/\d+)
|
|
468
|
+
help=r"[DEPRECATED] API operation path pattern (e.g., users/\d+)",
|
|
434
469
|
callback=callbacks.validate_regex,
|
|
435
|
-
|
|
436
|
-
group=ParameterGroup.filtering,
|
|
470
|
+
hidden=True,
|
|
437
471
|
)
|
|
438
|
-
@
|
|
472
|
+
@grouped_option(
|
|
439
473
|
"--method",
|
|
440
474
|
"-M",
|
|
441
475
|
"methods",
|
|
442
476
|
type=str,
|
|
443
477
|
multiple=True,
|
|
444
|
-
help="HTTP method (e.g., GET, POST)
|
|
478
|
+
help="[DEPRECATED] HTTP method (e.g., GET, POST)",
|
|
445
479
|
callback=callbacks.validate_regex,
|
|
446
|
-
|
|
447
|
-
group=ParameterGroup.filtering,
|
|
480
|
+
hidden=True,
|
|
448
481
|
)
|
|
449
|
-
@
|
|
482
|
+
@grouped_option(
|
|
450
483
|
"--tag",
|
|
451
484
|
"-T",
|
|
452
485
|
"tags",
|
|
453
486
|
type=str,
|
|
454
487
|
multiple=True,
|
|
455
|
-
help="Schema tag pattern
|
|
488
|
+
help="[DEPRECATED] Schema tag pattern",
|
|
456
489
|
callback=callbacks.validate_regex,
|
|
457
|
-
|
|
458
|
-
group=ParameterGroup.filtering,
|
|
490
|
+
hidden=True,
|
|
459
491
|
)
|
|
460
|
-
@
|
|
492
|
+
@grouped_option(
|
|
461
493
|
"--operation-id",
|
|
462
494
|
"-O",
|
|
463
495
|
"operation_ids",
|
|
464
496
|
type=str,
|
|
465
497
|
multiple=True,
|
|
466
|
-
help="OpenAPI operationId pattern
|
|
498
|
+
help="[DEPRECATED] OpenAPI operationId pattern",
|
|
467
499
|
callback=callbacks.validate_regex,
|
|
468
|
-
|
|
469
|
-
group=ParameterGroup.filtering,
|
|
470
|
-
)
|
|
471
|
-
@click.option(
|
|
472
|
-
"--workers",
|
|
473
|
-
"-w",
|
|
474
|
-
"workers_num",
|
|
475
|
-
help="Sets the number of concurrent workers for testing. Auto-adjusts if 'auto' is specified.",
|
|
476
|
-
type=CustomHelpMessageChoice(
|
|
477
|
-
["auto"] + list(map(str, range(MIN_WORKERS, MAX_WORKERS + 1))),
|
|
478
|
-
choices_repr=f"[auto|{MIN_WORKERS}-{MAX_WORKERS}]",
|
|
479
|
-
),
|
|
480
|
-
default=str(DEFAULT_WORKERS),
|
|
481
|
-
show_default=True,
|
|
482
|
-
callback=callbacks.convert_workers,
|
|
483
|
-
)
|
|
484
|
-
@click.option(
|
|
485
|
-
"--base-url",
|
|
486
|
-
"-b",
|
|
487
|
-
help="Provides the base URL of the API, required when schema is provided as a file.",
|
|
488
|
-
type=str,
|
|
489
|
-
callback=callbacks.validate_base_url,
|
|
490
|
-
envvar=BASE_URL_ENV_VAR,
|
|
491
|
-
)
|
|
492
|
-
@click.option(
|
|
493
|
-
"--app",
|
|
494
|
-
help="Specifies the WSGI/ASGI application under test, provided as an importable Python path.",
|
|
495
|
-
type=str,
|
|
496
|
-
callback=callbacks.validate_app,
|
|
497
|
-
)
|
|
498
|
-
@click.option(
|
|
499
|
-
"--wait-for-schema",
|
|
500
|
-
help="Maximum duration, in seconds, to wait for the API schema to become available.",
|
|
501
|
-
type=click.FloatRange(1.0),
|
|
502
|
-
default=None,
|
|
503
|
-
envvar=WAIT_FOR_SCHEMA_ENV_VAR,
|
|
504
|
-
)
|
|
505
|
-
@click.option(
|
|
506
|
-
"--request-timeout",
|
|
507
|
-
help="Sets a timeout limit, in milliseconds, for each network request during tests.",
|
|
508
|
-
type=click.IntRange(1),
|
|
509
|
-
default=DEFAULT_RESPONSE_TIMEOUT,
|
|
510
|
-
)
|
|
511
|
-
@with_request_proxy
|
|
512
|
-
@with_request_tls_verify
|
|
513
|
-
@with_request_cert
|
|
514
|
-
@with_request_cert_key
|
|
515
|
-
@click.option(
|
|
516
|
-
"--validate-schema",
|
|
517
|
-
help="Toggles validation of incoming payloads against the defined API schema. "
|
|
518
|
-
"Set to 'True' to enable or 'False' to disable. "
|
|
519
|
-
"Default is 'False'.",
|
|
520
|
-
type=bool,
|
|
521
|
-
default=False,
|
|
522
|
-
show_default=True,
|
|
523
|
-
cls=GroupedOption,
|
|
524
|
-
group=ParameterGroup.validation,
|
|
500
|
+
hidden=True,
|
|
525
501
|
)
|
|
526
|
-
@
|
|
502
|
+
@grouped_option(
|
|
527
503
|
"--skip-deprecated-operations",
|
|
528
|
-
help="Exclude deprecated API operations from testing
|
|
504
|
+
help="[DEPRECATED] Exclude deprecated API operations from testing",
|
|
529
505
|
is_flag=True,
|
|
530
506
|
is_eager=True,
|
|
531
507
|
default=False,
|
|
532
508
|
show_default=True,
|
|
533
|
-
|
|
534
|
-
group=ParameterGroup.filtering,
|
|
509
|
+
hidden=True,
|
|
535
510
|
)
|
|
536
|
-
@
|
|
511
|
+
@group("Output options")
|
|
512
|
+
@grouped_option(
|
|
537
513
|
"--junit-xml",
|
|
538
|
-
help="
|
|
514
|
+
help="Output a JUnit-XML style report at the specified file path",
|
|
539
515
|
type=click.File("w", encoding="utf-8"),
|
|
540
516
|
)
|
|
541
|
-
@
|
|
542
|
-
"--
|
|
543
|
-
"
|
|
544
|
-
help="""Specifies how the generated report should be handled.
|
|
545
|
-
If used without an argument, the report data will automatically be uploaded to Schemathesis.io.
|
|
546
|
-
If a file name is provided, the report will be stored in that file.
|
|
547
|
-
The report data, consisting of a tar gz file with multiple JSON files, is subject to change.""",
|
|
548
|
-
is_flag=False,
|
|
549
|
-
flag_value="",
|
|
550
|
-
envvar=service.REPORT_ENV_VAR,
|
|
551
|
-
callback=callbacks.convert_report, # type: ignore
|
|
552
|
-
)
|
|
553
|
-
@click.option(
|
|
554
|
-
"--debug-output-file",
|
|
555
|
-
help="Saves debugging information in a JSONL format at the specified file path.",
|
|
517
|
+
@grouped_option(
|
|
518
|
+
"--cassette-path",
|
|
519
|
+
help="Save the test outcomes in a VCR-compatible format",
|
|
556
520
|
type=click.File("w", encoding="utf-8"),
|
|
557
|
-
)
|
|
558
|
-
@click.option(
|
|
559
|
-
"--show-errors-tracebacks",
|
|
560
|
-
help="Displays complete traceback information for internal errors.",
|
|
561
|
-
is_flag=True,
|
|
562
521
|
is_eager=True,
|
|
563
|
-
default=False,
|
|
564
|
-
hidden=True,
|
|
565
|
-
show_default=True,
|
|
566
522
|
)
|
|
567
|
-
@
|
|
568
|
-
"--
|
|
569
|
-
help="
|
|
523
|
+
@grouped_option(
|
|
524
|
+
"--cassette-format",
|
|
525
|
+
help="Format of the saved cassettes",
|
|
526
|
+
type=click.Choice([item.name.lower() for item in cassettes.CassetteFormat]),
|
|
527
|
+
default=cassettes.CassetteFormat.VCR.name.lower(),
|
|
528
|
+
callback=callbacks.convert_cassette_format,
|
|
529
|
+
metavar="",
|
|
530
|
+
)
|
|
531
|
+
@grouped_option(
|
|
532
|
+
"--cassette-preserve-exact-body-bytes",
|
|
533
|
+
help="Retain exact byte sequence of payloads in cassettes, encoded as base64",
|
|
570
534
|
is_flag=True,
|
|
571
|
-
|
|
572
|
-
default=False,
|
|
573
|
-
show_default=True,
|
|
535
|
+
callback=callbacks.validate_preserve_exact_body_bytes,
|
|
574
536
|
)
|
|
575
|
-
@
|
|
537
|
+
@grouped_option(
|
|
576
538
|
"--code-sample-style",
|
|
577
|
-
help="
|
|
539
|
+
help="Code sample style for reproducing failures",
|
|
578
540
|
type=click.Choice([item.name for item in CodeSampleStyle]),
|
|
579
541
|
default=CodeSampleStyle.default().name,
|
|
580
542
|
callback=callbacks.convert_code_sample_style,
|
|
543
|
+
metavar="",
|
|
581
544
|
)
|
|
582
|
-
@
|
|
583
|
-
"--
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
545
|
+
@grouped_option(
|
|
546
|
+
"--sanitize-output",
|
|
547
|
+
type=bool,
|
|
548
|
+
default=True,
|
|
549
|
+
show_default=True,
|
|
550
|
+
help="Enable or disable automatic output sanitization to obscure sensitive data",
|
|
587
551
|
)
|
|
588
|
-
@
|
|
589
|
-
"--
|
|
590
|
-
help="
|
|
591
|
-
type=
|
|
592
|
-
default=
|
|
593
|
-
|
|
552
|
+
@grouped_option(
|
|
553
|
+
"--output-truncate",
|
|
554
|
+
help="Truncate schemas and responses in error messages",
|
|
555
|
+
type=str,
|
|
556
|
+
default="true",
|
|
557
|
+
show_default=True,
|
|
558
|
+
callback=callbacks.convert_boolean_string,
|
|
594
559
|
)
|
|
595
|
-
@
|
|
596
|
-
"--
|
|
597
|
-
help="
|
|
560
|
+
@grouped_option(
|
|
561
|
+
"--show-trace",
|
|
562
|
+
help="Display complete traceback information for internal errors",
|
|
598
563
|
is_flag=True,
|
|
599
|
-
|
|
564
|
+
is_eager=True,
|
|
565
|
+
default=False,
|
|
566
|
+
show_default=True,
|
|
600
567
|
)
|
|
601
|
-
@
|
|
568
|
+
@grouped_option(
|
|
569
|
+
"--debug-output-file",
|
|
570
|
+
help="Save debugging information in a JSONL format at the specified file path",
|
|
571
|
+
type=click.File("w", encoding="utf-8"),
|
|
572
|
+
)
|
|
573
|
+
@grouped_option(
|
|
602
574
|
"--store-network-log",
|
|
603
|
-
help="
|
|
575
|
+
help="[DEPRECATED] Save the test outcomes in a VCR-compatible format",
|
|
604
576
|
type=click.File("w", encoding="utf-8"),
|
|
605
577
|
hidden=True,
|
|
606
578
|
)
|
|
607
|
-
@
|
|
608
|
-
"--
|
|
609
|
-
help="
|
|
610
|
-
|
|
611
|
-
|
|
579
|
+
@grouped_option(
|
|
580
|
+
"--show-errors-tracebacks",
|
|
581
|
+
help="[DEPRECATED] Display complete traceback information for internal errors",
|
|
582
|
+
is_flag=True,
|
|
583
|
+
is_eager=True,
|
|
584
|
+
default=False,
|
|
585
|
+
hidden=True,
|
|
586
|
+
show_default=True,
|
|
612
587
|
)
|
|
613
|
-
@
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
"
|
|
617
|
-
|
|
618
|
-
|
|
588
|
+
@group("Data generation options")
|
|
589
|
+
@grouped_option(
|
|
590
|
+
"--data-generation-method",
|
|
591
|
+
"-D",
|
|
592
|
+
"data_generation_methods",
|
|
593
|
+
help="Specify the approach Schemathesis uses to generate test data. "
|
|
594
|
+
"Use 'positive' for valid data, 'negative' for invalid data, or 'all' for both",
|
|
595
|
+
type=DATA_GENERATION_METHOD_TYPE,
|
|
596
|
+
default=DataGenerationMethod.default().name,
|
|
597
|
+
callback=callbacks.convert_data_generation_method,
|
|
598
|
+
show_default=True,
|
|
599
|
+
metavar="",
|
|
619
600
|
)
|
|
620
|
-
@
|
|
601
|
+
@grouped_option(
|
|
621
602
|
"--stateful",
|
|
622
|
-
help="
|
|
603
|
+
help="Enable or disable stateful testing",
|
|
623
604
|
type=click.Choice([item.name for item in Stateful]),
|
|
624
605
|
default=Stateful.links.name,
|
|
625
606
|
callback=callbacks.convert_stateful,
|
|
607
|
+
metavar="",
|
|
626
608
|
)
|
|
627
|
-
@
|
|
609
|
+
@grouped_option(
|
|
628
610
|
"--stateful-recursion-limit",
|
|
629
|
-
help="
|
|
611
|
+
help="Recursion depth limit for stateful testing",
|
|
630
612
|
default=DEFAULT_STATEFUL_RECURSION_LIMIT,
|
|
631
613
|
show_default=True,
|
|
632
614
|
type=click.IntRange(1, 100),
|
|
633
615
|
hidden=True,
|
|
634
616
|
)
|
|
635
|
-
@
|
|
636
|
-
"--
|
|
637
|
-
help="
|
|
638
|
-
type=
|
|
617
|
+
@grouped_option(
|
|
618
|
+
"--generation-allow-x00",
|
|
619
|
+
help="Whether to allow the generation of `\x00` bytes within strings",
|
|
620
|
+
type=str,
|
|
621
|
+
default="true",
|
|
622
|
+
show_default=True,
|
|
623
|
+
callback=callbacks.convert_boolean_string,
|
|
639
624
|
)
|
|
640
|
-
@
|
|
641
|
-
"--
|
|
642
|
-
|
|
643
|
-
|
|
625
|
+
@grouped_option(
|
|
626
|
+
"--generation-codec",
|
|
627
|
+
help="The codec used for generating strings",
|
|
628
|
+
type=str,
|
|
629
|
+
default="utf-8",
|
|
630
|
+
callback=callbacks.validate_generation_codec,
|
|
631
|
+
)
|
|
632
|
+
@grouped_option(
|
|
633
|
+
"--generation-with-security-parameters",
|
|
634
|
+
help="Whether to generate security parameters",
|
|
635
|
+
type=str,
|
|
636
|
+
default="true",
|
|
644
637
|
show_default=True,
|
|
645
|
-
|
|
638
|
+
callback=callbacks.convert_boolean_string,
|
|
646
639
|
)
|
|
647
|
-
@
|
|
640
|
+
@grouped_option(
|
|
641
|
+
"--generation-graphql-allow-null",
|
|
642
|
+
help="Whether to use `null` values for optional arguments in GraphQL queries",
|
|
643
|
+
type=str,
|
|
644
|
+
default="true",
|
|
645
|
+
show_default=True,
|
|
646
|
+
callback=callbacks.convert_boolean_string,
|
|
647
|
+
)
|
|
648
|
+
@grouped_option(
|
|
648
649
|
"--contrib-unique-data",
|
|
649
650
|
"contrib_unique_data",
|
|
650
|
-
help="
|
|
651
|
+
help="Force the generation of unique test cases",
|
|
651
652
|
is_flag=True,
|
|
652
653
|
default=False,
|
|
653
654
|
show_default=True,
|
|
654
655
|
)
|
|
655
|
-
@
|
|
656
|
+
@grouped_option(
|
|
656
657
|
"--contrib-openapi-formats-uuid",
|
|
657
658
|
"contrib_openapi_formats_uuid",
|
|
658
|
-
help="
|
|
659
|
+
help="Enable support for the 'uuid' string format in OpenAPI",
|
|
659
660
|
is_flag=True,
|
|
660
661
|
default=False,
|
|
661
662
|
show_default=True,
|
|
662
663
|
)
|
|
663
|
-
@
|
|
664
|
+
@grouped_option(
|
|
664
665
|
"--contrib-openapi-fill-missing-examples",
|
|
665
666
|
"contrib_openapi_fill_missing_examples",
|
|
666
|
-
help="
|
|
667
|
+
help="Enable generation of random examples for API operations that do not have explicit examples",
|
|
667
668
|
is_flag=True,
|
|
668
669
|
default=False,
|
|
669
670
|
show_default=True,
|
|
670
671
|
)
|
|
671
|
-
@
|
|
672
|
+
@grouped_option(
|
|
673
|
+
"--target",
|
|
674
|
+
"-t",
|
|
675
|
+
"targets",
|
|
676
|
+
multiple=True,
|
|
677
|
+
help="Guide input generation to values more likely to expose bugs via targeted property-based testing",
|
|
678
|
+
type=TARGETS_TYPE,
|
|
679
|
+
default=DEFAULT_TARGETS_NAMES,
|
|
680
|
+
show_default=True,
|
|
681
|
+
metavar="",
|
|
682
|
+
)
|
|
683
|
+
@group("Open API options")
|
|
684
|
+
@grouped_option(
|
|
685
|
+
"--force-schema-version",
|
|
686
|
+
help="Force the schema to be interpreted as a particular OpenAPI version",
|
|
687
|
+
type=click.Choice(["20", "30"]),
|
|
688
|
+
metavar="",
|
|
689
|
+
)
|
|
690
|
+
@grouped_option(
|
|
691
|
+
"--set-query",
|
|
692
|
+
"set_query",
|
|
693
|
+
help=r"OpenAPI: Override a specific query parameter by specifying 'parameter=value'",
|
|
694
|
+
multiple=True,
|
|
695
|
+
type=str,
|
|
696
|
+
callback=callbacks.validate_set_query,
|
|
697
|
+
)
|
|
698
|
+
@grouped_option(
|
|
699
|
+
"--set-header",
|
|
700
|
+
"set_header",
|
|
701
|
+
help=r"OpenAPI: Override a specific header parameter by specifying 'parameter=value'",
|
|
702
|
+
multiple=True,
|
|
703
|
+
type=str,
|
|
704
|
+
callback=callbacks.validate_set_header,
|
|
705
|
+
)
|
|
706
|
+
@grouped_option(
|
|
707
|
+
"--set-cookie",
|
|
708
|
+
"set_cookie",
|
|
709
|
+
help=r"OpenAPI: Override a specific cookie parameter by specifying 'parameter=value'",
|
|
710
|
+
multiple=True,
|
|
711
|
+
type=str,
|
|
712
|
+
callback=callbacks.validate_set_cookie,
|
|
713
|
+
)
|
|
714
|
+
@grouped_option(
|
|
715
|
+
"--set-path",
|
|
716
|
+
"set_path",
|
|
717
|
+
help=r"OpenAPI: Override a specific path parameter by specifying 'parameter=value'",
|
|
718
|
+
multiple=True,
|
|
719
|
+
type=str,
|
|
720
|
+
callback=callbacks.validate_set_path,
|
|
721
|
+
)
|
|
722
|
+
@group("Hypothesis engine options")
|
|
723
|
+
@grouped_option(
|
|
672
724
|
"--hypothesis-database",
|
|
673
|
-
help="
|
|
725
|
+
help="Storage for examples discovered by Hypothesis. "
|
|
674
726
|
f"Use 'none' to disable, '{HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER}' for temporary storage, "
|
|
675
|
-
f"or specify a file path for persistent storage
|
|
727
|
+
f"or specify a file path for persistent storage",
|
|
676
728
|
type=str,
|
|
677
|
-
cls=GroupedOption,
|
|
678
|
-
group=ParameterGroup.hypothesis,
|
|
679
729
|
callback=callbacks.validate_hypothesis_database,
|
|
680
730
|
)
|
|
681
|
-
@
|
|
731
|
+
@grouped_option(
|
|
682
732
|
"--hypothesis-deadline",
|
|
683
|
-
help="
|
|
684
|
-
"Exceeding this limit will cause the test to fail
|
|
685
|
-
|
|
686
|
-
type=OptionalInt(1, 999999999 * 24 * 3600 * 1000),
|
|
687
|
-
cls=GroupedOption,
|
|
688
|
-
group=ParameterGroup.hypothesis,
|
|
733
|
+
help="Time limit for each test case generated by Hypothesis, in milliseconds. "
|
|
734
|
+
"Exceeding this limit will cause the test to fail",
|
|
735
|
+
type=OptionalInt(1, 5 * 60 * 1000),
|
|
689
736
|
)
|
|
690
|
-
@
|
|
737
|
+
@grouped_option(
|
|
691
738
|
"--hypothesis-derandomize",
|
|
692
|
-
help="Enables deterministic mode in Hypothesis, which eliminates random variation between
|
|
739
|
+
help="Enables deterministic mode in Hypothesis, which eliminates random variation between tests",
|
|
693
740
|
is_flag=True,
|
|
694
741
|
is_eager=True,
|
|
695
742
|
default=None,
|
|
696
743
|
show_default=True,
|
|
697
|
-
cls=GroupedOption,
|
|
698
|
-
group=ParameterGroup.hypothesis,
|
|
699
744
|
)
|
|
700
|
-
@
|
|
745
|
+
@grouped_option(
|
|
701
746
|
"--hypothesis-max-examples",
|
|
702
|
-
help="
|
|
747
|
+
help="The cap on the number of examples generated by Hypothesis for each API operation",
|
|
703
748
|
type=click.IntRange(1),
|
|
704
|
-
cls=GroupedOption,
|
|
705
|
-
group=ParameterGroup.hypothesis,
|
|
706
749
|
)
|
|
707
|
-
@
|
|
750
|
+
@grouped_option(
|
|
708
751
|
"--hypothesis-phases",
|
|
709
|
-
help="
|
|
752
|
+
help="Testing phases to execute",
|
|
710
753
|
type=CsvEnumChoice(Phase),
|
|
711
|
-
|
|
712
|
-
group=ParameterGroup.hypothesis,
|
|
754
|
+
metavar="",
|
|
713
755
|
)
|
|
714
|
-
@
|
|
756
|
+
@grouped_option(
|
|
715
757
|
"--hypothesis-no-phases",
|
|
716
|
-
help="
|
|
758
|
+
help="Testing phases to exclude from execution",
|
|
717
759
|
type=CsvEnumChoice(Phase),
|
|
718
|
-
|
|
719
|
-
group=ParameterGroup.hypothesis,
|
|
760
|
+
metavar="",
|
|
720
761
|
)
|
|
721
|
-
@
|
|
762
|
+
@grouped_option(
|
|
722
763
|
"--hypothesis-report-multiple-bugs",
|
|
723
|
-
help="
|
|
764
|
+
help="Report only the most easily reproducible error when multiple issues are found",
|
|
724
765
|
type=bool,
|
|
725
|
-
cls=GroupedOption,
|
|
726
|
-
group=ParameterGroup.hypothesis,
|
|
727
766
|
)
|
|
728
|
-
@
|
|
767
|
+
@grouped_option(
|
|
729
768
|
"--hypothesis-seed",
|
|
730
|
-
help="
|
|
769
|
+
help="Seed value for Hypothesis, ensuring reproducibility across test runs",
|
|
731
770
|
type=int,
|
|
732
|
-
cls=GroupedOption,
|
|
733
|
-
group=ParameterGroup.hypothesis,
|
|
734
771
|
)
|
|
735
|
-
@
|
|
772
|
+
@grouped_option(
|
|
736
773
|
"--hypothesis-suppress-health-check",
|
|
737
|
-
help="
|
|
738
|
-
"Provide a comma-separated list",
|
|
774
|
+
help="A comma-separated list of Hypothesis health checks to disable",
|
|
739
775
|
type=CsvEnumChoice(HealthCheck),
|
|
740
|
-
|
|
741
|
-
group=ParameterGroup.hypothesis,
|
|
776
|
+
metavar="",
|
|
742
777
|
)
|
|
743
|
-
@
|
|
778
|
+
@grouped_option(
|
|
744
779
|
"--hypothesis-verbosity",
|
|
745
|
-
help="
|
|
780
|
+
help="Verbosity level of Hypothesis output",
|
|
746
781
|
type=click.Choice([item.name for item in Verbosity]),
|
|
747
782
|
callback=callbacks.convert_verbosity,
|
|
748
|
-
|
|
749
|
-
group=ParameterGroup.hypothesis,
|
|
783
|
+
metavar="",
|
|
750
784
|
)
|
|
751
|
-
@
|
|
752
|
-
@
|
|
753
|
-
|
|
754
|
-
"
|
|
755
|
-
"
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
experimental.COVERAGE_PHASE.name,
|
|
764
|
-
]
|
|
765
|
-
),
|
|
766
|
-
callback=callbacks.convert_experimental,
|
|
767
|
-
multiple=True,
|
|
768
|
-
)
|
|
769
|
-
@click.option(
|
|
770
|
-
"--output-truncate",
|
|
771
|
-
help="Specifies whether to truncate schemas and responses in error messages.",
|
|
772
|
-
type=str,
|
|
773
|
-
default="true",
|
|
774
|
-
show_default=True,
|
|
775
|
-
callback=callbacks.convert_boolean_string,
|
|
776
|
-
)
|
|
777
|
-
@click.option(
|
|
778
|
-
"--generation-allow-x00",
|
|
779
|
-
help="Determines whether to allow the generation of `\x00` bytes within strings.",
|
|
780
|
-
type=str,
|
|
781
|
-
default="true",
|
|
782
|
-
show_default=True,
|
|
783
|
-
callback=callbacks.convert_boolean_string,
|
|
784
|
-
)
|
|
785
|
-
@click.option(
|
|
786
|
-
"--generation-codec",
|
|
787
|
-
help="Specifies the codec used for generating strings.",
|
|
788
|
-
type=str,
|
|
789
|
-
default="utf-8",
|
|
790
|
-
callback=callbacks.validate_generation_codec,
|
|
791
|
-
)
|
|
792
|
-
@click.option(
|
|
793
|
-
"--generation-with-security-parameters",
|
|
794
|
-
help="Whether to generate security parameters.",
|
|
795
|
-
type=str,
|
|
796
|
-
default="true",
|
|
797
|
-
show_default=True,
|
|
798
|
-
callback=callbacks.convert_boolean_string,
|
|
799
|
-
)
|
|
800
|
-
@click.option(
|
|
801
|
-
"--generation-graphql-allow-null",
|
|
802
|
-
help="Whether `null` values should be used for optional arguments in GraphQL queries.",
|
|
803
|
-
type=str,
|
|
804
|
-
default="true",
|
|
805
|
-
show_default=True,
|
|
806
|
-
callback=callbacks.convert_boolean_string,
|
|
785
|
+
@group("Schemathesis.io options")
|
|
786
|
+
@grouped_option(
|
|
787
|
+
"--report",
|
|
788
|
+
"report_value",
|
|
789
|
+
help="""Specify how the generated report should be handled.
|
|
790
|
+
If used without an argument, the report data will automatically be uploaded to Schemathesis.io.
|
|
791
|
+
If a file name is provided, the report will be stored in that file.
|
|
792
|
+
The report data, consisting of a tar gz file with multiple JSON files, is subject to change""",
|
|
793
|
+
is_flag=False,
|
|
794
|
+
flag_value="",
|
|
795
|
+
envvar=service.REPORT_ENV_VAR,
|
|
796
|
+
callback=callbacks.convert_report, # type: ignore
|
|
807
797
|
)
|
|
808
|
-
@
|
|
798
|
+
@grouped_option(
|
|
809
799
|
"--schemathesis-io-token",
|
|
810
|
-
help="Schemathesis.io authentication token
|
|
800
|
+
help="Schemathesis.io authentication token",
|
|
811
801
|
type=str,
|
|
812
802
|
envvar=service.TOKEN_ENV_VAR,
|
|
813
803
|
)
|
|
814
|
-
@
|
|
804
|
+
@grouped_option(
|
|
815
805
|
"--schemathesis-io-url",
|
|
816
|
-
help="Schemathesis.io base URL
|
|
806
|
+
help="Schemathesis.io base URL",
|
|
817
807
|
default=service.DEFAULT_URL,
|
|
818
808
|
type=str,
|
|
819
809
|
envvar=service.URL_ENV_VAR,
|
|
820
810
|
)
|
|
821
|
-
@
|
|
811
|
+
@grouped_option(
|
|
822
812
|
"--schemathesis-io-telemetry",
|
|
823
|
-
help="
|
|
813
|
+
help="Whether to send anonymized usage data to Schemathesis.io along with your report",
|
|
824
814
|
type=str,
|
|
825
815
|
default="true",
|
|
826
816
|
show_default=True,
|
|
@@ -828,7 +818,10 @@ The report data, consisting of a tar gz file with multiple JSON files, is subjec
|
|
|
828
818
|
envvar=service.TELEMETRY_ENV_VAR,
|
|
829
819
|
)
|
|
830
820
|
@with_hosts_file
|
|
831
|
-
@
|
|
821
|
+
@group("Global options")
|
|
822
|
+
@grouped_option("--verbosity", "-v", help="Increase verbosity of the output", count=True)
|
|
823
|
+
@grouped_option("--no-color", help="Disable ANSI color escape codes", type=bool, is_flag=True)
|
|
824
|
+
@grouped_option("--force-color", help="Explicitly tells to enable ANSI color escape codes", type=bool, is_flag=True)
|
|
832
825
|
@click.pass_context
|
|
833
826
|
def run(
|
|
834
827
|
ctx: click.Context,
|
|
@@ -933,9 +926,9 @@ def run(
|
|
|
933
926
|
) -> None:
|
|
934
927
|
"""Run tests against an API using a specified SCHEMA.
|
|
935
928
|
|
|
936
|
-
[Required] SCHEMA: Path to an OpenAPI (`.json`, `.yml`) or GraphQL SDL file, or a URL pointing to such specifications
|
|
929
|
+
[Required] SCHEMA: Path to an OpenAPI (`.json`, `.yml`) or GraphQL SDL file, or a URL pointing to such specifications
|
|
937
930
|
|
|
938
|
-
[Optional] API_NAME: Identifier for uploading test data to Schemathesis.io
|
|
931
|
+
[Optional] API_NAME: Identifier for uploading test data to Schemathesis.io
|
|
939
932
|
"""
|
|
940
933
|
_hypothesis_phases: list[hypothesis.Phase] | None = None
|
|
941
934
|
if hypothesis_phases is not None:
|
|
@@ -1020,7 +1013,7 @@ def run(
|
|
|
1020
1013
|
replacement = deprecated_filters[arg_name]
|
|
1021
1014
|
click.secho(
|
|
1022
1015
|
f"Warning: Option `{arg_name}` is deprecated and will be removed in Schemathesis 4.0. "
|
|
1023
|
-
f"Use `{replacement}` instead
|
|
1016
|
+
f"Use `{replacement}` instead",
|
|
1024
1017
|
fg="yellow",
|
|
1025
1018
|
)
|
|
1026
1019
|
_ensure_unique_filter(values, arg_name)
|
|
@@ -1805,13 +1798,13 @@ def get_exit_code(event: events.ExecutionEvent) -> int:
|
|
|
1805
1798
|
|
|
1806
1799
|
@schemathesis.command(short_help="Replay requests from a saved cassette.")
|
|
1807
1800
|
@click.argument("cassette_path", type=click.Path(exists=True))
|
|
1808
|
-
@click.option("--id", "id_", help="ID of interaction to replay
|
|
1809
|
-
@click.option("--status", help="Status of interactions to replay
|
|
1810
|
-
@click.option("--uri", help="A regexp that filters interactions by their request URI
|
|
1811
|
-
@click.option("--method", help="A regexp that filters interactions by their request method
|
|
1812
|
-
@click.option("--no-color", help="Disable ANSI color escape codes
|
|
1813
|
-
@click.option("--force-color", help="Explicitly tells to enable ANSI color escape codes
|
|
1814
|
-
@click.option("--verbosity", "-v", help="Increase verbosity of the output
|
|
1801
|
+
@click.option("--id", "id_", help="ID of interaction to replay", type=str)
|
|
1802
|
+
@click.option("--status", help="Status of interactions to replay", type=str)
|
|
1803
|
+
@click.option("--uri", help="A regexp that filters interactions by their request URI", type=str)
|
|
1804
|
+
@click.option("--method", help="A regexp that filters interactions by their request method", type=str)
|
|
1805
|
+
@click.option("--no-color", help="Disable ANSI color escape codes", type=bool, is_flag=True)
|
|
1806
|
+
@click.option("--force-color", help="Explicitly tells to enable ANSI color escape codes", type=bool, is_flag=True)
|
|
1807
|
+
@click.option("--verbosity", "-v", help="Increase verbosity of the output", count=True)
|
|
1815
1808
|
@with_request_tls_verify
|
|
1816
1809
|
@with_request_proxy
|
|
1817
1810
|
@with_request_cert
|
|
@@ -1879,13 +1872,13 @@ def replay(
|
|
|
1879
1872
|
@click.argument("report", type=click.File(mode="rb"))
|
|
1880
1873
|
@click.option(
|
|
1881
1874
|
"--schemathesis-io-token",
|
|
1882
|
-
help="Schemathesis.io authentication token
|
|
1875
|
+
help="Schemathesis.io authentication token",
|
|
1883
1876
|
type=str,
|
|
1884
1877
|
envvar=service.TOKEN_ENV_VAR,
|
|
1885
1878
|
)
|
|
1886
1879
|
@click.option(
|
|
1887
1880
|
"--schemathesis-io-url",
|
|
1888
|
-
help="Schemathesis.io base URL
|
|
1881
|
+
help="Schemathesis.io base URL",
|
|
1889
1882
|
default=service.DEFAULT_URL,
|
|
1890
1883
|
type=str,
|
|
1891
1884
|
envvar=service.URL_ENV_VAR,
|
|
@@ -2012,6 +2005,25 @@ def add_option(*args: Any, cls: Type = click.Option, **kwargs: Any) -> None:
|
|
|
2012
2005
|
run.params.append(cls(args, **kwargs))
|
|
2013
2006
|
|
|
2014
2007
|
|
|
2008
|
+
@dataclass
|
|
2009
|
+
class Group:
|
|
2010
|
+
name: str
|
|
2011
|
+
|
|
2012
|
+
def add_option(self, *args: Any, **kwargs: Any) -> None:
|
|
2013
|
+
kwargs["cls"] = GroupedOption
|
|
2014
|
+
kwargs["group"] = self.name
|
|
2015
|
+
add_option(*args, **kwargs)
|
|
2016
|
+
|
|
2017
|
+
|
|
2018
|
+
def add_group(name: str, *, index: int | None = None) -> Group:
|
|
2019
|
+
"""Add a custom options group to `st run`."""
|
|
2020
|
+
if index is not None:
|
|
2021
|
+
GROUPS.insert(index, name)
|
|
2022
|
+
else:
|
|
2023
|
+
GROUPS.append(name)
|
|
2024
|
+
return Group(name)
|
|
2025
|
+
|
|
2026
|
+
|
|
2015
2027
|
def handler() -> Callable[[Type], None]:
|
|
2016
2028
|
"""Register a new CLI event handler."""
|
|
2017
2029
|
|