schemathesis 3.25.5__py3-none-any.whl → 4.0.0a1__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 +27 -65
- schemathesis/auths.py +102 -82
- schemathesis/checks.py +126 -46
- schemathesis/cli/__init__.py +11 -1766
- schemathesis/cli/__main__.py +4 -0
- schemathesis/cli/commands/__init__.py +37 -0
- schemathesis/cli/commands/run/__init__.py +662 -0
- schemathesis/cli/commands/run/checks.py +80 -0
- schemathesis/cli/commands/run/context.py +117 -0
- schemathesis/cli/commands/run/events.py +35 -0
- schemathesis/cli/commands/run/executor.py +138 -0
- schemathesis/cli/commands/run/filters.py +194 -0
- schemathesis/cli/commands/run/handlers/__init__.py +46 -0
- schemathesis/cli/commands/run/handlers/base.py +18 -0
- schemathesis/cli/commands/run/handlers/cassettes.py +494 -0
- schemathesis/cli/commands/run/handlers/junitxml.py +54 -0
- schemathesis/cli/commands/run/handlers/output.py +746 -0
- schemathesis/cli/commands/run/hypothesis.py +105 -0
- schemathesis/cli/commands/run/loaders.py +129 -0
- schemathesis/cli/{callbacks.py → commands/run/validation.py} +103 -174
- schemathesis/cli/constants.py +5 -52
- schemathesis/cli/core.py +17 -0
- schemathesis/cli/ext/fs.py +14 -0
- schemathesis/cli/ext/groups.py +55 -0
- schemathesis/cli/{options.py → ext/options.py} +39 -10
- schemathesis/cli/hooks.py +36 -0
- schemathesis/contrib/__init__.py +1 -3
- schemathesis/contrib/openapi/__init__.py +1 -3
- schemathesis/contrib/openapi/fill_missing_examples.py +3 -5
- schemathesis/core/__init__.py +58 -0
- schemathesis/core/compat.py +25 -0
- schemathesis/core/control.py +2 -0
- schemathesis/core/curl.py +58 -0
- schemathesis/core/deserialization.py +65 -0
- schemathesis/core/errors.py +370 -0
- schemathesis/core/failures.py +285 -0
- schemathesis/core/fs.py +19 -0
- schemathesis/{_lazy_import.py → core/lazy_import.py} +1 -0
- schemathesis/core/loaders.py +104 -0
- schemathesis/core/marks.py +66 -0
- schemathesis/{transports/content_types.py → core/media_types.py} +17 -13
- schemathesis/core/output/__init__.py +69 -0
- schemathesis/core/output/sanitization.py +197 -0
- schemathesis/core/rate_limit.py +60 -0
- schemathesis/core/registries.py +31 -0
- schemathesis/{internal → core}/result.py +1 -1
- schemathesis/core/transforms.py +113 -0
- schemathesis/core/transport.py +108 -0
- schemathesis/core/validation.py +38 -0
- schemathesis/core/version.py +7 -0
- schemathesis/engine/__init__.py +30 -0
- schemathesis/engine/config.py +59 -0
- schemathesis/engine/context.py +119 -0
- schemathesis/engine/control.py +36 -0
- schemathesis/engine/core.py +157 -0
- schemathesis/engine/errors.py +394 -0
- schemathesis/engine/events.py +337 -0
- schemathesis/engine/phases/__init__.py +66 -0
- schemathesis/{cli → engine/phases}/probes.py +63 -70
- schemathesis/engine/phases/stateful/__init__.py +65 -0
- schemathesis/engine/phases/stateful/_executor.py +326 -0
- schemathesis/engine/phases/stateful/context.py +85 -0
- schemathesis/engine/phases/unit/__init__.py +174 -0
- schemathesis/engine/phases/unit/_executor.py +321 -0
- schemathesis/engine/phases/unit/_pool.py +74 -0
- schemathesis/engine/recorder.py +241 -0
- schemathesis/errors.py +31 -0
- schemathesis/experimental/__init__.py +18 -14
- schemathesis/filters.py +103 -14
- schemathesis/generation/__init__.py +21 -37
- schemathesis/generation/case.py +190 -0
- schemathesis/generation/coverage.py +931 -0
- schemathesis/generation/hypothesis/__init__.py +30 -0
- schemathesis/generation/hypothesis/builder.py +585 -0
- schemathesis/generation/hypothesis/examples.py +50 -0
- schemathesis/generation/hypothesis/given.py +66 -0
- schemathesis/generation/hypothesis/reporting.py +14 -0
- schemathesis/generation/hypothesis/strategies.py +16 -0
- schemathesis/generation/meta.py +115 -0
- schemathesis/generation/modes.py +28 -0
- schemathesis/generation/overrides.py +96 -0
- schemathesis/generation/stateful/__init__.py +20 -0
- schemathesis/{stateful → generation/stateful}/state_machine.py +68 -81
- schemathesis/generation/targets.py +69 -0
- schemathesis/graphql/__init__.py +15 -0
- schemathesis/graphql/checks.py +115 -0
- schemathesis/graphql/loaders.py +131 -0
- schemathesis/hooks.py +99 -67
- schemathesis/openapi/__init__.py +13 -0
- schemathesis/openapi/checks.py +412 -0
- schemathesis/openapi/generation/__init__.py +0 -0
- schemathesis/openapi/generation/filters.py +63 -0
- schemathesis/openapi/loaders.py +178 -0
- schemathesis/pytest/__init__.py +5 -0
- schemathesis/pytest/control_flow.py +7 -0
- schemathesis/pytest/lazy.py +273 -0
- schemathesis/pytest/loaders.py +12 -0
- schemathesis/{extra/pytest_plugin.py → pytest/plugin.py} +106 -127
- schemathesis/python/__init__.py +0 -0
- schemathesis/python/asgi.py +12 -0
- schemathesis/python/wsgi.py +12 -0
- schemathesis/schemas.py +537 -261
- schemathesis/specs/graphql/__init__.py +0 -1
- schemathesis/specs/graphql/_cache.py +25 -0
- schemathesis/specs/graphql/nodes.py +1 -0
- schemathesis/specs/graphql/scalars.py +7 -5
- schemathesis/specs/graphql/schemas.py +215 -187
- schemathesis/specs/graphql/validation.py +11 -18
- schemathesis/specs/openapi/__init__.py +7 -1
- schemathesis/specs/openapi/_cache.py +122 -0
- schemathesis/specs/openapi/_hypothesis.py +146 -165
- schemathesis/specs/openapi/checks.py +565 -67
- schemathesis/specs/openapi/converter.py +33 -6
- schemathesis/specs/openapi/definitions.py +11 -18
- schemathesis/specs/openapi/examples.py +153 -39
- schemathesis/specs/openapi/expressions/__init__.py +37 -2
- schemathesis/specs/openapi/expressions/context.py +4 -6
- schemathesis/specs/openapi/expressions/extractors.py +23 -0
- schemathesis/specs/openapi/expressions/lexer.py +20 -18
- schemathesis/specs/openapi/expressions/nodes.py +38 -14
- schemathesis/specs/openapi/expressions/parser.py +26 -5
- schemathesis/specs/openapi/formats.py +45 -0
- schemathesis/specs/openapi/links.py +65 -165
- schemathesis/specs/openapi/media_types.py +32 -0
- schemathesis/specs/openapi/negative/__init__.py +7 -3
- schemathesis/specs/openapi/negative/mutations.py +24 -8
- schemathesis/specs/openapi/parameters.py +46 -30
- schemathesis/specs/openapi/patterns.py +137 -0
- schemathesis/specs/openapi/references.py +47 -57
- schemathesis/specs/openapi/schemas.py +483 -367
- schemathesis/specs/openapi/security.py +25 -7
- schemathesis/specs/openapi/serialization.py +11 -6
- schemathesis/specs/openapi/stateful/__init__.py +185 -73
- schemathesis/specs/openapi/utils.py +6 -1
- schemathesis/transport/__init__.py +104 -0
- schemathesis/transport/asgi.py +26 -0
- schemathesis/transport/prepare.py +99 -0
- schemathesis/transport/requests.py +221 -0
- schemathesis/{_xml.py → transport/serialization.py} +143 -28
- schemathesis/transport/wsgi.py +165 -0
- schemathesis-4.0.0a1.dist-info/METADATA +297 -0
- schemathesis-4.0.0a1.dist-info/RECORD +152 -0
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/WHEEL +1 -1
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/entry_points.txt +1 -1
- schemathesis/_compat.py +0 -74
- schemathesis/_dependency_versions.py +0 -17
- schemathesis/_hypothesis.py +0 -246
- schemathesis/_override.py +0 -49
- schemathesis/cli/cassettes.py +0 -375
- schemathesis/cli/context.py +0 -55
- schemathesis/cli/debug.py +0 -26
- schemathesis/cli/handlers.py +0 -16
- schemathesis/cli/junitxml.py +0 -43
- schemathesis/cli/output/__init__.py +0 -1
- schemathesis/cli/output/default.py +0 -765
- schemathesis/cli/output/short.py +0 -40
- schemathesis/cli/sanitization.py +0 -20
- schemathesis/code_samples.py +0 -149
- schemathesis/constants.py +0 -55
- schemathesis/contrib/openapi/formats/__init__.py +0 -9
- schemathesis/contrib/openapi/formats/uuid.py +0 -15
- schemathesis/contrib/unique_data.py +0 -41
- schemathesis/exceptions.py +0 -560
- schemathesis/extra/_aiohttp.py +0 -27
- schemathesis/extra/_flask.py +0 -10
- schemathesis/extra/_server.py +0 -17
- schemathesis/failures.py +0 -209
- schemathesis/fixups/__init__.py +0 -36
- schemathesis/fixups/fast_api.py +0 -41
- schemathesis/fixups/utf8_bom.py +0 -29
- schemathesis/graphql.py +0 -4
- schemathesis/internal/__init__.py +0 -7
- schemathesis/internal/copy.py +0 -13
- schemathesis/internal/datetime.py +0 -5
- schemathesis/internal/deprecation.py +0 -34
- schemathesis/internal/jsonschema.py +0 -35
- schemathesis/internal/transformation.py +0 -15
- schemathesis/internal/validation.py +0 -34
- schemathesis/lazy.py +0 -361
- schemathesis/loaders.py +0 -120
- schemathesis/models.py +0 -1231
- schemathesis/parameters.py +0 -86
- schemathesis/runner/__init__.py +0 -555
- schemathesis/runner/events.py +0 -309
- schemathesis/runner/impl/__init__.py +0 -3
- schemathesis/runner/impl/core.py +0 -986
- schemathesis/runner/impl/solo.py +0 -90
- schemathesis/runner/impl/threadpool.py +0 -400
- schemathesis/runner/serialization.py +0 -411
- schemathesis/sanitization.py +0 -248
- schemathesis/serializers.py +0 -315
- schemathesis/service/__init__.py +0 -18
- schemathesis/service/auth.py +0 -11
- schemathesis/service/ci.py +0 -201
- schemathesis/service/client.py +0 -100
- schemathesis/service/constants.py +0 -38
- schemathesis/service/events.py +0 -57
- schemathesis/service/hosts.py +0 -107
- schemathesis/service/metadata.py +0 -46
- schemathesis/service/models.py +0 -49
- schemathesis/service/report.py +0 -255
- schemathesis/service/serialization.py +0 -184
- schemathesis/service/usage.py +0 -65
- schemathesis/specs/graphql/loaders.py +0 -344
- schemathesis/specs/openapi/filters.py +0 -49
- schemathesis/specs/openapi/loaders.py +0 -667
- schemathesis/specs/openapi/stateful/links.py +0 -92
- schemathesis/specs/openapi/validation.py +0 -25
- schemathesis/stateful/__init__.py +0 -133
- schemathesis/targets.py +0 -45
- schemathesis/throttling.py +0 -41
- schemathesis/transports/__init__.py +0 -5
- schemathesis/transports/auth.py +0 -15
- schemathesis/transports/headers.py +0 -35
- schemathesis/transports/responses.py +0 -52
- schemathesis/types.py +0 -35
- schemathesis/utils.py +0 -169
- schemathesis-3.25.5.dist-info/METADATA +0 -356
- schemathesis-3.25.5.dist-info/RECORD +0 -134
- /schemathesis/{extra → cli/ext}/__init__.py +0 -0
- {schemathesis-3.25.5.dist-info → schemathesis-4.0.0a1.dist-info}/licenses/LICENSE +0 -0
schemathesis/parameters.py
DELETED
@@ -1,86 +0,0 @@
|
|
1
|
-
"""API operation parameters.
|
2
|
-
|
3
|
-
These are basic entities that describe what data could be sent to the API.
|
4
|
-
"""
|
5
|
-
from __future__ import annotations
|
6
|
-
from dataclasses import dataclass, field
|
7
|
-
from typing import TYPE_CHECKING, Any, Generator, Generic, TypeVar
|
8
|
-
|
9
|
-
if TYPE_CHECKING:
|
10
|
-
from .models import APIOperation
|
11
|
-
|
12
|
-
|
13
|
-
@dataclass(eq=False)
|
14
|
-
class Parameter:
|
15
|
-
"""A logically separate parameter bound to a location (e.g., to "query string").
|
16
|
-
|
17
|
-
For example, if the API requires multiple headers to be present, each header is presented as a separate
|
18
|
-
`Parameter` instance.
|
19
|
-
"""
|
20
|
-
|
21
|
-
# The parameter definition in the language acceptable by the API
|
22
|
-
definition: Any
|
23
|
-
|
24
|
-
@property
|
25
|
-
def location(self) -> str:
|
26
|
-
"""Where this parameter is located.
|
27
|
-
|
28
|
-
E.g. "query" or "body"
|
29
|
-
"""
|
30
|
-
raise NotImplementedError
|
31
|
-
|
32
|
-
@property
|
33
|
-
def name(self) -> str:
|
34
|
-
"""Parameter name."""
|
35
|
-
raise NotImplementedError
|
36
|
-
|
37
|
-
@property
|
38
|
-
def is_required(self) -> bool:
|
39
|
-
"""Whether the parameter is required for a successful API call."""
|
40
|
-
raise NotImplementedError
|
41
|
-
|
42
|
-
def serialize(self, operation: APIOperation) -> str:
|
43
|
-
"""Get parameter's string representation."""
|
44
|
-
raise NotImplementedError
|
45
|
-
|
46
|
-
|
47
|
-
P = TypeVar("P", bound=Parameter)
|
48
|
-
|
49
|
-
|
50
|
-
@dataclass
|
51
|
-
class ParameterSet(Generic[P]):
|
52
|
-
"""A set of parameters for the same location."""
|
53
|
-
|
54
|
-
items: list[P] = field(default_factory=list)
|
55
|
-
|
56
|
-
def add(self, parameter: P) -> None:
|
57
|
-
"""Add a new parameter."""
|
58
|
-
self.items.append(parameter)
|
59
|
-
|
60
|
-
def get(self, name: str) -> P | None:
|
61
|
-
for parameter in self:
|
62
|
-
if parameter.name == name:
|
63
|
-
return parameter
|
64
|
-
return None
|
65
|
-
|
66
|
-
def contains(self, name: str) -> bool:
|
67
|
-
return self.get(name) is not None
|
68
|
-
|
69
|
-
def __contains__(self, item: str) -> bool:
|
70
|
-
return self.contains(item)
|
71
|
-
|
72
|
-
def __bool__(self) -> bool:
|
73
|
-
return bool(self.items)
|
74
|
-
|
75
|
-
def __iter__(self) -> Generator[P, None, None]:
|
76
|
-
yield from iter(self.items)
|
77
|
-
|
78
|
-
def __len__(self) -> int:
|
79
|
-
return len(self.items)
|
80
|
-
|
81
|
-
def __getitem__(self, item: int) -> P:
|
82
|
-
return self.items[item]
|
83
|
-
|
84
|
-
|
85
|
-
class PayloadAlternatives(ParameterSet[P]):
|
86
|
-
"""A set of alternative payloads."""
|
schemathesis/runner/__init__.py
DELETED
@@ -1,555 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from random import Random
|
4
|
-
from typing import Any, Callable, Generator, Iterable, TYPE_CHECKING
|
5
|
-
from urllib.parse import urlparse
|
6
|
-
|
7
|
-
from .._override import CaseOverride
|
8
|
-
from ..generation import DEFAULT_DATA_GENERATION_METHODS, DataGenerationMethod, GenerationConfig
|
9
|
-
from ..constants import (
|
10
|
-
DEFAULT_DEADLINE,
|
11
|
-
DEFAULT_STATEFUL_RECURSION_LIMIT,
|
12
|
-
HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER,
|
13
|
-
)
|
14
|
-
from ..internal.deprecation import deprecated_function
|
15
|
-
from ..internal.datetime import current_datetime
|
16
|
-
from ..internal.validation import file_exists
|
17
|
-
from ..transports.auth import get_requests_auth
|
18
|
-
from ..exceptions import SchemaError
|
19
|
-
from ..loaders import load_app
|
20
|
-
from ..specs.graphql import loaders as gql_loaders
|
21
|
-
from ..specs.openapi import loaders as oas_loaders
|
22
|
-
from ..targets import DEFAULT_TARGETS, Target
|
23
|
-
from ..types import Filter, NotSet, RawAuth, RequestCert
|
24
|
-
|
25
|
-
if TYPE_CHECKING:
|
26
|
-
from . import events
|
27
|
-
from ..models import CheckFunction
|
28
|
-
from ..schemas import BaseSchema
|
29
|
-
from .impl import BaseRunner
|
30
|
-
from ..stateful import Stateful
|
31
|
-
import hypothesis
|
32
|
-
|
33
|
-
|
34
|
-
@deprecated_function(removed_in="4.0", replacement="schemathesis.runner.from_schema")
|
35
|
-
def prepare(
|
36
|
-
schema_uri: str | dict[str, Any],
|
37
|
-
*,
|
38
|
-
# Runtime behavior
|
39
|
-
checks: Iterable[CheckFunction] | None = None,
|
40
|
-
data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
|
41
|
-
max_response_time: int | None = None,
|
42
|
-
targets: Iterable[Target] = DEFAULT_TARGETS,
|
43
|
-
workers_num: int = 1,
|
44
|
-
seed: int | None = None,
|
45
|
-
exit_first: bool = False,
|
46
|
-
dry_run: bool = False,
|
47
|
-
store_interactions: bool = False,
|
48
|
-
stateful: Stateful | None = None,
|
49
|
-
stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
|
50
|
-
# Schema loading
|
51
|
-
loader: Callable = oas_loaders.from_uri,
|
52
|
-
base_url: str | None = None,
|
53
|
-
auth: tuple[str, str] | None = None,
|
54
|
-
auth_type: str | None = None,
|
55
|
-
override: CaseOverride | None = None,
|
56
|
-
headers: dict[str, str] | None = None,
|
57
|
-
request_timeout: int | None = None,
|
58
|
-
request_tls_verify: bool | str = True,
|
59
|
-
request_cert: RequestCert | None = None,
|
60
|
-
endpoint: Filter | None = None,
|
61
|
-
method: Filter | None = None,
|
62
|
-
tag: Filter | None = None,
|
63
|
-
operation_id: Filter | None = None,
|
64
|
-
app: str | None = None,
|
65
|
-
validate_schema: bool = True,
|
66
|
-
skip_deprecated_operations: bool = False,
|
67
|
-
force_schema_version: str | None = None,
|
68
|
-
count_operations: bool = True,
|
69
|
-
count_links: bool = True,
|
70
|
-
# Hypothesis-specific configuration
|
71
|
-
hypothesis_deadline: int | NotSet | None = None,
|
72
|
-
hypothesis_derandomize: bool | None = None,
|
73
|
-
hypothesis_max_examples: int | None = None,
|
74
|
-
hypothesis_phases: list[hypothesis.Phase] | None = None,
|
75
|
-
hypothesis_report_multiple_bugs: bool | None = None,
|
76
|
-
hypothesis_suppress_health_check: list[hypothesis.HealthCheck] | None = None,
|
77
|
-
hypothesis_verbosity: hypothesis.Verbosity | None = None,
|
78
|
-
) -> Generator[events.ExecutionEvent, None, None]:
|
79
|
-
"""Prepare a generator that will run test cases against the given API definition."""
|
80
|
-
from ..checks import DEFAULT_CHECKS
|
81
|
-
|
82
|
-
checks = checks or DEFAULT_CHECKS
|
83
|
-
|
84
|
-
validate_loader(loader, schema_uri)
|
85
|
-
|
86
|
-
if auth is None:
|
87
|
-
# Auth type doesn't matter if auth is not passed
|
88
|
-
auth_type = None # type: ignore
|
89
|
-
hypothesis_settings = prepare_hypothesis_settings(
|
90
|
-
deadline=hypothesis_deadline,
|
91
|
-
derandomize=hypothesis_derandomize,
|
92
|
-
max_examples=hypothesis_max_examples,
|
93
|
-
phases=hypothesis_phases,
|
94
|
-
report_multiple_bugs=hypothesis_report_multiple_bugs,
|
95
|
-
suppress_health_check=hypothesis_suppress_health_check,
|
96
|
-
verbosity=hypothesis_verbosity,
|
97
|
-
)
|
98
|
-
return execute_from_schema(
|
99
|
-
schema_uri=schema_uri,
|
100
|
-
loader=loader,
|
101
|
-
base_url=base_url,
|
102
|
-
endpoint=endpoint,
|
103
|
-
method=method,
|
104
|
-
tag=tag,
|
105
|
-
operation_id=operation_id,
|
106
|
-
app=app,
|
107
|
-
validate_schema=validate_schema,
|
108
|
-
skip_deprecated_operations=skip_deprecated_operations,
|
109
|
-
force_schema_version=force_schema_version,
|
110
|
-
checks=checks,
|
111
|
-
data_generation_methods=data_generation_methods,
|
112
|
-
max_response_time=max_response_time,
|
113
|
-
targets=targets,
|
114
|
-
hypothesis_settings=hypothesis_settings,
|
115
|
-
seed=seed,
|
116
|
-
workers_num=workers_num,
|
117
|
-
exit_first=exit_first,
|
118
|
-
dry_run=dry_run,
|
119
|
-
auth=auth,
|
120
|
-
auth_type=auth_type,
|
121
|
-
override=override,
|
122
|
-
headers=headers,
|
123
|
-
request_timeout=request_timeout,
|
124
|
-
request_tls_verify=request_tls_verify,
|
125
|
-
request_cert=request_cert,
|
126
|
-
store_interactions=store_interactions,
|
127
|
-
stateful=stateful,
|
128
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
129
|
-
count_operations=count_operations,
|
130
|
-
count_links=count_links,
|
131
|
-
)
|
132
|
-
|
133
|
-
|
134
|
-
def validate_loader(loader: Callable, schema_uri: str | dict[str, Any]) -> None:
|
135
|
-
"""Sanity checking for input schema & loader."""
|
136
|
-
if loader not in (
|
137
|
-
oas_loaders.from_uri,
|
138
|
-
oas_loaders.from_aiohttp,
|
139
|
-
oas_loaders.from_dict,
|
140
|
-
oas_loaders.from_file,
|
141
|
-
oas_loaders.from_path,
|
142
|
-
oas_loaders.from_asgi,
|
143
|
-
oas_loaders.from_wsgi,
|
144
|
-
gql_loaders.from_dict,
|
145
|
-
gql_loaders.from_url,
|
146
|
-
gql_loaders.from_wsgi,
|
147
|
-
):
|
148
|
-
# Custom loaders are not checked
|
149
|
-
return
|
150
|
-
if isinstance(schema_uri, dict):
|
151
|
-
if loader not in (oas_loaders.from_dict, gql_loaders.from_dict):
|
152
|
-
raise ValueError("Dictionary as a schema is allowed only with `from_dict` loader")
|
153
|
-
elif loader in (oas_loaders.from_dict, gql_loaders.from_dict):
|
154
|
-
raise ValueError("Schema should be a dictionary for `from_dict` loader")
|
155
|
-
|
156
|
-
|
157
|
-
def execute_from_schema(
|
158
|
-
*,
|
159
|
-
schema_uri: str | dict[str, Any],
|
160
|
-
loader: Callable = oas_loaders.from_uri,
|
161
|
-
base_url: str | None = None,
|
162
|
-
endpoint: Filter | None = None,
|
163
|
-
method: Filter | None = None,
|
164
|
-
tag: Filter | None = None,
|
165
|
-
operation_id: Filter | None = None,
|
166
|
-
app: str | None = None,
|
167
|
-
validate_schema: bool = True,
|
168
|
-
skip_deprecated_operations: bool = False,
|
169
|
-
force_schema_version: str | None = None,
|
170
|
-
checks: Iterable[CheckFunction],
|
171
|
-
data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
|
172
|
-
max_response_time: int | None = None,
|
173
|
-
targets: Iterable[Target],
|
174
|
-
workers_num: int = 1,
|
175
|
-
hypothesis_settings: hypothesis.settings,
|
176
|
-
auth: RawAuth | None = None,
|
177
|
-
auth_type: str | None = None,
|
178
|
-
override: CaseOverride | None = None,
|
179
|
-
headers: dict[str, Any] | None = None,
|
180
|
-
request_timeout: int | None = None,
|
181
|
-
request_tls_verify: bool | str = True,
|
182
|
-
request_cert: RequestCert | None = None,
|
183
|
-
seed: int | None = None,
|
184
|
-
exit_first: bool = False,
|
185
|
-
dry_run: bool = False,
|
186
|
-
store_interactions: bool = False,
|
187
|
-
stateful: Stateful | None = None,
|
188
|
-
stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
|
189
|
-
count_operations: bool = True,
|
190
|
-
count_links: bool = True,
|
191
|
-
) -> Generator[events.ExecutionEvent, None, None]:
|
192
|
-
"""Execute tests for the given schema.
|
193
|
-
|
194
|
-
Provides the main testing loop and preparation step.
|
195
|
-
"""
|
196
|
-
try:
|
197
|
-
if app is not None:
|
198
|
-
app = load_app(app)
|
199
|
-
schema = load_schema(
|
200
|
-
schema_uri,
|
201
|
-
base_url=base_url,
|
202
|
-
loader=loader,
|
203
|
-
app=app,
|
204
|
-
validate_schema=validate_schema,
|
205
|
-
skip_deprecated_operations=skip_deprecated_operations,
|
206
|
-
auth=auth,
|
207
|
-
auth_type=auth_type,
|
208
|
-
headers=headers,
|
209
|
-
endpoint=endpoint,
|
210
|
-
method=method,
|
211
|
-
tag=tag,
|
212
|
-
operation_id=operation_id,
|
213
|
-
data_generation_methods=data_generation_methods,
|
214
|
-
force_schema_version=force_schema_version,
|
215
|
-
request_tls_verify=request_tls_verify,
|
216
|
-
request_cert=request_cert,
|
217
|
-
)
|
218
|
-
yield from from_schema(
|
219
|
-
schema,
|
220
|
-
checks=checks,
|
221
|
-
max_response_time=max_response_time,
|
222
|
-
targets=targets,
|
223
|
-
hypothesis_settings=hypothesis_settings,
|
224
|
-
auth=auth,
|
225
|
-
auth_type=auth_type,
|
226
|
-
override=override,
|
227
|
-
headers=headers,
|
228
|
-
seed=seed,
|
229
|
-
workers_num=workers_num,
|
230
|
-
request_timeout=request_timeout,
|
231
|
-
request_tls_verify=request_tls_verify,
|
232
|
-
request_cert=request_cert,
|
233
|
-
exit_first=exit_first,
|
234
|
-
dry_run=dry_run,
|
235
|
-
store_interactions=store_interactions,
|
236
|
-
stateful=stateful,
|
237
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
238
|
-
count_operations=count_operations,
|
239
|
-
count_links=count_links,
|
240
|
-
).execute()
|
241
|
-
except SchemaError as error:
|
242
|
-
yield events.InternalError.from_schema_error(error)
|
243
|
-
except Exception as exc:
|
244
|
-
yield events.InternalError.from_exc(exc)
|
245
|
-
|
246
|
-
|
247
|
-
def load_schema(
|
248
|
-
schema_uri: str | dict[str, Any],
|
249
|
-
*,
|
250
|
-
base_url: str | None = None,
|
251
|
-
loader: Callable = oas_loaders.from_uri,
|
252
|
-
app: Any = None,
|
253
|
-
validate_schema: bool = True,
|
254
|
-
skip_deprecated_operations: bool = False,
|
255
|
-
data_generation_methods: tuple[DataGenerationMethod, ...] = DEFAULT_DATA_GENERATION_METHODS,
|
256
|
-
force_schema_version: str | None = None,
|
257
|
-
request_tls_verify: bool | str = True,
|
258
|
-
request_cert: RequestCert | None = None,
|
259
|
-
# Network request parameters
|
260
|
-
auth: tuple[str, str] | None = None,
|
261
|
-
auth_type: str | None = None,
|
262
|
-
headers: dict[str, str] | None = None,
|
263
|
-
# Schema filters
|
264
|
-
endpoint: Filter | None = None,
|
265
|
-
method: Filter | None = None,
|
266
|
-
tag: Filter | None = None,
|
267
|
-
operation_id: Filter | None = None,
|
268
|
-
) -> BaseSchema:
|
269
|
-
"""Load schema via specified loader and parameters."""
|
270
|
-
loader_options = {
|
271
|
-
key: value
|
272
|
-
for key, value in (
|
273
|
-
("base_url", base_url),
|
274
|
-
("endpoint", endpoint),
|
275
|
-
("method", method),
|
276
|
-
("tag", tag),
|
277
|
-
("operation_id", operation_id),
|
278
|
-
("app", app),
|
279
|
-
("data_generation_methods", data_generation_methods),
|
280
|
-
)
|
281
|
-
if value
|
282
|
-
}
|
283
|
-
|
284
|
-
if not isinstance(schema_uri, dict):
|
285
|
-
if file_exists(schema_uri):
|
286
|
-
loader = oas_loaders.from_path
|
287
|
-
elif loader is not oas_loaders.from_path:
|
288
|
-
if app is not None and not urlparse(schema_uri).netloc:
|
289
|
-
# If `schema` is not an existing filesystem path, or a URL then it is considered as a path within
|
290
|
-
# the given app
|
291
|
-
loader = oas_loaders.get_loader_for_app(app)
|
292
|
-
if headers:
|
293
|
-
loader_options["headers"] = headers
|
294
|
-
else:
|
295
|
-
if headers:
|
296
|
-
loader_options["headers"] = headers
|
297
|
-
if auth:
|
298
|
-
loader_options["auth"] = auth
|
299
|
-
if auth_type:
|
300
|
-
loader_options["auth_type"] = auth_type
|
301
|
-
|
302
|
-
if loader is oas_loaders.from_uri and loader_options.get("auth"):
|
303
|
-
loader_options["auth"] = get_requests_auth(loader_options["auth"], loader_options.pop("auth_type", None))
|
304
|
-
if loader in (oas_loaders.from_uri, oas_loaders.from_aiohttp):
|
305
|
-
loader_options["verify"] = request_tls_verify
|
306
|
-
loader_options["cert"] = request_cert
|
307
|
-
|
308
|
-
return loader(
|
309
|
-
schema_uri,
|
310
|
-
validate_schema=validate_schema,
|
311
|
-
skip_deprecated_operations=skip_deprecated_operations,
|
312
|
-
force_schema_version=force_schema_version,
|
313
|
-
**loader_options,
|
314
|
-
)
|
315
|
-
|
316
|
-
|
317
|
-
def from_schema(
|
318
|
-
schema: BaseSchema,
|
319
|
-
*,
|
320
|
-
override: CaseOverride | None = None,
|
321
|
-
checks: Iterable[CheckFunction] | None = None,
|
322
|
-
max_response_time: int | None = None,
|
323
|
-
targets: Iterable[Target] = DEFAULT_TARGETS,
|
324
|
-
workers_num: int = 1,
|
325
|
-
hypothesis_settings: hypothesis.settings | None = None,
|
326
|
-
generation_config: GenerationConfig | None = None,
|
327
|
-
auth: RawAuth | None = None,
|
328
|
-
auth_type: str | None = None,
|
329
|
-
headers: dict[str, Any] | None = None,
|
330
|
-
request_timeout: int | None = None,
|
331
|
-
request_tls_verify: bool | str = True,
|
332
|
-
request_proxy: str | None = None,
|
333
|
-
request_cert: RequestCert | None = None,
|
334
|
-
seed: int | None = None,
|
335
|
-
exit_first: bool = False,
|
336
|
-
max_failures: int | None = None,
|
337
|
-
started_at: str | None = None,
|
338
|
-
dry_run: bool = False,
|
339
|
-
store_interactions: bool = False,
|
340
|
-
stateful: Stateful | None = None,
|
341
|
-
stateful_recursion_limit: int = DEFAULT_STATEFUL_RECURSION_LIMIT,
|
342
|
-
count_operations: bool = True,
|
343
|
-
count_links: bool = True,
|
344
|
-
) -> BaseRunner:
|
345
|
-
from starlette.applications import Starlette
|
346
|
-
import hypothesis
|
347
|
-
from ..checks import DEFAULT_CHECKS
|
348
|
-
from .impl import (
|
349
|
-
SingleThreadASGIRunner,
|
350
|
-
SingleThreadRunner,
|
351
|
-
SingleThreadWSGIRunner,
|
352
|
-
ThreadPoolASGIRunner,
|
353
|
-
ThreadPoolRunner,
|
354
|
-
ThreadPoolWSGIRunner,
|
355
|
-
)
|
356
|
-
|
357
|
-
checks = checks or DEFAULT_CHECKS
|
358
|
-
|
359
|
-
hypothesis_settings = hypothesis_settings or hypothesis.settings(deadline=DEFAULT_DEADLINE)
|
360
|
-
generation_config = generation_config or GenerationConfig()
|
361
|
-
|
362
|
-
# Use the same seed for all tests unless `derandomize=True` is used
|
363
|
-
if seed is None and not hypothesis_settings.derandomize:
|
364
|
-
seed = Random().getrandbits(128)
|
365
|
-
|
366
|
-
started_at = started_at or current_datetime()
|
367
|
-
if workers_num > 1:
|
368
|
-
if not schema.app:
|
369
|
-
return ThreadPoolRunner(
|
370
|
-
schema=schema,
|
371
|
-
checks=checks,
|
372
|
-
max_response_time=max_response_time,
|
373
|
-
targets=targets,
|
374
|
-
hypothesis_settings=hypothesis_settings,
|
375
|
-
generation_config=generation_config,
|
376
|
-
auth=auth,
|
377
|
-
auth_type=auth_type,
|
378
|
-
override=override,
|
379
|
-
headers=headers,
|
380
|
-
seed=seed,
|
381
|
-
workers_num=workers_num,
|
382
|
-
request_timeout=request_timeout,
|
383
|
-
request_tls_verify=request_tls_verify,
|
384
|
-
request_proxy=request_proxy,
|
385
|
-
request_cert=request_cert,
|
386
|
-
exit_first=exit_first,
|
387
|
-
max_failures=max_failures,
|
388
|
-
started_at=started_at,
|
389
|
-
dry_run=dry_run,
|
390
|
-
store_interactions=store_interactions,
|
391
|
-
stateful=stateful,
|
392
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
393
|
-
count_operations=count_operations,
|
394
|
-
count_links=count_links,
|
395
|
-
)
|
396
|
-
if isinstance(schema.app, Starlette):
|
397
|
-
return ThreadPoolASGIRunner(
|
398
|
-
schema=schema,
|
399
|
-
checks=checks,
|
400
|
-
max_response_time=max_response_time,
|
401
|
-
targets=targets,
|
402
|
-
hypothesis_settings=hypothesis_settings,
|
403
|
-
generation_config=generation_config,
|
404
|
-
auth=auth,
|
405
|
-
auth_type=auth_type,
|
406
|
-
override=override,
|
407
|
-
headers=headers,
|
408
|
-
seed=seed,
|
409
|
-
exit_first=exit_first,
|
410
|
-
max_failures=max_failures,
|
411
|
-
started_at=started_at,
|
412
|
-
dry_run=dry_run,
|
413
|
-
store_interactions=store_interactions,
|
414
|
-
stateful=stateful,
|
415
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
416
|
-
count_operations=count_operations,
|
417
|
-
count_links=count_links,
|
418
|
-
)
|
419
|
-
return ThreadPoolWSGIRunner(
|
420
|
-
schema=schema,
|
421
|
-
checks=checks,
|
422
|
-
max_response_time=max_response_time,
|
423
|
-
targets=targets,
|
424
|
-
hypothesis_settings=hypothesis_settings,
|
425
|
-
generation_config=generation_config,
|
426
|
-
auth=auth,
|
427
|
-
auth_type=auth_type,
|
428
|
-
override=override,
|
429
|
-
headers=headers,
|
430
|
-
seed=seed,
|
431
|
-
workers_num=workers_num,
|
432
|
-
exit_first=exit_first,
|
433
|
-
max_failures=max_failures,
|
434
|
-
started_at=started_at,
|
435
|
-
dry_run=dry_run,
|
436
|
-
store_interactions=store_interactions,
|
437
|
-
stateful=stateful,
|
438
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
439
|
-
count_operations=count_operations,
|
440
|
-
count_links=count_links,
|
441
|
-
)
|
442
|
-
if not schema.app:
|
443
|
-
return SingleThreadRunner(
|
444
|
-
schema=schema,
|
445
|
-
checks=checks,
|
446
|
-
max_response_time=max_response_time,
|
447
|
-
targets=targets,
|
448
|
-
hypothesis_settings=hypothesis_settings,
|
449
|
-
generation_config=generation_config,
|
450
|
-
auth=auth,
|
451
|
-
auth_type=auth_type,
|
452
|
-
override=override,
|
453
|
-
headers=headers,
|
454
|
-
seed=seed,
|
455
|
-
request_timeout=request_timeout,
|
456
|
-
request_tls_verify=request_tls_verify,
|
457
|
-
request_proxy=request_proxy,
|
458
|
-
request_cert=request_cert,
|
459
|
-
exit_first=exit_first,
|
460
|
-
max_failures=max_failures,
|
461
|
-
started_at=started_at,
|
462
|
-
dry_run=dry_run,
|
463
|
-
store_interactions=store_interactions,
|
464
|
-
stateful=stateful,
|
465
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
466
|
-
count_operations=count_operations,
|
467
|
-
count_links=count_links,
|
468
|
-
)
|
469
|
-
if isinstance(schema.app, Starlette):
|
470
|
-
return SingleThreadASGIRunner(
|
471
|
-
schema=schema,
|
472
|
-
checks=checks,
|
473
|
-
max_response_time=max_response_time,
|
474
|
-
targets=targets,
|
475
|
-
hypothesis_settings=hypothesis_settings,
|
476
|
-
generation_config=generation_config,
|
477
|
-
auth=auth,
|
478
|
-
auth_type=auth_type,
|
479
|
-
override=override,
|
480
|
-
headers=headers,
|
481
|
-
seed=seed,
|
482
|
-
exit_first=exit_first,
|
483
|
-
max_failures=max_failures,
|
484
|
-
started_at=started_at,
|
485
|
-
dry_run=dry_run,
|
486
|
-
store_interactions=store_interactions,
|
487
|
-
stateful=stateful,
|
488
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
489
|
-
count_operations=count_operations,
|
490
|
-
count_links=count_links,
|
491
|
-
)
|
492
|
-
return SingleThreadWSGIRunner(
|
493
|
-
schema=schema,
|
494
|
-
checks=checks,
|
495
|
-
max_response_time=max_response_time,
|
496
|
-
targets=targets,
|
497
|
-
hypothesis_settings=hypothesis_settings,
|
498
|
-
generation_config=generation_config,
|
499
|
-
auth=auth,
|
500
|
-
auth_type=auth_type,
|
501
|
-
override=override,
|
502
|
-
headers=headers,
|
503
|
-
seed=seed,
|
504
|
-
exit_first=exit_first,
|
505
|
-
max_failures=max_failures,
|
506
|
-
started_at=started_at,
|
507
|
-
dry_run=dry_run,
|
508
|
-
store_interactions=store_interactions,
|
509
|
-
stateful=stateful,
|
510
|
-
stateful_recursion_limit=stateful_recursion_limit,
|
511
|
-
count_operations=count_operations,
|
512
|
-
count_links=count_links,
|
513
|
-
)
|
514
|
-
|
515
|
-
|
516
|
-
def prepare_hypothesis_settings(
|
517
|
-
database: str | None = None,
|
518
|
-
deadline: int | NotSet | None = None,
|
519
|
-
derandomize: bool | None = None,
|
520
|
-
max_examples: int | None = None,
|
521
|
-
phases: list[hypothesis.Phase] | None = None,
|
522
|
-
report_multiple_bugs: bool | None = None,
|
523
|
-
suppress_health_check: list[hypothesis.HealthCheck] | None = None,
|
524
|
-
verbosity: hypothesis.Verbosity | None = None,
|
525
|
-
) -> hypothesis.settings:
|
526
|
-
import hypothesis
|
527
|
-
from hypothesis.database import DirectoryBasedExampleDatabase, InMemoryExampleDatabase
|
528
|
-
|
529
|
-
kwargs = {
|
530
|
-
key: value
|
531
|
-
for key, value in (
|
532
|
-
("derandomize", derandomize),
|
533
|
-
("max_examples", max_examples),
|
534
|
-
("phases", phases),
|
535
|
-
("report_multiple_bugs", report_multiple_bugs),
|
536
|
-
("suppress_health_check", suppress_health_check),
|
537
|
-
("verbosity", verbosity),
|
538
|
-
)
|
539
|
-
if value is not None
|
540
|
-
}
|
541
|
-
# `deadline` is special, since Hypothesis allows passing `None`
|
542
|
-
if deadline is not None:
|
543
|
-
if isinstance(deadline, NotSet):
|
544
|
-
kwargs["deadline"] = None
|
545
|
-
else:
|
546
|
-
kwargs["deadline"] = deadline
|
547
|
-
if database is not None:
|
548
|
-
if database.lower() == "none":
|
549
|
-
kwargs["database"] = None
|
550
|
-
elif database == HYPOTHESIS_IN_MEMORY_DATABASE_IDENTIFIER:
|
551
|
-
kwargs["database"] = InMemoryExampleDatabase()
|
552
|
-
else:
|
553
|
-
kwargs["database"] = DirectoryBasedExampleDatabase(database)
|
554
|
-
kwargs.setdefault("deadline", DEFAULT_DEADLINE)
|
555
|
-
return hypothesis.settings(print_blob=False, **kwargs)
|