schemathesis 3.27.0__py3-none-any.whl → 3.27.1__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 +1 -1
- schemathesis/cli/__main__.py +4 -0
- schemathesis/generation/__init__.py +14 -2
- schemathesis/runner/impl/core.py +1 -4
- schemathesis/specs/openapi/_hypothesis.py +16 -5
- schemathesis/transports/__init__.py +4 -3
- {schemathesis-3.27.0.dist-info → schemathesis-3.27.1.dist-info}/METADATA +2 -3
- {schemathesis-3.27.0.dist-info → schemathesis-3.27.1.dist-info}/RECORD +11 -10
- {schemathesis-3.27.0.dist-info → schemathesis-3.27.1.dist-info}/WHEEL +0 -0
- {schemathesis-3.27.0.dist-info → schemathesis-3.27.1.dist-info}/entry_points.txt +0 -0
- {schemathesis-3.27.0.dist-info → schemathesis-3.27.1.dist-info}/licenses/LICENSE +0 -0
schemathesis/__init__.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import Any
|
|
|
3
3
|
|
|
4
4
|
from . import auths, checks, experimental, contrib, fixups, graphql, hooks, runner, serializers, targets # noqa: E402
|
|
5
5
|
from ._lazy_import import lazy_import
|
|
6
|
-
from .generation import DataGenerationMethod, GenerationConfig # noqa: E402
|
|
6
|
+
from .generation import DataGenerationMethod, GenerationConfig, HeaderConfig # noqa: E402
|
|
7
7
|
from .constants import SCHEMATHESIS_VERSION # noqa: E402
|
|
8
8
|
from .models import Case # noqa: E402
|
|
9
9
|
from .specs import openapi # noqa: E402
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import random
|
|
3
|
-
from dataclasses import dataclass
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
4
|
from enum import Enum
|
|
5
|
-
from typing import Union, Iterable
|
|
5
|
+
from typing import Union, Iterable, TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from hypothesis.strategies import SearchStrategy
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class DataGenerationMethod(str, Enum):
|
|
@@ -58,6 +61,13 @@ def generate_random_case_id(length: int = 6) -> str:
|
|
|
58
61
|
return output
|
|
59
62
|
|
|
60
63
|
|
|
64
|
+
@dataclass
|
|
65
|
+
class HeaderConfig:
|
|
66
|
+
"""Configuration for generating headers."""
|
|
67
|
+
|
|
68
|
+
strategy: SearchStrategy[str] | None = None
|
|
69
|
+
|
|
70
|
+
|
|
61
71
|
@dataclass
|
|
62
72
|
class GenerationConfig:
|
|
63
73
|
"""Holds various configuration options relevant for data generation."""
|
|
@@ -66,3 +76,5 @@ class GenerationConfig:
|
|
|
66
76
|
allow_x00: bool = True
|
|
67
77
|
# Generate strings using the given codec
|
|
68
78
|
codec: str | None = "utf-8"
|
|
79
|
+
# Header generation configuration
|
|
80
|
+
headers: HeaderConfig = field(default_factory=HeaderConfig)
|
schemathesis/runner/impl/core.py
CHANGED
|
@@ -299,10 +299,7 @@ def run_probes(schema: BaseSchema, config: probes.ProbeConfig) -> list[probes.Pr
|
|
|
299
299
|
if isinstance(result.probe, probes.NullByteInHeader) and result.is_failure:
|
|
300
300
|
from ...specs.openapi._hypothesis import HEADER_FORMAT, header_values
|
|
301
301
|
|
|
302
|
-
formats.register(
|
|
303
|
-
HEADER_FORMAT,
|
|
304
|
-
header_values(blacklist_characters="\n\r\x00").map(str.lstrip),
|
|
305
|
-
)
|
|
302
|
+
formats.register(HEADER_FORMAT, header_values(blacklist_characters="\n\r\x00"))
|
|
306
303
|
return results
|
|
307
304
|
|
|
308
305
|
|
|
@@ -45,7 +45,8 @@ StrategyFactory = Callable[[Dict[str, Any], str, str, Optional[str], GenerationC
|
|
|
45
45
|
def header_values(blacklist_characters: str = "\n\r") -> st.SearchStrategy[str]:
|
|
46
46
|
return st.text(
|
|
47
47
|
alphabet=st.characters(min_codepoint=0, max_codepoint=255, blacklist_characters=blacklist_characters)
|
|
48
|
-
|
|
48
|
+
# Header values with leading non-visible chars can't be sent with `requests`
|
|
49
|
+
).map(str.lstrip)
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
@lru_cache
|
|
@@ -67,8 +68,7 @@ def get_default_format_strategies() -> dict[str, st.SearchStrategy]:
|
|
|
67
68
|
"_header_name": st.text(
|
|
68
69
|
min_size=1, alphabet=st.sampled_from("!#$%&'*+-.^_`|~" + string.digits + string.ascii_letters)
|
|
69
70
|
),
|
|
70
|
-
|
|
71
|
-
HEADER_FORMAT: header_value.map(str.lstrip),
|
|
71
|
+
HEADER_FORMAT: header_value,
|
|
72
72
|
"_basic_auth": st.tuples(latin1_text, latin1_text).map(make_basic_auth_str),
|
|
73
73
|
"_bearer_auth": header_value.map("Bearer {}".format),
|
|
74
74
|
}
|
|
@@ -425,6 +425,15 @@ def jsonify_python_specific_types(value: dict[str, Any]) -> dict[str, Any]:
|
|
|
425
425
|
return value
|
|
426
426
|
|
|
427
427
|
|
|
428
|
+
def _build_custom_formats(
|
|
429
|
+
custom_formats: dict[str, st.SearchStrategy] | None, generation_config: GenerationConfig
|
|
430
|
+
) -> dict[str, st.SearchStrategy]:
|
|
431
|
+
custom_formats = {**get_default_format_strategies(), **STRING_FORMATS, **(custom_formats or {})}
|
|
432
|
+
if generation_config.headers.strategy is not None:
|
|
433
|
+
custom_formats[HEADER_FORMAT] = generation_config.headers.strategy
|
|
434
|
+
return custom_formats
|
|
435
|
+
|
|
436
|
+
|
|
428
437
|
def make_positive_strategy(
|
|
429
438
|
schema: dict[str, Any],
|
|
430
439
|
operation_name: str,
|
|
@@ -441,9 +450,10 @@ def make_positive_strategy(
|
|
|
441
450
|
for sub_schema in schema.get("properties", {}).values():
|
|
442
451
|
if list(sub_schema) == ["type"] and sub_schema["type"] == "string":
|
|
443
452
|
sub_schema.setdefault("format", HEADER_FORMAT)
|
|
453
|
+
custom_formats = _build_custom_formats(custom_formats, generation_config)
|
|
444
454
|
return from_schema(
|
|
445
455
|
schema,
|
|
446
|
-
custom_formats=
|
|
456
|
+
custom_formats=custom_formats,
|
|
447
457
|
allow_x00=generation_config.allow_x00,
|
|
448
458
|
codec=generation_config.codec,
|
|
449
459
|
)
|
|
@@ -462,12 +472,13 @@ def make_negative_strategy(
|
|
|
462
472
|
generation_config: GenerationConfig,
|
|
463
473
|
custom_formats: dict[str, st.SearchStrategy] | None = None,
|
|
464
474
|
) -> st.SearchStrategy:
|
|
475
|
+
custom_formats = _build_custom_formats(custom_formats, generation_config)
|
|
465
476
|
return negative_schema(
|
|
466
477
|
schema,
|
|
467
478
|
operation_name=operation_name,
|
|
468
479
|
location=location,
|
|
469
480
|
media_type=media_type,
|
|
470
|
-
custom_formats=
|
|
481
|
+
custom_formats=custom_formats,
|
|
471
482
|
generation_config=generation_config,
|
|
472
483
|
)
|
|
473
484
|
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import base64
|
|
4
4
|
import time
|
|
5
|
+
from inspect import iscoroutinefunction
|
|
5
6
|
from contextlib import contextmanager
|
|
6
7
|
from dataclasses import dataclass
|
|
7
8
|
from datetime import timedelta
|
|
@@ -31,11 +32,11 @@ def serialize_payload(payload: bytes) -> str:
|
|
|
31
32
|
|
|
32
33
|
def get(app: Any) -> Transport:
|
|
33
34
|
"""Get transport to send the data to the application."""
|
|
34
|
-
from starlette.applications import Starlette
|
|
35
|
-
|
|
36
35
|
if app is None:
|
|
37
36
|
return RequestsTransport()
|
|
38
|
-
if
|
|
37
|
+
if iscoroutinefunction(app) or (
|
|
38
|
+
hasattr(app, "__call__") and iscoroutinefunction(app.__call__) # noqa: B004
|
|
39
|
+
):
|
|
39
40
|
return ASGITransport(app=app)
|
|
40
41
|
return WSGITransport(app=app)
|
|
41
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: schemathesis
|
|
3
|
-
Version: 3.27.
|
|
3
|
+
Version: 3.27.1
|
|
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://schemathesis.readthedocs.io/en/stable/changelog.html
|
|
@@ -28,7 +28,6 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
28
28
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
29
29
|
Classifier: Topic :: Software Development :: Testing
|
|
30
30
|
Requires-Python: >=3.8
|
|
31
|
-
Requires-Dist: anyio<4
|
|
32
31
|
Requires-Dist: backoff<3.0,>=2.1.2
|
|
33
32
|
Requires-Dist: click<9.0,>=7.0
|
|
34
33
|
Requires-Dist: colorama<1.0,>=0.4
|
|
@@ -44,7 +43,7 @@ Requires-Dist: pytest-subtests<0.8.0,>=0.2.1
|
|
|
44
43
|
Requires-Dist: pytest<9,>=4.6.4
|
|
45
44
|
Requires-Dist: pyyaml<7.0,>=5.1
|
|
46
45
|
Requires-Dist: requests<3,>=2.22
|
|
47
|
-
Requires-Dist: starlette-testclient<1
|
|
46
|
+
Requires-Dist: starlette-testclient<1,>=0.4.1
|
|
48
47
|
Requires-Dist: starlette<1,>=0.13
|
|
49
48
|
Requires-Dist: tomli-w<2.0,>=1.0.0
|
|
50
49
|
Requires-Dist: tomli<3.0,>=2.0.1
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
schemathesis/__init__.py,sha256=
|
|
1
|
+
schemathesis/__init__.py,sha256=zAa981OnVdIdjiETPP5a5vZL8QXAh2HbTWj8iEoxKC4,1984
|
|
2
2
|
schemathesis/_compat.py,sha256=VizWR0QAVj4l7WZautNe_zmo3AJ7WBl2zrJQOfJAQtk,1837
|
|
3
3
|
schemathesis/_dependency_versions.py,sha256=InIv6MZmuRVHc_9FxAiRg7_dY-vuF0jT69FBxrBLK6U,879
|
|
4
4
|
schemathesis/_hypothesis.py,sha256=O3rfMbT0rChFONMUsYmMEGV9nPG5cHd_6v9NhWDI_IQ,10763
|
|
@@ -28,6 +28,7 @@ schemathesis/throttling.py,sha256=uwhL4XWPWAU8HECg0NhibfCMn5dT7NElTx3fdL3Mmcc,10
|
|
|
28
28
|
schemathesis/types.py,sha256=AglR5M0bce-YXeDRkweToXTP0GjNOWVjS_mIsxLobwc,919
|
|
29
29
|
schemathesis/utils.py,sha256=4HXvHysnHp-Uz2HfNgLfW5F5VjL-mtixrjjzRCEJhYo,5233
|
|
30
30
|
schemathesis/cli/__init__.py,sha256=oTBqweV5CP681LqRFdRXtkd0VyYoG_xUKshkKEPnqIQ,64871
|
|
31
|
+
schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
|
|
31
32
|
schemathesis/cli/callbacks.py,sha256=HmD0WmSYf5x8v4xeZdOKzy_8CEk23NitUlL8JQ7LHdQ,14950
|
|
32
33
|
schemathesis/cli/cassettes.py,sha256=1ucgYyOZiNu44uOv044FdfKTzQolUyhAM2onk4m3MD0,12988
|
|
33
34
|
schemathesis/cli/constants.py,sha256=XoezT0_fHuiOY2e--cmBUhNieJsepcUoW8e48QuLSDI,1544
|
|
@@ -56,7 +57,7 @@ schemathesis/extra/pytest_plugin.py,sha256=44RRkjkN1JupWu0muq9B5b3K9goucYndB394Q
|
|
|
56
57
|
schemathesis/fixups/__init__.py,sha256=iTpOm-cwyZQRglbWRJHxj3k7WO9a4a-MCq-UDQa6U0Y,966
|
|
57
58
|
schemathesis/fixups/fast_api.py,sha256=-gjYNSUtiKl7cKgyQ_rON0Oo_sGm6r7rOQDH0ahG32A,1322
|
|
58
59
|
schemathesis/fixups/utf8_bom.py,sha256=ttzPOaJb6K7QtNAbIZ_TWrrm0N9FylS8QzO6zI0jXgY,764
|
|
59
|
-
schemathesis/generation/__init__.py,sha256=
|
|
60
|
+
schemathesis/generation/__init__.py,sha256=UXRrDTaUEX29VEK9bLqVi_xVzyNNqul3WhpLh1za90M,2277
|
|
60
61
|
schemathesis/internal/__init__.py,sha256=93HcdG3LF0BbQKbCteOsFMa1w6nXl8yTmx87QLNJOik,161
|
|
61
62
|
schemathesis/internal/copy.py,sha256=xsC7RyrFa9KadMsj9ai_aAy0XZg0oplz3cFZCka_2fg,459
|
|
62
63
|
schemathesis/internal/datetime.py,sha256=zPLBL0XXLNfP-KYel3H2m8pnsxjsA_4d-zTOhJg2EPQ,136
|
|
@@ -70,7 +71,7 @@ schemathesis/runner/events.py,sha256=eZc4TT8C8mWCMr9h4JvlijvQQ-x8wFry8LntdsYIL-A
|
|
|
70
71
|
schemathesis/runner/probes.py,sha256=t_B38-ljy-p3Odw-dqcZUVIjYTPwBvac8KE5GaLnz4M,5546
|
|
71
72
|
schemathesis/runner/serialization.py,sha256=7DBve7E6JAbAHH5npzjME7lFnysKCc9dPXMmdIIYrNI,16667
|
|
72
73
|
schemathesis/runner/impl/__init__.py,sha256=1E2iME8uthYPBh9MjwVBCTFV-P3fi7AdphCCoBBspjs,199
|
|
73
|
-
schemathesis/runner/impl/core.py,sha256=
|
|
74
|
+
schemathesis/runner/impl/core.py,sha256=Y8WyKEUeuEs0xi9hWmEA63a39-NO7L6I5hQRhwo9JBQ,39621
|
|
74
75
|
schemathesis/runner/impl/solo.py,sha256=Y_tNhVBVxcuxv65hN0FjxLlVSC41ebHMOM1xSzVrNk8,3358
|
|
75
76
|
schemathesis/runner/impl/threadpool.py,sha256=2-2Wvw7msezZtenZY5vU_x3FGLLVlH-ywvhU9hTwAAo,15073
|
|
76
77
|
schemathesis/service/__init__.py,sha256=cDVTCFD1G-vvhxZkJUwiToTAEQ-0ByIoqwXvJBCf_V8,472
|
|
@@ -94,7 +95,7 @@ schemathesis/specs/graphql/scalars.py,sha256=W5oj6AcjiXpR-Z6eSSp1oPWl0mjH2NF-w87
|
|
|
94
95
|
schemathesis/specs/graphql/schemas.py,sha256=6BlTF9iAongsDxzy4_l85YjDob2QzpB0Vt7mlbIUxaw,12637
|
|
95
96
|
schemathesis/specs/graphql/validation.py,sha256=SqQbj9uymGUQxlHXc8HkQccIq25uwP5CvLF1zReb1Xg,1636
|
|
96
97
|
schemathesis/specs/openapi/__init__.py,sha256=HDcx3bqpa6qWPpyMrxAbM3uTo0Lqpg-BUNZhDJSJKnw,279
|
|
97
|
-
schemathesis/specs/openapi/_hypothesis.py,sha256=
|
|
98
|
+
schemathesis/specs/openapi/_hypothesis.py,sha256=Qrm6Po2W2wsxZAlLFRUwq0svO8SmQp-5InCFa2cwYaw,23275
|
|
98
99
|
schemathesis/specs/openapi/checks.py,sha256=1WB_UGNqptfJThWLUNbds1Q-IzOGbbHCOYPIhBYk-zs,5411
|
|
99
100
|
schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
|
|
100
101
|
schemathesis/specs/openapi/converter.py,sha256=9TKeKvNi9MVvoNMfqoPz_cODO8oNrMSTXTOwLLfjD_Q,2799
|
|
@@ -126,13 +127,13 @@ schemathesis/specs/openapi/stateful/__init__.py,sha256=R8RhPJD3rDzqL4eA9jSnUwh9Q
|
|
|
126
127
|
schemathesis/specs/openapi/stateful/links.py,sha256=cSIwho2Hroty6au-gyCD-OwqnuCcIpnIIHU6FvF0SwA,3533
|
|
127
128
|
schemathesis/stateful/__init__.py,sha256=T7rvhzftfl3wumEsir33DBBzCTK2PtRp9CxBxMLdMSE,4693
|
|
128
129
|
schemathesis/stateful/state_machine.py,sha256=ZcKpbvEl1QGhVOYnA7Ow6zkuFHtEPDAyCjroPrj-FgU,11343
|
|
129
|
-
schemathesis/transports/__init__.py,sha256=
|
|
130
|
+
schemathesis/transports/__init__.py,sha256=IHQaob4pLHPP0zXXJukWEQBpV4aSIhGPHHMm0up8x64,11287
|
|
130
131
|
schemathesis/transports/auth.py,sha256=ZKFku9gjhIG6445qNC2p_64Yt9Iz_4azbvja8AMptBk,404
|
|
131
132
|
schemathesis/transports/content_types.py,sha256=xU8RZWxz-CyWRqQTI2fGYQacB7KasoY7LL_bxPQdyPY,2144
|
|
132
133
|
schemathesis/transports/headers.py,sha256=EDxpm8su0AuhyqZUkMex-OFZMAJN_5NHah7fDT2HDZE,989
|
|
133
134
|
schemathesis/transports/responses.py,sha256=j_-udvWbmi6XtEYmpdX8WoFnlrQ6-i3PSBizfozRjQI,1673
|
|
134
|
-
schemathesis-3.27.
|
|
135
|
-
schemathesis-3.27.
|
|
136
|
-
schemathesis-3.27.
|
|
137
|
-
schemathesis-3.27.
|
|
138
|
-
schemathesis-3.27.
|
|
135
|
+
schemathesis-3.27.1.dist-info/METADATA,sha256=GtcBreI2a4R9b3KL_eS-QQb57LTmQckmsQ_vkPTIdDs,16242
|
|
136
|
+
schemathesis-3.27.1.dist-info/WHEEL,sha256=hKi7AIIx6qfnsRbr087vpeJnrVUuDokDHZacPPMW7-Y,87
|
|
137
|
+
schemathesis-3.27.1.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
|
|
138
|
+
schemathesis-3.27.1.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
|
|
139
|
+
schemathesis-3.27.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|