schemathesis 4.0.0a10__py3-none-any.whl → 4.0.0a12__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 +29 -30
- schemathesis/auths.py +65 -24
- schemathesis/checks.py +73 -39
- schemathesis/cli/commands/__init__.py +51 -3
- schemathesis/cli/commands/data.py +10 -0
- schemathesis/cli/commands/run/__init__.py +163 -274
- schemathesis/cli/commands/run/context.py +8 -4
- schemathesis/cli/commands/run/events.py +11 -1
- schemathesis/cli/commands/run/executor.py +70 -78
- schemathesis/cli/commands/run/filters.py +15 -165
- schemathesis/cli/commands/run/handlers/cassettes.py +105 -104
- schemathesis/cli/commands/run/handlers/junitxml.py +5 -4
- schemathesis/cli/commands/run/handlers/output.py +195 -121
- schemathesis/cli/commands/run/loaders.py +35 -50
- schemathesis/cli/commands/run/validation.py +52 -162
- schemathesis/cli/core.py +5 -3
- schemathesis/cli/ext/fs.py +7 -5
- schemathesis/cli/ext/options.py +0 -21
- schemathesis/config/__init__.py +189 -0
- schemathesis/config/_auth.py +51 -0
- schemathesis/config/_checks.py +268 -0
- schemathesis/config/_diff_base.py +99 -0
- schemathesis/config/_env.py +21 -0
- schemathesis/config/_error.py +156 -0
- schemathesis/config/_generation.py +149 -0
- schemathesis/config/_health_check.py +24 -0
- schemathesis/config/_operations.py +327 -0
- schemathesis/config/_output.py +171 -0
- schemathesis/config/_parameters.py +19 -0
- schemathesis/config/_phases.py +187 -0
- schemathesis/config/_projects.py +523 -0
- schemathesis/config/_rate_limit.py +17 -0
- schemathesis/config/_report.py +120 -0
- schemathesis/config/_validator.py +9 -0
- schemathesis/config/_warnings.py +25 -0
- schemathesis/config/schema.json +885 -0
- schemathesis/core/__init__.py +2 -0
- schemathesis/core/compat.py +16 -9
- schemathesis/core/errors.py +24 -4
- schemathesis/core/failures.py +6 -7
- schemathesis/core/hooks.py +20 -0
- schemathesis/core/output/__init__.py +14 -37
- schemathesis/core/output/sanitization.py +3 -146
- schemathesis/core/transport.py +36 -1
- schemathesis/core/validation.py +16 -0
- schemathesis/engine/__init__.py +2 -4
- schemathesis/engine/context.py +42 -43
- schemathesis/engine/core.py +7 -5
- schemathesis/engine/errors.py +60 -1
- schemathesis/engine/events.py +10 -2
- schemathesis/engine/phases/__init__.py +10 -0
- schemathesis/engine/phases/probes.py +11 -8
- schemathesis/engine/phases/stateful/__init__.py +2 -1
- schemathesis/engine/phases/stateful/_executor.py +104 -46
- schemathesis/engine/phases/stateful/context.py +2 -2
- schemathesis/engine/phases/unit/__init__.py +23 -15
- schemathesis/engine/phases/unit/_executor.py +110 -21
- schemathesis/engine/phases/unit/_pool.py +1 -1
- schemathesis/errors.py +2 -0
- schemathesis/filters.py +2 -3
- schemathesis/generation/__init__.py +5 -33
- schemathesis/generation/case.py +6 -3
- schemathesis/generation/coverage.py +154 -124
- schemathesis/generation/hypothesis/builder.py +70 -20
- schemathesis/generation/meta.py +3 -3
- schemathesis/generation/metrics.py +93 -0
- schemathesis/generation/modes.py +0 -8
- schemathesis/generation/overrides.py +37 -1
- schemathesis/generation/stateful/__init__.py +4 -0
- schemathesis/generation/stateful/state_machine.py +9 -1
- schemathesis/graphql/loaders.py +159 -16
- schemathesis/hooks.py +62 -35
- schemathesis/openapi/checks.py +12 -8
- schemathesis/openapi/generation/filters.py +10 -8
- schemathesis/openapi/loaders.py +142 -17
- schemathesis/pytest/lazy.py +2 -5
- schemathesis/pytest/loaders.py +24 -0
- schemathesis/pytest/plugin.py +33 -2
- schemathesis/schemas.py +21 -66
- schemathesis/specs/graphql/scalars.py +37 -3
- schemathesis/specs/graphql/schemas.py +23 -18
- schemathesis/specs/openapi/_hypothesis.py +26 -28
- schemathesis/specs/openapi/checks.py +37 -36
- schemathesis/specs/openapi/examples.py +4 -3
- schemathesis/specs/openapi/formats.py +32 -5
- schemathesis/specs/openapi/media_types.py +44 -1
- schemathesis/specs/openapi/negative/__init__.py +2 -2
- schemathesis/specs/openapi/patterns.py +46 -16
- schemathesis/specs/openapi/references.py +2 -3
- schemathesis/specs/openapi/schemas.py +19 -22
- schemathesis/specs/openapi/stateful/__init__.py +12 -6
- schemathesis/transport/__init__.py +54 -16
- schemathesis/transport/prepare.py +38 -13
- schemathesis/transport/requests.py +12 -9
- schemathesis/transport/wsgi.py +11 -12
- {schemathesis-4.0.0a10.dist-info → schemathesis-4.0.0a12.dist-info}/METADATA +50 -97
- schemathesis-4.0.0a12.dist-info/RECORD +164 -0
- schemathesis/cli/commands/run/checks.py +0 -79
- schemathesis/cli/commands/run/hypothesis.py +0 -78
- schemathesis/cli/commands/run/reports.py +0 -72
- schemathesis/cli/hooks.py +0 -36
- schemathesis/contrib/__init__.py +0 -9
- schemathesis/contrib/openapi/__init__.py +0 -9
- schemathesis/contrib/openapi/fill_missing_examples.py +0 -20
- schemathesis/engine/config.py +0 -59
- schemathesis/experimental/__init__.py +0 -72
- schemathesis/generation/targets.py +0 -69
- schemathesis-4.0.0a10.dist-info/RECORD +0 -153
- {schemathesis-4.0.0a10.dist-info → schemathesis-4.0.0a12.dist-info}/WHEEL +0 -0
- {schemathesis-4.0.0a10.dist-info → schemathesis-4.0.0a12.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.0.0a10.dist-info → schemathesis-4.0.0a12.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
|
5
|
+
from schemathesis.config._error import ConfigError
|
6
|
+
from schemathesis.core import rate_limit
|
7
|
+
from schemathesis.core.errors import InvalidRateLimit
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from pyrate_limiter import Limiter
|
11
|
+
|
12
|
+
|
13
|
+
def build_limiter(value: str) -> Limiter:
|
14
|
+
try:
|
15
|
+
return rate_limit.build_limiter(value)
|
16
|
+
except InvalidRateLimit as exc:
|
17
|
+
raise ConfigError(str(exc)) from None
|
@@ -0,0 +1,120 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import datetime
|
4
|
+
from dataclasses import dataclass
|
5
|
+
from enum import Enum
|
6
|
+
from pathlib import Path
|
7
|
+
from typing import Any
|
8
|
+
|
9
|
+
from schemathesis.config._diff_base import DiffBase
|
10
|
+
from schemathesis.config._env import resolve
|
11
|
+
|
12
|
+
DEFAULT_REPORT_DIRECTORY = Path("./schemathesis-report")
|
13
|
+
|
14
|
+
|
15
|
+
class ReportFormat(str, Enum):
|
16
|
+
"""Available report formats."""
|
17
|
+
|
18
|
+
JUNIT = "junit"
|
19
|
+
VCR = "vcr"
|
20
|
+
HAR = "har"
|
21
|
+
|
22
|
+
@property
|
23
|
+
def extension(self) -> str:
|
24
|
+
"""File extension for this format."""
|
25
|
+
return {
|
26
|
+
self.JUNIT: "xml",
|
27
|
+
self.VCR: "yaml",
|
28
|
+
self.HAR: "json",
|
29
|
+
}[self]
|
30
|
+
|
31
|
+
|
32
|
+
@dataclass(repr=False)
|
33
|
+
class ReportConfig(DiffBase):
|
34
|
+
enabled: bool
|
35
|
+
path: Path | None
|
36
|
+
|
37
|
+
__slots__ = ("enabled", "path")
|
38
|
+
|
39
|
+
def __init__(self, *, enabled: bool = False, path: Path | None = None) -> None:
|
40
|
+
self.enabled = enabled
|
41
|
+
self.path = path
|
42
|
+
|
43
|
+
@classmethod
|
44
|
+
def from_dict(cls, data: dict[str, Any]) -> ReportConfig:
|
45
|
+
path = resolve(data.get("path"))
|
46
|
+
if path is not None:
|
47
|
+
return cls(enabled=True, path=Path(path))
|
48
|
+
enabled = data.get("enabled", False)
|
49
|
+
return cls(enabled=enabled, path=path)
|
50
|
+
|
51
|
+
|
52
|
+
@dataclass(repr=False)
|
53
|
+
class ReportsConfig(DiffBase):
|
54
|
+
directory: Path
|
55
|
+
preserve_bytes: bool
|
56
|
+
junit: ReportConfig
|
57
|
+
vcr: ReportConfig
|
58
|
+
har: ReportConfig
|
59
|
+
_timestamp: str
|
60
|
+
|
61
|
+
__slots__ = ("directory", "preserve_bytes", "junit", "vcr", "har", "_timestamp")
|
62
|
+
|
63
|
+
def __init__(
|
64
|
+
self,
|
65
|
+
*,
|
66
|
+
directory: str | None = None,
|
67
|
+
preserve_bytes: bool = False,
|
68
|
+
junit: ReportConfig | None = None,
|
69
|
+
vcr: ReportConfig | None = None,
|
70
|
+
har: ReportConfig | None = None,
|
71
|
+
) -> None:
|
72
|
+
self.directory = Path(resolve(directory) or DEFAULT_REPORT_DIRECTORY)
|
73
|
+
self.preserve_bytes = preserve_bytes
|
74
|
+
self.junit = junit or ReportConfig()
|
75
|
+
self.vcr = vcr or ReportConfig()
|
76
|
+
self.har = har or ReportConfig()
|
77
|
+
self._timestamp = datetime.datetime.now().strftime("%Y%m%dT%H%M%SZ")
|
78
|
+
|
79
|
+
@classmethod
|
80
|
+
def from_dict(cls, data: dict[str, Any]) -> ReportsConfig:
|
81
|
+
return cls(
|
82
|
+
directory=data.get("directory"),
|
83
|
+
preserve_bytes=data.get("preserve-bytes", False),
|
84
|
+
junit=ReportConfig.from_dict(data.get("junit", {})),
|
85
|
+
vcr=ReportConfig.from_dict(data.get("vcr", {})),
|
86
|
+
har=ReportConfig.from_dict(data.get("har", {})),
|
87
|
+
)
|
88
|
+
|
89
|
+
def update(
|
90
|
+
self,
|
91
|
+
*,
|
92
|
+
formats: list[ReportFormat] | None = None,
|
93
|
+
junit_path: str | None = None,
|
94
|
+
vcr_path: str | None = None,
|
95
|
+
har_path: str | None = None,
|
96
|
+
directory: Path = DEFAULT_REPORT_DIRECTORY,
|
97
|
+
preserve_bytes: bool = False,
|
98
|
+
) -> None:
|
99
|
+
formats = formats or []
|
100
|
+
if junit_path is not None or ReportFormat.JUNIT in formats:
|
101
|
+
self.junit.enabled = True
|
102
|
+
self.junit.path = Path(junit_path) if junit_path is not None else junit_path
|
103
|
+
if vcr_path is not None or ReportFormat.VCR in formats:
|
104
|
+
self.vcr.enabled = True
|
105
|
+
self.vcr.path = Path(vcr_path) if vcr_path is not None else vcr_path
|
106
|
+
if har_path is not None or ReportFormat.HAR in formats:
|
107
|
+
self.har.enabled = True
|
108
|
+
self.har.path = Path(har_path) if har_path is not None else har_path
|
109
|
+
if directory != DEFAULT_REPORT_DIRECTORY:
|
110
|
+
self.directory = directory
|
111
|
+
if preserve_bytes is True:
|
112
|
+
self.preserve_bytes = preserve_bytes
|
113
|
+
|
114
|
+
def get_path(self, format: ReportFormat) -> Path:
|
115
|
+
"""Get the final path for a specific format."""
|
116
|
+
report: ReportConfig = getattr(self, format.value)
|
117
|
+
if report.path is not None:
|
118
|
+
return report.path
|
119
|
+
|
120
|
+
return self.directory / f"{format.value}-{self._timestamp}.{format.extension}"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import json
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
import jsonschema.validators
|
5
|
+
|
6
|
+
with (Path(__file__).absolute().parent / "schema.json").open() as fd:
|
7
|
+
CONFIG_SCHEMA = json.loads(fd.read())
|
8
|
+
|
9
|
+
CONFIG_VALIDATOR = jsonschema.validators.Draft202012Validator(CONFIG_SCHEMA)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import enum
|
4
|
+
|
5
|
+
from schemathesis.config._env import resolve
|
6
|
+
|
7
|
+
|
8
|
+
class SchemathesisWarning(str, enum.Enum):
|
9
|
+
MISSING_AUTH = "missing_auth"
|
10
|
+
MISSING_TEST_DATA = "missing_test_data"
|
11
|
+
VALIDATION_MISMATCH = "validation_mismatch"
|
12
|
+
|
13
|
+
@classmethod
|
14
|
+
def from_str(cls, value: str) -> SchemathesisWarning:
|
15
|
+
return {
|
16
|
+
"missing_auth": cls.MISSING_AUTH,
|
17
|
+
"missing_test_data": cls.MISSING_TEST_DATA,
|
18
|
+
"validation_mismatch": cls.VALIDATION_MISMATCH,
|
19
|
+
}[value.lower()]
|
20
|
+
|
21
|
+
|
22
|
+
def resolve_warnings(value: bool | list[str] | None) -> bool | list[SchemathesisWarning] | None:
|
23
|
+
if isinstance(value, list):
|
24
|
+
return [SchemathesisWarning.from_str(resolve(item)) for item in value]
|
25
|
+
return value
|