schemathesis 4.0.14__py3-none-any.whl → 4.0.16__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/cli/commands/run/handlers/output.py +15 -5
- schemathesis/generation/coverage.py +3 -0
- schemathesis/generation/hypothesis/builder.py +2 -1
- schemathesis/generation/stateful/state_machine.py +3 -1
- schemathesis/specs/openapi/schemas.py +1 -1
- schemathesis/transport/requests.py +9 -6
- {schemathesis-4.0.14.dist-info → schemathesis-4.0.16.dist-info}/METADATA +1 -1
- {schemathesis-4.0.14.dist-info → schemathesis-4.0.16.dist-info}/RECORD +11 -11
- {schemathesis-4.0.14.dist-info → schemathesis-4.0.16.dist-info}/WHEEL +0 -0
- {schemathesis-4.0.14.dist-info → schemathesis-4.0.16.dist-info}/entry_points.txt +0 -0
- {schemathesis-4.0.14.dist-info → schemathesis-4.0.16.dist-info}/licenses/LICENSE +0 -0
@@ -26,6 +26,7 @@ from schemathesis.engine import Status, events
|
|
26
26
|
from schemathesis.engine.phases import PhaseName, PhaseSkipReason
|
27
27
|
from schemathesis.engine.phases.probes import ProbeOutcome
|
28
28
|
from schemathesis.engine.recorder import Interaction, ScenarioRecorder
|
29
|
+
from schemathesis.generation.meta import CoveragePhaseData
|
29
30
|
from schemathesis.generation.modes import GenerationMode
|
30
31
|
from schemathesis.schemas import ApiStatistic
|
31
32
|
|
@@ -1053,10 +1054,19 @@ class OutputHandler(EventHandler):
|
|
1053
1054
|
|
1054
1055
|
warnings = self.config.warnings_for(operation=operation)
|
1055
1056
|
|
1057
|
+
def has_only_missing_auth_case() -> bool:
|
1058
|
+
case = list(event.recorder.cases.values())[0].value
|
1059
|
+
return bool(
|
1060
|
+
case.meta
|
1061
|
+
and isinstance(case.meta.phase.data, CoveragePhaseData)
|
1062
|
+
and case.meta.phase.data.description == "Missing `Authorization` at header"
|
1063
|
+
)
|
1064
|
+
|
1056
1065
|
if SchemathesisWarning.MISSING_AUTH in warnings:
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1066
|
+
if not (len(event.recorder.cases) == 1 and has_only_missing_auth_case()):
|
1067
|
+
for status_code in (401, 403):
|
1068
|
+
if statistic.ratio_for(status_code) >= AUTH_ERRORS_THRESHOLD:
|
1069
|
+
self.warnings.missing_auth.setdefault(status_code, set()).add(event.recorder.label)
|
1060
1070
|
|
1061
1071
|
# Warn if all positive test cases got 4xx in return and no failure was found
|
1062
1072
|
def all_positive_are_rejected(recorder: ScenarioRecorder) -> bool:
|
@@ -1220,10 +1230,10 @@ class OutputHandler(EventHandler):
|
|
1220
1230
|
click.echo()
|
1221
1231
|
if self.warnings.missing_auth:
|
1222
1232
|
self._display_warning_block(
|
1223
|
-
title="
|
1233
|
+
title="Authentication failed",
|
1224
1234
|
operations=self.warnings.missing_auth,
|
1225
1235
|
operation_suffix=" returned authentication errors",
|
1226
|
-
tips=["💡
|
1236
|
+
tips=["💡 Ensure valid authentication credentials are set via --auth or -H"],
|
1227
1237
|
)
|
1228
1238
|
|
1229
1239
|
if self.warnings.missing_test_data:
|
@@ -233,6 +233,9 @@ class CoverageContext:
|
|
233
233
|
return cached_draw(st.integers(min_value=schema.get("minimum"), max_value=schema.get("maximum")))
|
234
234
|
if "enum" in schema:
|
235
235
|
return cached_draw(st.sampled_from(schema["enum"]))
|
236
|
+
if keys == ["multipleOf", "type"] and schema["type"] in ("integer", "number"):
|
237
|
+
step = schema["multipleOf"]
|
238
|
+
return cached_draw(st.integers().map(step.__mul__))
|
236
239
|
if "pattern" in schema:
|
237
240
|
pattern = schema["pattern"]
|
238
241
|
try:
|
@@ -22,6 +22,7 @@ from schemathesis.config import GenerationConfig, ProjectConfig
|
|
22
22
|
from schemathesis.core import NOT_SET, NotSet, SpecificationFeature, media_types
|
23
23
|
from schemathesis.core.errors import InvalidSchema, SerializationNotPossible
|
24
24
|
from schemathesis.core.marks import Mark
|
25
|
+
from schemathesis.core.transforms import deepclone
|
25
26
|
from schemathesis.core.transport import prepare_urlencoded
|
26
27
|
from schemathesis.core.validation import has_invalid_characters, is_latin_1_encodable
|
27
28
|
from schemathesis.generation import GenerationMode, coverage
|
@@ -397,7 +398,7 @@ class Template:
|
|
397
398
|
return output
|
398
399
|
|
399
400
|
def unmodified(self) -> TemplateValue:
|
400
|
-
kwargs = self._template
|
401
|
+
kwargs = deepclone(self._template)
|
401
402
|
kwargs = self._serialize(kwargs)
|
402
403
|
return TemplateValue(kwargs=kwargs, components=self._components.copy())
|
403
404
|
|
@@ -185,9 +185,11 @@ class APIStateMachine(RuleBasedStateMachine):
|
|
185
185
|
if target is not None:
|
186
186
|
super()._add_result_to_targets((target,), result)
|
187
187
|
|
188
|
-
def _add_results_to_targets(self, targets: tuple[str, ...], results: list[StepOutput]) -> None:
|
188
|
+
def _add_results_to_targets(self, targets: tuple[str, ...], results: list[StepOutput | None]) -> None:
|
189
189
|
# Hypothesis >6.131.15
|
190
190
|
for result in results:
|
191
|
+
if result is None:
|
192
|
+
continue
|
191
193
|
target = self._get_target_for_result(result)
|
192
194
|
if target is not None:
|
193
195
|
super()._add_results_to_targets((target,), [result])
|
@@ -195,7 +195,7 @@ class BaseOpenAPISchema(BaseSchema):
|
|
195
195
|
self.resolver.push_scope(scope)
|
196
196
|
try:
|
197
197
|
for method, definition in path_item.items():
|
198
|
-
if method not in HTTP_METHODS:
|
198
|
+
if method not in HTTP_METHODS or not definition:
|
199
199
|
continue
|
200
200
|
statistic.operations.total += 1
|
201
201
|
is_selected = not should_skip(path, method, definition)
|
@@ -80,6 +80,10 @@ class RequestsTransport(BaseTransport["requests.Session"]):
|
|
80
80
|
if cookies is not None:
|
81
81
|
merge_at(data, "cookies", cookies)
|
82
82
|
|
83
|
+
excluded_headers = get_exclude_headers(case)
|
84
|
+
for name in excluded_headers:
|
85
|
+
data["headers"].pop(name, None)
|
86
|
+
|
83
87
|
return data
|
84
88
|
|
85
89
|
def send(self, case: Case, *, session: requests.Session | None = None, **kwargs: Any) -> Response:
|
@@ -112,9 +116,6 @@ class RequestsTransport(BaseTransport["requests.Session"]):
|
|
112
116
|
data.update({key: value for key, value in kwargs.items() if key not in data})
|
113
117
|
data.setdefault("timeout", DEFAULT_RESPONSE_TIMEOUT)
|
114
118
|
|
115
|
-
excluded_headers = get_exclude_headers(case)
|
116
|
-
for name in excluded_headers:
|
117
|
-
data["headers"].pop(name, None)
|
118
119
|
current_session_headers: MutableMapping[str, Any] = {}
|
119
120
|
current_session_auth = None
|
120
121
|
|
@@ -124,9 +125,11 @@ class RequestsTransport(BaseTransport["requests.Session"]):
|
|
124
125
|
close_session = True
|
125
126
|
else:
|
126
127
|
current_session_headers = session.headers
|
127
|
-
if isinstance(session.auth, tuple)
|
128
|
-
|
129
|
-
|
128
|
+
if isinstance(session.auth, tuple):
|
129
|
+
excluded_headers = get_exclude_headers(case)
|
130
|
+
if "Authorization" in excluded_headers:
|
131
|
+
current_session_auth = session.auth
|
132
|
+
session.auth = None
|
130
133
|
close_session = False
|
131
134
|
session.headers = {}
|
132
135
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: schemathesis
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.16
|
4
4
|
Summary: Property-based testing framework for Open API and GraphQL based apps
|
5
5
|
Project-URL: Documentation, https://schemathesis.readthedocs.io/en/stable/
|
6
6
|
Project-URL: Changelog, https://github.com/schemathesis/schemathesis/blob/master/CHANGELOG.md
|
@@ -23,7 +23,7 @@ schemathesis/cli/commands/run/handlers/__init__.py,sha256=TPZ3KdGi8m0fjlN0GjA31M
|
|
23
23
|
schemathesis/cli/commands/run/handlers/base.py,sha256=yDsTtCiztLksfk7cRzg8JlaAVOfS-zwK3tsJMOXAFyc,530
|
24
24
|
schemathesis/cli/commands/run/handlers/cassettes.py,sha256=rRD4byjp4HXCkJS-zx3jSIFOJsPq77ejPpYeyCtsEZs,19461
|
25
25
|
schemathesis/cli/commands/run/handlers/junitxml.py,sha256=ydk6Ofj-Uti6H8EucT4Snp85cmTA5W7uVpKkoHrIDKE,2586
|
26
|
-
schemathesis/cli/commands/run/handlers/output.py,sha256=
|
26
|
+
schemathesis/cli/commands/run/handlers/output.py,sha256=oS3HP4idz99IxpZcjsqADtEOkuu8wruTcri5c1YIph0,62986
|
27
27
|
schemathesis/cli/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
28
28
|
schemathesis/cli/ext/fs.py,sha256=3lvoAsEDDdih75ITJJNxemd3nwxX55gGWrI7uDxm0cM,447
|
29
29
|
schemathesis/cli/ext/groups.py,sha256=kQ37t6qeArcKaY2y5VxyK3_KwAkBKCVm58IYV8gewds,2720
|
@@ -85,19 +85,19 @@ schemathesis/engine/phases/unit/_executor.py,sha256=9MmZoKSBVSPk0LWwN3PZ3iaO9nzp
|
|
85
85
|
schemathesis/engine/phases/unit/_pool.py,sha256=iU0hdHDmohPnEv7_S1emcabuzbTf-Cznqwn0pGQ5wNQ,2480
|
86
86
|
schemathesis/generation/__init__.py,sha256=tvNO2FLiY8z3fZ_kL_QJhSgzXfnT4UqwSXMHCwfLI0g,645
|
87
87
|
schemathesis/generation/case.py,sha256=zwAwFQ-Fp7SOxCXYOQyAdwAtNwVJe63PdLpvqackFQY,12296
|
88
|
-
schemathesis/generation/coverage.py,sha256=
|
88
|
+
schemathesis/generation/coverage.py,sha256=jpl1GpAGZXyoO2aZLUZlIE0h_ygdHMnvUK14oBg51k4,53896
|
89
89
|
schemathesis/generation/meta.py,sha256=adkoMuCfzSjHJ9ZDocQn0GnVldSCkLL3eVR5A_jafwM,2552
|
90
90
|
schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
|
91
91
|
schemathesis/generation/modes.py,sha256=Q1fhjWr3zxabU5qdtLvKfpMFZJAwlW9pnxgenjeXTyU,481
|
92
92
|
schemathesis/generation/overrides.py,sha256=OBWqDQPreiliaf2M-oyXppVKHoJkCRzxtwSJx1b6AFw,3759
|
93
93
|
schemathesis/generation/hypothesis/__init__.py,sha256=SVwM-rx07jPZzms0idWYACgUtWAxh49HRuTnaQ__zf0,1549
|
94
|
-
schemathesis/generation/hypothesis/builder.py,sha256=
|
94
|
+
schemathesis/generation/hypothesis/builder.py,sha256=ujPp9ByUfNYdxWyKoJlxE0h8pAVBpmNJwWIi9MnR968,34824
|
95
95
|
schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8EHc-PWT4NRBq4NI0Rs,1409
|
96
96
|
schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
|
97
97
|
schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
|
98
98
|
schemathesis/generation/hypothesis/strategies.py,sha256=RurE81E06d99YKG48dizy9346ayfNswYTt38zewmGgw,483
|
99
99
|
schemathesis/generation/stateful/__init__.py,sha256=s7jiJEnguIj44IsRyMi8afs-8yjIUuBbzW58bH5CHjs,1042
|
100
|
-
schemathesis/generation/stateful/state_machine.py,sha256=
|
100
|
+
schemathesis/generation/stateful/state_machine.py,sha256=3oAGpn46adNJx3sp5ym9e30SyYOjJGiEqenDZ5gWtBY,8803
|
101
101
|
schemathesis/graphql/__init__.py,sha256=_eO6MAPHGgiADVGRntnwtPxmuvk666sAh-FAU4cG9-0,326
|
102
102
|
schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzYo,3186
|
103
103
|
schemathesis/graphql/loaders.py,sha256=2tgG4HIvFmjHLr_KexVXnT8hSBM-dKG_fuXTZgE97So,9445
|
@@ -134,7 +134,7 @@ schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKR
|
|
134
134
|
schemathesis/specs/openapi/parameters.py,sha256=ifu_QQCMUzsUHQAkvsOvLuokns6CzesssmQ3Nd3zxII,14594
|
135
135
|
schemathesis/specs/openapi/patterns.py,sha256=cBj8W4wn7VLJd4nABaIH5f502-zBDiqljxLgPWUn-50,15609
|
136
136
|
schemathesis/specs/openapi/references.py,sha256=40YcDExPLR2B8EOwt-Csw-5MYFi2xj_DXf91J0Pc9d4,8855
|
137
|
-
schemathesis/specs/openapi/schemas.py,sha256=
|
137
|
+
schemathesis/specs/openapi/schemas.py,sha256=FXD6yLindLNtjiW5D_GllWxfMAigSKjpjl8_GbqJXxE,52557
|
138
138
|
schemathesis/specs/openapi/security.py,sha256=6UWYMhL-dPtkTineqqBFNKca1i4EuoTduw-EOLeE0aQ,7149
|
139
139
|
schemathesis/specs/openapi/serialization.py,sha256=VdDLmeHqxlWM4cxQQcCkvrU6XurivolwEEaT13ohelA,11972
|
140
140
|
schemathesis/specs/openapi/utils.py,sha256=ER4vJkdFVDIE7aKyxyYatuuHVRNutytezgE52pqZNE8,900
|
@@ -154,11 +154,11 @@ schemathesis/specs/openapi/stateful/links.py,sha256=h5q40jUbcIk5DS_Tih1cvFJxS_Qx
|
|
154
154
|
schemathesis/transport/__init__.py,sha256=6yg_RfV_9L0cpA6qpbH-SL9_3ggtHQji9CZrpIkbA6s,5321
|
155
155
|
schemathesis/transport/asgi.py,sha256=qTClt6oT_xUEWnRHokACN_uqCNNUZrRPT6YG0PjbElY,926
|
156
156
|
schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEzXd0o,4743
|
157
|
-
schemathesis/transport/requests.py,sha256=
|
157
|
+
schemathesis/transport/requests.py,sha256=46aplzhSmBupegPNMawma-iJWCegWkEd6mzdWLTpgM4,10742
|
158
158
|
schemathesis/transport/serialization.py,sha256=igUXKZ_VJ9gV7P0TUc5PDQBJXl_s0kK9T3ljGWWvo6E,10339
|
159
159
|
schemathesis/transport/wsgi.py,sha256=KoAfvu6RJtzyj24VGB8e-Iaa9smpgXJ3VsM8EgAz2tc,6152
|
160
|
-
schemathesis-4.0.
|
161
|
-
schemathesis-4.0.
|
162
|
-
schemathesis-4.0.
|
163
|
-
schemathesis-4.0.
|
164
|
-
schemathesis-4.0.
|
160
|
+
schemathesis-4.0.16.dist-info/METADATA,sha256=Cy4KK06pQyWGPssr3PsSFtofmnMdsSgSNNjy3LHoxuw,8472
|
161
|
+
schemathesis-4.0.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
162
|
+
schemathesis-4.0.16.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
|
163
|
+
schemathesis-4.0.16.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
|
164
|
+
schemathesis-4.0.16.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|