schemathesis 4.0.1__py3-none-any.whl → 4.0.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.
Files changed (34) hide show
  1. schemathesis/cli/commands/run/handlers/cassettes.py +23 -5
  2. schemathesis/cli/commands/run/handlers/junitxml.py +8 -2
  3. schemathesis/cli/commands/run/handlers/output.py +15 -4
  4. schemathesis/core/__init__.py +2 -0
  5. schemathesis/engine/control.py +10 -2
  6. schemathesis/engine/core.py +6 -0
  7. schemathesis/engine/phases/__init__.py +12 -2
  8. schemathesis/engine/phases/probes.py +25 -4
  9. schemathesis/generation/case.py +12 -6
  10. schemathesis/generation/hypothesis/builder.py +35 -6
  11. schemathesis/generation/meta.py +4 -0
  12. schemathesis/generation/overrides.py +2 -0
  13. schemathesis/hooks.py +2 -0
  14. schemathesis/pytest/lazy.py +12 -2
  15. schemathesis/pytest/plugin.py +22 -14
  16. schemathesis/schemas.py +10 -4
  17. schemathesis/specs/graphql/_cache.py +13 -3
  18. schemathesis/specs/graphql/schemas.py +2 -0
  19. schemathesis/specs/openapi/_hypothesis.py +1 -1
  20. schemathesis/specs/openapi/examples.py +4 -0
  21. schemathesis/specs/openapi/expressions/extractors.py +2 -0
  22. schemathesis/specs/openapi/expressions/lexer.py +2 -0
  23. schemathesis/specs/openapi/expressions/nodes.py +35 -4
  24. schemathesis/specs/openapi/negative/__init__.py +2 -0
  25. schemathesis/specs/openapi/negative/mutations.py +2 -0
  26. schemathesis/specs/openapi/stateful/links.py +1 -0
  27. schemathesis/transport/prepare.py +0 -2
  28. schemathesis/transport/requests.py +38 -5
  29. schemathesis/transport/wsgi.py +11 -1
  30. {schemathesis-4.0.1.dist-info → schemathesis-4.0.3.dist-info}/METADATA +2 -2
  31. {schemathesis-4.0.1.dist-info → schemathesis-4.0.3.dist-info}/RECORD +34 -34
  32. {schemathesis-4.0.1.dist-info → schemathesis-4.0.3.dist-info}/WHEEL +0 -0
  33. {schemathesis-4.0.1.dist-info → schemathesis-4.0.3.dist-info}/entry_points.txt +0 -0
  34. {schemathesis-4.0.1.dist-info → schemathesis-4.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,7 @@ import datetime
4
4
  import json
5
5
  import sys
6
6
  import threading
7
- from dataclasses import dataclass, field
7
+ from dataclasses import dataclass
8
8
  from http.cookies import SimpleCookie
9
9
  from pathlib import Path
10
10
  from queue import Queue
@@ -35,10 +35,23 @@ class CassetteWriter(EventHandler):
35
35
  format: ReportFormat
36
36
  path: Path
37
37
  config: ProjectConfig
38
- queue: Queue = field(default_factory=Queue)
39
- worker: threading.Thread = field(init=False)
38
+ queue: Queue
39
+ worker: threading.Thread
40
+
41
+ __slots__ = ("format", "path", "config", "queue", "worker")
42
+
43
+ def __init__(
44
+ self,
45
+ format: ReportFormat,
46
+ path: Path,
47
+ config: ProjectConfig,
48
+ queue: Queue | None = None,
49
+ ) -> None:
50
+ self.format = format
51
+ self.path = path
52
+ self.config = config
53
+ self.queue = queue or Queue()
40
54
 
41
- def __post_init__(self) -> None:
42
55
  kwargs = {
43
56
  "path": self.path,
44
57
  "config": self.config,
@@ -49,7 +62,12 @@ class CassetteWriter(EventHandler):
49
62
  writer = har_writer
50
63
  else:
51
64
  writer = vcr_writer
52
- self.worker = threading.Thread(name="SchemathesisCassetteWriter", target=writer, kwargs=kwargs)
65
+
66
+ self.worker = threading.Thread(
67
+ name="SchemathesisCassetteWriter",
68
+ target=writer,
69
+ kwargs=kwargs,
70
+ )
53
71
  self.worker.start()
54
72
 
55
73
  def start(self, ctx: ExecutionContext) -> None:
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import platform
4
- from dataclasses import dataclass, field
4
+ from dataclasses import dataclass
5
5
  from pathlib import Path
6
6
  from typing import Iterable
7
7
 
@@ -16,7 +16,13 @@ from schemathesis.engine import Status, events
16
16
  @dataclass
17
17
  class JunitXMLHandler(EventHandler):
18
18
  path: Path
19
- test_cases: dict = field(default_factory=dict)
19
+ test_cases: dict
20
+
21
+ __slots__ = ("path", "test_cases")
22
+
23
+ def __init__(self, path: Path, test_cases: dict | None = None) -> None:
24
+ self.path = path
25
+ self.test_cases = test_cases or {}
20
26
 
21
27
  def handle_event(self, ctx: ExecutionContext, event: events.EngineEvent) -> None:
22
28
  if isinstance(event, events.ScenarioFinished):
@@ -324,10 +324,21 @@ class ProbingProgressManager:
324
324
 
325
325
  @dataclass
326
326
  class WarningData:
327
- missing_auth: dict[int, set[str]] = field(default_factory=dict)
328
- missing_test_data: set[str] = field(default_factory=set)
329
- # operations that only returned 4xx
330
- validation_mismatch: set[str] = field(default_factory=set)
327
+ missing_auth: dict[int, set[str]]
328
+ missing_test_data: set[str]
329
+ validation_mismatch: set[str]
330
+
331
+ __slots__ = ("missing_auth", "missing_test_data", "validation_mismatch")
332
+
333
+ def __init__(
334
+ self,
335
+ missing_auth: dict[int, set[str]] | None = None,
336
+ missing_test_data: set[str] | None = None,
337
+ validation_mismatch: set[str] | None = None,
338
+ ) -> None:
339
+ self.missing_auth = missing_auth or {}
340
+ self.missing_test_data = missing_test_data or set()
341
+ self.validation_mismatch = validation_mismatch or set()
331
342
 
332
343
  @property
333
344
  def is_empty(self) -> bool:
@@ -28,6 +28,8 @@ class Specification:
28
28
  kind: SpecificationKind
29
29
  version: str
30
30
 
31
+ __slots__ = ("kind", "version")
32
+
31
33
  @classmethod
32
34
  def openapi(cls, version: str) -> Specification:
33
35
  return cls(kind=SpecificationKind.OPENAPI, version=version)
@@ -12,8 +12,16 @@ class ExecutionControl:
12
12
 
13
13
  stop_event: threading.Event
14
14
  max_failures: int | None
15
- _failures_counter: int = 0
16
- has_reached_the_failure_limit: bool = False
15
+ _failures_counter: int
16
+ has_reached_the_failure_limit: bool
17
+
18
+ __slots__ = ("stop_event", "max_failures", "_failures_counter", "has_reached_the_failure_limit")
19
+
20
+ def __init__(self, stop_event: threading.Event, max_failures: int | None) -> None:
21
+ self.stop_event = stop_event
22
+ self.max_failures = max_failures
23
+ self._failures_counter = 0
24
+ self.has_reached_the_failure_limit = False
17
25
 
18
26
  @property
19
27
  def is_stopped(self) -> bool:
@@ -18,6 +18,8 @@ from .phases import Phase, PhaseName, PhaseSkipReason
18
18
  class Engine:
19
19
  schema: BaseSchema
20
20
 
21
+ __slots__ = ("schema",)
22
+
21
23
  def execute(self) -> EventStream:
22
24
  """Execute all test phases."""
23
25
  # Unregister auth if explicitly provided
@@ -103,6 +105,8 @@ class ExecutionPlan:
103
105
 
104
106
  phases: Sequence[Phase]
105
107
 
108
+ __slots__ = ("phases",)
109
+
106
110
  def execute(self, engine: EngineContext) -> EventGenerator:
107
111
  """Execute all phases in sequence."""
108
112
  yield events.EngineStarted()
@@ -150,6 +154,8 @@ class EventStream:
150
154
  generator: EventGenerator
151
155
  stop_event: threading.Event
152
156
 
157
+ __slots__ = ("generator", "stop_event")
158
+
153
159
  def __next__(self) -> events.EngineEvent:
154
160
  return next(self.generator)
155
161
 
@@ -60,8 +60,18 @@ class Phase:
60
60
 
61
61
  name: PhaseName
62
62
  is_supported: bool
63
- is_enabled: bool = True
64
- skip_reason: PhaseSkipReason | None = None
63
+ is_enabled: bool
64
+ skip_reason: PhaseSkipReason | None
65
+
66
+ __slots__ = ("name", "is_supported", "is_enabled", "skip_reason")
67
+
68
+ def __init__(
69
+ self, name: PhaseName, is_supported: bool, is_enabled: bool = True, skip_reason: PhaseSkipReason | None = None
70
+ ) -> None:
71
+ self.name = name
72
+ self.is_supported = is_supported
73
+ self.is_enabled = is_enabled
74
+ self.skip_reason = skip_reason
65
75
 
66
76
  def should_execute(self, ctx: EngineContext) -> bool:
67
77
  """Determine if phase should run based on context & configuration."""
@@ -68,6 +68,8 @@ class Probe:
68
68
 
69
69
  name: str
70
70
 
71
+ __slots__ = ("name",)
72
+
71
73
  def prepare_request(
72
74
  self, session: requests.Session, request: requests.Request, schema: BaseSchema
73
75
  ) -> requests.PreparedRequest:
@@ -92,9 +94,25 @@ class ProbeOutcome(str, enum.Enum):
92
94
  class ProbeRun:
93
95
  probe: Probe
94
96
  outcome: ProbeOutcome
95
- request: requests.PreparedRequest | None = None
96
- response: requests.Response | None = None
97
- error: Exception | None = None
97
+ request: requests.PreparedRequest | None
98
+ response: requests.Response | None
99
+ error: Exception | None
100
+
101
+ __slots__ = ("probe", "outcome", "request", "response", "error")
102
+
103
+ def __init__(
104
+ self,
105
+ probe: Probe,
106
+ outcome: ProbeOutcome,
107
+ request: requests.PreparedRequest | None = None,
108
+ response: requests.Response | None = None,
109
+ error: Exception | None = None,
110
+ ) -> None:
111
+ self.probe = probe
112
+ self.outcome = outcome
113
+ self.request = request
114
+ self.response = response
115
+ self.error = error
98
116
 
99
117
  @property
100
118
  def is_failure(self) -> bool:
@@ -105,7 +123,10 @@ class ProbeRun:
105
123
  class NullByteInHeader(Probe):
106
124
  """Support NULL bytes in headers."""
107
125
 
108
- name: str = "Supports NULL byte in headers"
126
+ __slots__ = ("name",)
127
+
128
+ def __init__(self) -> None:
129
+ self.name = "Supports NULL byte in headers"
109
130
 
110
131
  def prepare_request(
111
132
  self, session: requests.Session, request: requests.Request, schema: BaseSchema
@@ -244,19 +244,25 @@ class Case:
244
244
 
245
245
  response = Response.from_any(response)
246
246
 
247
+ config = self.operation.schema.config.checks_config_for(
248
+ operation=self.operation, phase=self.meta.phase.name.value if self.meta is not None else None
249
+ )
250
+ if not checks:
251
+ # Checks are not specified explicitly, derive from the config
252
+ checks = []
253
+ for check in CHECKS.get_all():
254
+ name = check.__name__
255
+ if config.get_by_name(name=name).enabled:
256
+ checks.append(check)
247
257
  checks = [
248
- check
249
- for check in list(checks or CHECKS.get_all()) + list(additional_checks or [])
250
- if check not in set(excluded_checks or [])
258
+ check for check in list(checks) + list(additional_checks or []) if check not in set(excluded_checks or [])
251
259
  ]
252
260
 
253
261
  ctx = CheckContext(
254
262
  override=self._override,
255
263
  auth=None,
256
264
  headers=CaseInsensitiveDict(headers) if headers else None,
257
- config=self.operation.schema.config.checks_config_for(
258
- operation=self.operation, phase=self.meta.phase.name.value if self.meta is not None else None
259
- ),
265
+ config=config,
260
266
  transport_kwargs=transport_kwargs,
261
267
  recorder=None,
262
268
  )
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- from dataclasses import dataclass, field
4
+ from dataclasses import dataclass
5
5
  from enum import Enum
6
6
  from functools import wraps
7
7
  from itertools import combinations
@@ -53,11 +53,39 @@ class HypothesisTestMode(str, Enum):
53
53
  class HypothesisTestConfig:
54
54
  project: ProjectConfig
55
55
  modes: list[HypothesisTestMode]
56
- settings: hypothesis.settings | None = None
57
- seed: int | None = None
58
- as_strategy_kwargs: dict[str, Any] = field(default_factory=dict)
59
- given_args: tuple[GivenInput, ...] = ()
60
- given_kwargs: dict[str, GivenInput] = field(default_factory=dict)
56
+ settings: hypothesis.settings | None
57
+ seed: int | None
58
+ as_strategy_kwargs: dict[str, Any]
59
+ given_args: tuple[GivenInput, ...]
60
+ given_kwargs: dict[str, GivenInput]
61
+
62
+ __slots__ = (
63
+ "project",
64
+ "modes",
65
+ "settings",
66
+ "seed",
67
+ "as_strategy_kwargs",
68
+ "given_args",
69
+ "given_kwargs",
70
+ )
71
+
72
+ def __init__(
73
+ self,
74
+ project: ProjectConfig,
75
+ modes: list[HypothesisTestMode],
76
+ settings: hypothesis.settings | None = None,
77
+ seed: int | None = None,
78
+ as_strategy_kwargs: dict[str, Any] | None = None,
79
+ given_args: tuple[GivenInput, ...] = (),
80
+ given_kwargs: dict[str, GivenInput] | None = None,
81
+ ) -> None:
82
+ self.project = project
83
+ self.modes = modes
84
+ self.settings = settings
85
+ self.seed = seed
86
+ self.as_strategy_kwargs = as_strategy_kwargs or {}
87
+ self.given_args = given_args
88
+ self.given_kwargs = given_kwargs or {}
61
89
 
62
90
 
63
91
  def create_test(
@@ -393,6 +421,7 @@ class Template:
393
421
  class TemplateValue:
394
422
  kwargs: dict[str, Any]
395
423
  components: dict[ComponentKind, ComponentInfo]
424
+
396
425
  __slots__ = ("kwargs", "components")
397
426
 
398
427
 
@@ -37,11 +37,15 @@ class ComponentInfo:
37
37
  class GeneratePhaseData:
38
38
  """Metadata specific to generate phase."""
39
39
 
40
+ __slots__ = ()
41
+
40
42
 
41
43
  @dataclass
42
44
  class ExplicitPhaseData:
43
45
  """Metadata specific to explicit phase."""
44
46
 
47
+ __slots__ = ()
48
+
45
49
 
46
50
  @dataclass
47
51
  class CoveragePhaseData:
@@ -22,6 +22,8 @@ class Override:
22
22
  cookies: dict[str, str]
23
23
  path_parameters: dict[str, str]
24
24
 
25
+ __slots__ = ("query", "headers", "cookies", "path_parameters")
26
+
25
27
  def items(self) -> Iterator[tuple[str, dict[str, str]]]:
26
28
  for key, value in (
27
29
  ("query", self.query),
schemathesis/hooks.py CHANGED
@@ -32,6 +32,8 @@ class RegisteredHook:
32
32
  signature: inspect.Signature
33
33
  scopes: list[HookScope]
34
34
 
35
+ __slots__ = ("signature", "scopes")
36
+
35
37
  def _repr_pretty_(self, *args: Any, **kwargs: Any) -> None: ...
36
38
 
37
39
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from contextlib import nullcontext
4
- from dataclasses import dataclass, field
4
+ from dataclasses import dataclass
5
5
  from inspect import signature
6
6
  from typing import TYPE_CHECKING, Any, Callable, Generator, Type
7
7
 
@@ -71,7 +71,17 @@ def get_all_tests(
71
71
  @dataclass
72
72
  class LazySchema:
73
73
  fixture_name: str
74
- filter_set: FilterSet = field(default_factory=FilterSet)
74
+ filter_set: FilterSet
75
+
76
+ __slots__ = ("fixture_name", "filter_set")
77
+
78
+ def __init__(
79
+ self,
80
+ fixture_name: str,
81
+ filter_set: FilterSet | None = None,
82
+ ) -> None:
83
+ self.fixture_name = fixture_name
84
+ self.filter_set = filter_set or FilterSet()
75
85
 
76
86
  def include(
77
87
  self,
@@ -20,6 +20,7 @@ from schemathesis.core.errors import (
20
20
  InvalidHeadersExample,
21
21
  InvalidRegexPattern,
22
22
  InvalidSchema,
23
+ SchemathesisError,
23
24
  SerializationNotPossible,
24
25
  format_exception,
25
26
  )
@@ -263,20 +264,27 @@ def pytest_pycollect_makeitem(collector: nodes.Collector, name: str, obj: Any) -
263
264
 
264
265
  @pytest.hookimpl(tryfirst=True) # type: ignore[misc]
265
266
  def pytest_exception_interact(node: Function, call: pytest.CallInfo, report: pytest.TestReport) -> None:
266
- if call.excinfo and call.excinfo.type is FailureGroup:
267
- tb_entries = list(call.excinfo.traceback)
268
- total_frames = len(tb_entries)
269
-
270
- # Keep internal Schemathesis frames + one extra one from the caller
271
- skip_frames = 0
272
- for i in range(total_frames - 1, -1, -1):
273
- entry = tb_entries[i]
274
-
275
- if not str(entry.path).endswith("schemathesis/generation/case.py"):
276
- skip_frames = i
277
- break
278
-
279
- report.longrepr = "".join(format_exception(call.excinfo.value, with_traceback=True, skip_frames=skip_frames))
267
+ if call.excinfo:
268
+ if issubclass(call.excinfo.type, SchemathesisError) and hasattr(call.excinfo.value, "__notes__"):
269
+ # Hypothesis adds quite a lot of additional debug information which is not that helpful in Schemathesis
270
+ call.excinfo.value.__notes__.clear()
271
+ report.longrepr = "".join(format_exception(call.excinfo.value))
272
+ if call.excinfo.type is FailureGroup:
273
+ tb_entries = list(call.excinfo.traceback)
274
+ total_frames = len(tb_entries)
275
+
276
+ # Keep internal Schemathesis frames + one extra one from the caller
277
+ skip_frames = 0
278
+ for i in range(total_frames - 1, -1, -1):
279
+ entry = tb_entries[i]
280
+
281
+ if not str(entry.path).endswith("schemathesis/generation/case.py"):
282
+ skip_frames = i
283
+ break
284
+
285
+ report.longrepr = "".join(
286
+ format_exception(call.excinfo.value, with_traceback=True, skip_frames=skip_frames)
287
+ )
280
288
 
281
289
 
282
290
  @hookimpl(wrapper=True)
schemathesis/schemas.py CHANGED
@@ -50,9 +50,6 @@ if TYPE_CHECKING:
50
50
  from schemathesis.generation.stateful.state_machine import APIStateMachine
51
51
 
52
52
 
53
- C = TypeVar("C", bound=Case)
54
-
55
-
56
53
  @lru_cache
57
54
  def get_full_path(base_path: str, path: str) -> str:
58
55
  return unquote(urljoin(base_path, quote(path.lstrip("/"))))
@@ -483,6 +480,8 @@ class APIOperationMap(Mapping):
483
480
  _schema: BaseSchema
484
481
  _data: Mapping
485
482
 
483
+ __slots__ = ("_schema", "_data")
484
+
486
485
  def __getitem__(self, item: str) -> APIOperation:
487
486
  return self._data[item]
488
487
 
@@ -526,6 +525,8 @@ class Parameter:
526
525
  # The parameter definition in the language acceptable by the API
527
526
  definition: Any
528
527
 
528
+ __slots__ = ("definition",)
529
+
529
530
  @property
530
531
  def location(self) -> str:
531
532
  """Where this parameter is located.
@@ -556,7 +557,12 @@ P = TypeVar("P", bound=Parameter)
556
557
  class ParameterSet(Generic[P]):
557
558
  """A set of parameters for the same location."""
558
559
 
559
- items: list[P] = field(default_factory=list)
560
+ items: list[P]
561
+
562
+ __slots__ = ("items",)
563
+
564
+ def __init__(self, items: list[P] | None = None) -> None:
565
+ self.items = items or []
560
566
 
561
567
  def _repr_pretty_(self, *args: Any, **kwargs: Any) -> None: ...
562
568
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from dataclasses import dataclass, field
3
+ from dataclasses import dataclass
4
4
  from typing import TYPE_CHECKING
5
5
 
6
6
  if TYPE_CHECKING:
@@ -9,8 +9,18 @@ if TYPE_CHECKING:
9
9
 
10
10
  @dataclass
11
11
  class OperationCache:
12
- _maps: dict[str, APIOperationMap] = field(default_factory=dict)
13
- _operations: dict[str, APIOperation] = field(default_factory=dict)
12
+ _maps: dict[str, APIOperationMap]
13
+ _operations: dict[str, APIOperation]
14
+
15
+ __slots__ = ("_maps", "_operations")
16
+
17
+ def __init__(
18
+ self,
19
+ _maps: dict[str, APIOperationMap] | None = None,
20
+ _operations: dict[str, APIOperation] | None = None,
21
+ ) -> None:
22
+ self._maps = _maps or {}
23
+ self._operations = _operations or {}
14
24
 
15
25
  def get_map(self, key: str) -> APIOperationMap | None:
16
26
  return self._maps.get(key)
@@ -71,6 +71,8 @@ class GraphQLOperationDefinition(OperationDefinition):
71
71
  type_: graphql.GraphQLType
72
72
  root_type: RootType
73
73
 
74
+ __slots__ = ("raw", "resolved", "scope", "field_name", "type_", "root_type")
75
+
74
76
  def _repr_pretty_(self, *args: Any, **kwargs: Any) -> None: ...
75
77
 
76
78
  @property
@@ -120,7 +120,7 @@ def openapi_cases(
120
120
  for media_type in all_media_types
121
121
  ):
122
122
  # None of media types defined for this operation are not supported
123
- raise SerializationNotPossible.from_media_types(*all_media_types)
123
+ raise SerializationNotPossible.from_media_types(*all_media_types) from None
124
124
  # Other media types are possible - avoid choosing this media type in the future
125
125
  event_text = f"Can't serialize data to `{parameter.media_type}`."
126
126
  note(f"{event_text} {SERIALIZERS_SUGGESTION_MESSAGE}")
@@ -35,6 +35,8 @@ class ParameterExample:
35
35
  name: str
36
36
  value: Any
37
37
 
38
+ __slots__ = ("container", "name", "value")
39
+
38
40
 
39
41
  @dataclass
40
42
  class BodyExample:
@@ -43,6 +45,8 @@ class BodyExample:
43
45
  value: Any
44
46
  media_type: str
45
47
 
48
+ __slots__ = ("value", "media_type")
49
+
46
50
 
47
51
  Example = Union[ParameterExample, BodyExample]
48
52
 
@@ -16,6 +16,8 @@ class RegexExtractor(Extractor):
16
16
 
17
17
  value: re.Pattern
18
18
 
19
+ __slots__ = ("value",)
20
+
19
21
  def extract(self, value: str) -> str | None:
20
22
  match = self.value.search(value)
21
23
  if match is None:
@@ -23,6 +23,8 @@ class Token:
23
23
  end: int
24
24
  type_: TokenType
25
25
 
26
+ __slots__ = ("value", "end", "type_")
27
+
26
28
  # Helpers for cleaner instantiation
27
29
 
28
30
  @classmethod
@@ -39,6 +39,8 @@ class String(Node):
39
39
 
40
40
  value: str
41
41
 
42
+ __slots__ = ("value",)
43
+
42
44
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
43
45
  """String tokens are passed as they are.
44
46
 
@@ -53,6 +55,8 @@ class String(Node):
53
55
  class URL(Node):
54
56
  """A node for `$url` expression."""
55
57
 
58
+ __slots__ = ()
59
+
56
60
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
57
61
  import requests
58
62
 
@@ -66,6 +70,8 @@ class URL(Node):
66
70
  class Method(Node):
67
71
  """A node for `$method` expression."""
68
72
 
73
+ __slots__ = ()
74
+
69
75
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
70
76
  return output.case.operation.method.upper()
71
77
 
@@ -74,6 +80,8 @@ class Method(Node):
74
80
  class StatusCode(Node):
75
81
  """A node for `$statusCode` expression."""
76
82
 
83
+ __slots__ = ()
84
+
77
85
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
78
86
  return str(output.response.status_code)
79
87
 
@@ -84,7 +92,14 @@ class NonBodyRequest(Node):
84
92
 
85
93
  location: str
86
94
  parameter: str
87
- extractor: Extractor | None = None
95
+ extractor: Extractor | None
96
+
97
+ __slots__ = ("location", "parameter", "extractor")
98
+
99
+ def __init__(self, location: str, parameter: str, extractor: Extractor | None = None) -> None:
100
+ self.location = location
101
+ self.parameter = parameter
102
+ self.extractor = extractor
88
103
 
89
104
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
90
105
  container = {
@@ -106,7 +121,12 @@ class NonBodyRequest(Node):
106
121
  class BodyRequest(Node):
107
122
  """A node for `$request` expressions where location is `body`."""
108
123
 
109
- pointer: str | None = None
124
+ pointer: str | None
125
+
126
+ __slots__ = ("pointer",)
127
+
128
+ def __init__(self, pointer: str | None = None) -> None:
129
+ self.pointer = pointer
110
130
 
111
131
  def evaluate(self, output: StepOutput) -> Any | Unresolvable:
112
132
  document = output.case.body
@@ -120,7 +140,13 @@ class HeaderResponse(Node):
120
140
  """A node for `$response.header` expressions."""
121
141
 
122
142
  parameter: str
123
- extractor: Extractor | None = None
143
+ extractor: Extractor | None
144
+
145
+ __slots__ = ("parameter", "extractor")
146
+
147
+ def __init__(self, parameter: str, extractor: Extractor | None = None) -> None:
148
+ self.parameter = parameter
149
+ self.extractor = extractor
124
150
 
125
151
  def evaluate(self, output: StepOutput) -> str | Unresolvable:
126
152
  value = output.response.headers.get(self.parameter.lower())
@@ -135,7 +161,12 @@ class HeaderResponse(Node):
135
161
  class BodyResponse(Node):
136
162
  """A node for `$response.body` expressions."""
137
163
 
138
- pointer: str | None = None
164
+ pointer: str | None
165
+
166
+ __slots__ = ("pointer",)
167
+
168
+ def __init__(self, pointer: str | None = None) -> None:
169
+ self.pointer = pointer
139
170
 
140
171
  def evaluate(self, output: StepOutput) -> Any:
141
172
  document = output.response.json()
@@ -30,6 +30,8 @@ class CacheKey:
30
30
  schema: Schema
31
31
  validator_cls: type[jsonschema.Validator]
32
32
 
33
+ __slots__ = ("operation_name", "location", "schema", "validator_cls")
34
+
33
35
  def __hash__(self) -> int:
34
36
  return hash((self.operation_name, self.location))
35
37
 
@@ -74,6 +74,8 @@ class MutationContext:
74
74
  # Payload media type, if available
75
75
  media_type: str | None
76
76
 
77
+ __slots__ = ("keywords", "non_keywords", "location", "media_type")
78
+
77
79
  @property
78
80
  def is_header_location(self) -> bool:
79
81
  return is_header_location(self.location)
@@ -186,6 +186,7 @@ class StepOutputWrapper:
186
186
  """Wrapper for StepOutput that uses only case_id for hash-based caching."""
187
187
 
188
188
  output: StepOutput
189
+
189
190
  __slots__ = ("output",)
190
191
 
191
192
  def __hash__(self) -> int:
@@ -34,8 +34,6 @@ def prepare_headers(case: Case, headers: dict[str, str] | None = None) -> CaseIn
34
34
  default_headers.setdefault(SCHEMATHESIS_TEST_CASE_HEADER, case.id)
35
35
  if headers:
36
36
  default_headers.update(headers)
37
- for header in get_exclude_headers(case):
38
- default_headers.pop(header, None)
39
37
  return default_headers
40
38
 
41
39
 
@@ -4,7 +4,7 @@ import binascii
4
4
  import inspect
5
5
  import os
6
6
  from io import BytesIO
7
- from typing import TYPE_CHECKING, Any
7
+ from typing import TYPE_CHECKING, Any, MutableMapping
8
8
  from urllib.parse import urlparse
9
9
 
10
10
  from schemathesis.core import NotSet
@@ -13,7 +13,7 @@ from schemathesis.core.transforms import deepclone, merge_at
13
13
  from schemathesis.core.transport import DEFAULT_RESPONSE_TIMEOUT, Response
14
14
  from schemathesis.generation.overrides import Override
15
15
  from schemathesis.transport import BaseTransport, SerializationContext
16
- from schemathesis.transport.prepare import prepare_body, prepare_headers, prepare_url
16
+ from schemathesis.transport.prepare import get_exclude_headers, prepare_body, prepare_headers, prepare_url
17
17
  from schemathesis.transport.serialization import Binary, serialize_binary, serialize_json, serialize_xml, serialize_yaml
18
18
 
19
19
  if TYPE_CHECKING:
@@ -85,23 +85,54 @@ class RequestsTransport(BaseTransport["requests.Session"]):
85
85
  def send(self, case: Case, *, session: requests.Session | None = None, **kwargs: Any) -> Response:
86
86
  import requests
87
87
 
88
+ config = case.operation.schema.config
89
+
90
+ timeout = config.request_timeout_for(operation=case.operation)
91
+ verify = config.tls_verify_for(operation=case.operation)
92
+ cert = config.request_cert_for(operation=case.operation)
93
+
94
+ if session is not None and session.headers:
95
+ # These headers are explicitly provided via config or CLI args.
96
+ # They have lower priority than ones provided via `kwargs`
97
+ headers = kwargs.setdefault("headers", {}) or {}
98
+ for name, value in session.headers.items():
99
+ headers.setdefault(name, value)
100
+ kwargs["headers"] = headers
101
+
88
102
  data = self.serialize_case(case, **kwargs)
103
+
104
+ if verify is not None:
105
+ data.setdefault("verify", verify)
106
+ if timeout is not None:
107
+ data.setdefault("timeout", timeout)
108
+ if cert is not None:
109
+ data.setdefault("cert", cert)
110
+
89
111
  kwargs.pop("base_url", None)
90
112
  data.update({key: value for key, value in kwargs.items() if key not in data})
91
113
  data.setdefault("timeout", DEFAULT_RESPONSE_TIMEOUT)
92
114
 
115
+ excluded_headers = get_exclude_headers(case)
116
+ for name in excluded_headers:
117
+ data["headers"].pop(name, None)
118
+ current_session_headers: MutableMapping[str, Any] = {}
119
+ current_session_auth = None
120
+
93
121
  if session is None:
94
122
  validate_vanilla_requests_kwargs(data)
95
123
  session = requests.Session()
96
- session.headers = {}
97
124
  close_session = True
98
125
  else:
126
+ current_session_headers = session.headers
127
+ if isinstance(session.auth, tuple) and "Authorization" in excluded_headers:
128
+ current_session_auth = session.auth
129
+ session.auth = None
99
130
  close_session = False
131
+ session.headers = {}
100
132
 
101
133
  verify = data.get("verify", True)
102
134
 
103
135
  try:
104
- config = case.operation.schema.config
105
136
  rate_limit = config.rate_limit_for(operation=case.operation)
106
137
  with ratelimit(rate_limit, config.base_url):
107
138
  response = session.request(**data) # type: ignore
@@ -115,8 +146,10 @@ class RequestsTransport(BaseTransport["requests.Session"]):
115
146
  path_parameters={},
116
147
  ),
117
148
  )
118
-
119
149
  finally:
150
+ session.headers = current_session_headers
151
+ if current_session_auth is not None:
152
+ session.auth = current_session_auth
120
153
  if close_session:
121
154
  session.close()
122
155
 
@@ -12,7 +12,13 @@ from schemathesis.generation.case import Case
12
12
  from schemathesis.generation.overrides import Override
13
13
  from schemathesis.python import wsgi
14
14
  from schemathesis.transport import BaseTransport, SerializationContext
15
- from schemathesis.transport.prepare import normalize_base_url, prepare_body, prepare_headers, prepare_path
15
+ from schemathesis.transport.prepare import (
16
+ get_exclude_headers,
17
+ normalize_base_url,
18
+ prepare_body,
19
+ prepare_headers,
20
+ prepare_path,
21
+ )
16
22
  from schemathesis.transport.requests import REQUESTS_TRANSPORT
17
23
  from schemathesis.transport.serialization import serialize_binary, serialize_json, serialize_xml, serialize_yaml
18
24
 
@@ -73,6 +79,10 @@ class WSGITransport(BaseTransport["werkzeug.Client"]):
73
79
  data = self.serialize_case(case, headers=headers, params=params)
74
80
  data.update({key: value for key, value in kwargs.items() if key not in data})
75
81
 
82
+ excluded_headers = get_exclude_headers(case)
83
+ for name in excluded_headers:
84
+ data["headers"].pop(name, None)
85
+
76
86
  client = session or wsgi.get_client(application)
77
87
  cookies = {**(case.cookies or {}), **(cookies or {})}
78
88
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.0.1
3
+ Version: 4.0.3
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
@@ -170,7 +170,7 @@ def test_api(case):
170
170
 
171
171
  **CI/CD:**
172
172
  ```yaml
173
- - uses: schemathesis/action@v1
173
+ - uses: schemathesis/action@v2
174
174
  with:
175
175
  schema: "https://your-api.com/openapi.json"
176
176
  ```
@@ -3,9 +3,9 @@ schemathesis/auths.py,sha256=JdEwPRS9WKmPcxzGXYYz9pjlIUMQYCfif7ZJU0Kde-I,16400
3
3
  schemathesis/checks.py,sha256=GTdejjXDooAOuq66nvCK3i-AMPBuU-_-aNeSeL9JIlc,6561
4
4
  schemathesis/errors.py,sha256=T8nobEi5tQX_SkwaYb8JFoIlF9F_vOQVprZ8EVPAhjA,931
5
5
  schemathesis/filters.py,sha256=OEub50Ob5sf0Tn3iTeuIaxSMtepF7KVoiEM9wtt5GGA,13433
6
- schemathesis/hooks.py,sha256=XIeSKLiClAz3NlMqQ0oNCGZlu-f4Kvzju5gaxqlAqSs,13881
6
+ schemathesis/hooks.py,sha256=L1o9IQz0_mY59gs3WGHGSCnGHjF6WWEZZuwJaHcVG1o,13922
7
7
  schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- schemathesis/schemas.py,sha256=abMMY3nT_lh5siRE3mc5oB6y4rNv2oDJnCE8e5B1pzs,28252
8
+ schemathesis/schemas.py,sha256=glaIjN7JO1mdOCs5_HUFjLWQ-89z8NFBUIuc5p8cLAU,28386
9
9
  schemathesis/cli/__init__.py,sha256=U9gjzWWpiFhaqevPjZbwyTNjABdpvXETI4HgwdGKnvs,877
10
10
  schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
11
11
  schemathesis/cli/constants.py,sha256=CVcQNHEiX-joAQmyuEVKWPOSxDHsOw_EXXZsEclzLuY,341
@@ -21,9 +21,9 @@ schemathesis/cli/commands/run/loaders.py,sha256=6j0ez7wduAUYbUT28ELKxMf-dYEWr_67
21
21
  schemathesis/cli/commands/run/validation.py,sha256=FzCzYdW1-hn3OgyzPO1p6wHEX5PG7HdewbPRvclV_vc,9002
22
22
  schemathesis/cli/commands/run/handlers/__init__.py,sha256=TPZ3KdGi8m0fjlN0GjA31MAXXn1qI7uU4FtiDwroXZI,1915
23
23
  schemathesis/cli/commands/run/handlers/base.py,sha256=yDsTtCiztLksfk7cRzg8JlaAVOfS-zwK3tsJMOXAFyc,530
24
- schemathesis/cli/commands/run/handlers/cassettes.py,sha256=Gu0qcxzvHp1zMY-SVkY96T-Ifwtdh6oj-w0gE1MShnA,19157
25
- schemathesis/cli/commands/run/handlers/junitxml.py,sha256=FX_347PcHhGLG7XY3eG8VwhB_8tSX4mOtqjZj_s6yLM,2402
26
- schemathesis/cli/commands/run/handlers/output.py,sha256=L-zJnMsbHMkilSG65W1a030cQ7Nfo2Gnnmsia-8pZOc,62554
24
+ schemathesis/cli/commands/run/handlers/cassettes.py,sha256=rRD4byjp4HXCkJS-zx3jSIFOJsPq77ejPpYeyCtsEZs,19461
25
+ schemathesis/cli/commands/run/handlers/junitxml.py,sha256=Q5GxGjsPq-oKVgq5P19nv0rsi-ZWT5ghHWh-WXgpQ5k,2550
26
+ schemathesis/cli/commands/run/handlers/output.py,sha256=4sffi2lj3QcDt6JKJCsIT9wCesj1ZdHfTaP6-8dTwh8,62884
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
@@ -46,7 +46,7 @@ schemathesis/config/_report.py,sha256=aYLnPO74B7Wfn_qTwlEp5zY9L74U1XFuYS10yjwKKW
46
46
  schemathesis/config/_validator.py,sha256=IcE8geFZ0ZwR18rkIRs25i7pTl7Z84XbjYGUB-mqReU,258
47
47
  schemathesis/config/_warnings.py,sha256=sI0VZcTj3dOnphhBwYwU_KTagxr89HGWTtQ99HcY84k,772
48
48
  schemathesis/config/schema.json,sha256=wC1qe9M_fXotfmlBOmW_FCTRw9K5YC814-PipMGKllE,18907
49
- schemathesis/core/__init__.py,sha256=5fAAKG6BAA5DP9qOUnMT1cG5LLN3tU7D7VdLyb-MxfM,1880
49
+ schemathesis/core/__init__.py,sha256=j862XBH5dXhxsrDg9mE7n4cSSfol0EHdY0ru1d27tCc,1917
50
50
  schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1058
51
51
  schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
52
52
  schemathesis/core/curl.py,sha256=yuaCe_zHLGwUjEeloQi6W3tOA3cGdnHDNI17-5jia0o,1723
@@ -70,13 +70,13 @@ schemathesis/core/output/__init__.py,sha256=SiHqONFskXl73AtP5dV29L14nZoKo7B-IeG5
70
70
  schemathesis/core/output/sanitization.py,sha256=Ev3tae8dVwsYd7yVb2_1VBFYs92WFsQ4Eu1fGaymItE,2013
71
71
  schemathesis/engine/__init__.py,sha256=QaFE-FinaTAaarteADo2RRMJ-Sz6hZB9TzD5KjMinIA,706
72
72
  schemathesis/engine/context.py,sha256=x-I9KX6rO6hdCvvN8FEdzIZBqIcNaxdNYHgQjcXbZhM,3931
73
- schemathesis/engine/control.py,sha256=QKUOs5VMphe7EcAIro_DDo9ZqdOU6ZVwTU1gMNndHWw,1006
74
- schemathesis/engine/core.py,sha256=Pnpf1zNTxruUOnnJ9rQ-MskXj4WuA4A27_fWrf0hXWc,5609
73
+ schemathesis/engine/control.py,sha256=FXzP8dxL47j1Giqpy2-Bsr_MdMw9YiATSK_UfpFwDtk,1348
74
+ schemathesis/engine/core.py,sha256=5jfAqFH0XSD7NVgoSXuUPW-dooItscneAzUNq1RBh1E,5712
75
75
  schemathesis/engine/errors.py,sha256=cWKuwj0Kzr2BHdVCHACnniUJ8sFVJ0Nqckc3iggZS1o,18800
76
76
  schemathesis/engine/events.py,sha256=VV6epicFIJnX4c87fVNSd0ibDccX3gryDv52OUGa3FI,6370
77
77
  schemathesis/engine/recorder.py,sha256=K3HfMARrT5mPWXPnYebjjcq5CcsBRhMrtZwEL9_Lvtg,8432
78
- schemathesis/engine/phases/__init__.py,sha256=zzILnWjoDJQwNmvEmrj3HXVAKT2q7Vb614svjyt8E-U,2794
79
- schemathesis/engine/phases/probes.py,sha256=-8JdQhMwANTkq64s5h8867oojorM5nUU8P0btdfJne4,5141
78
+ schemathesis/engine/phases/__init__.py,sha256=jUIfb_9QoUo4zmJEVU0z70PgXPYjt8CIqp4qP_HlYHg,3146
79
+ schemathesis/engine/phases/probes.py,sha256=SEtWKPdkLfRTKV0_tbiNHTK3sJsUUPZ0jZQ9Nv4qUi8,5678
80
80
  schemathesis/engine/phases/stateful/__init__.py,sha256=Lz1rgNqCfUSIz173XqCGsiMuUI5bh4L-RIFexU1-c_Q,2461
81
81
  schemathesis/engine/phases/stateful/_executor.py,sha256=CV4jUuXpV4uSXVJqDI4btnLR8dpzOQVqbv2qVCgE4_s,15182
82
82
  schemathesis/engine/phases/stateful/context.py,sha256=A7X1SLDOWFpCvFN9IiIeNVZM0emjqatmJL_k9UsO7vM,2946
@@ -84,14 +84,14 @@ schemathesis/engine/phases/unit/__init__.py,sha256=BvZh39LZmXg90Cy_Tn0cQY5y7eWzY
84
84
  schemathesis/engine/phases/unit/_executor.py,sha256=jay_D7fmmBTjZigifmY30RiVP5Jb0OlK450fknSWZ_I,16471
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
- schemathesis/generation/case.py,sha256=WbOJagE7Gjz3ZvBxzRl8vJHgm_LjW0wf2oRuPzoj6LI,11547
87
+ schemathesis/generation/case.py,sha256=MuqnKsJBpGm2gaqDFdJi1yGSWgBhqJUwtYaX97kfXgo,11820
88
88
  schemathesis/generation/coverage.py,sha256=bKP0idU5-eiK4VwhH4kjxDPtCZzMg81mbN1tEDuT6EA,47913
89
- schemathesis/generation/meta.py,sha256=5ikrlhdk424dWcYLekZSMoWJYRl9_IhI80GKZzhByi4,2512
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
- schemathesis/generation/overrides.py,sha256=ZwU7k5WnkjjuzKorpBwl_eov1Ko1VfM5WqjdRlX2DK4,3691
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=2mXAVSkgl2SBV8IzrqkOd3okTD6oVLFdQoRirQMF7ss,32385
94
+ schemathesis/generation/hypothesis/builder.py,sha256=xc5U3LfJ1lQHKFFW_9W8n3KFutwA2mv954A4jLhB9vg,33105
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
@@ -108,27 +108,27 @@ schemathesis/openapi/generation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
108
108
  schemathesis/openapi/generation/filters.py,sha256=pY9cUZdL_kQK80Z2aylTOqqa12zmaYUlYC5BfYgeQMk,2395
109
109
  schemathesis/pytest/__init__.py,sha256=7W0q-Thcw03IAQfXE_Mo8JPZpUdHJzfu85fjK1ZdfQM,88
110
110
  schemathesis/pytest/control_flow.py,sha256=F8rAPsPeNv_sJiJgbZYtTpwKWjauZmqFUaKroY2GmQI,217
111
- schemathesis/pytest/lazy.py,sha256=W9epwVFYjOZRZSNemHUsgIwvRp9ya9p8IGHxvg3_t18,10854
111
+ schemathesis/pytest/lazy.py,sha256=u58q0orI0zisivLJKJkSo53RaQMPLSMiE0vJ1TQ9_uA,11073
112
112
  schemathesis/pytest/loaders.py,sha256=Sbv8e5F77_x4amLP50iwubfm6kpOhx7LhLFGsVXW5Ys,925
113
- schemathesis/pytest/plugin.py,sha256=m4zGLw6A537o4mBb9FvuM4jmAoxfpg0DPLWq5eCLXGc,13818
113
+ schemathesis/pytest/plugin.py,sha256=MXllorF5SqUgqjLyhHb-P0wlWokvZMg0Rm6OTRoFoas,14266
114
114
  schemathesis/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
115
  schemathesis/python/asgi.py,sha256=5PyvuTBaivvyPUEi3pwJni91K1kX5Zc0u9c6c1D8a1Q,287
116
116
  schemathesis/python/wsgi.py,sha256=uShAgo_NChbfYaV1117e6UHp0MTg7jaR0Sy_to3Jmf8,219
117
117
  schemathesis/specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
118
  schemathesis/specs/graphql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
119
- schemathesis/specs/graphql/_cache.py,sha256=QIcEFy2Koy5K0-u1nB-iab52LDlYsTm_9N5t42GplkM,770
119
+ schemathesis/specs/graphql/_cache.py,sha256=mlOtzEvdE9gZ1posP7OqHUYlaZyiygL5U_Xda7wphFc,988
120
120
  schemathesis/specs/graphql/nodes.py,sha256=bE3G1kNmqJ8OV4igBvIK-UORrkQA6Nofduf87O3TD9I,541
121
121
  schemathesis/specs/graphql/scalars.py,sha256=6lew8mnwhrtg23leiEbG43mLGPLlRln8mClCY94XpDA,2680
122
- schemathesis/specs/graphql/schemas.py,sha256=25TXYPCxAXCAWE0L_vDFLDXmhNe7ac4YQbKulJuf9zI,14542
122
+ schemathesis/specs/graphql/schemas.py,sha256=ezkqgMwx37tMWlhy_I0ahDF1Q44emDSJkyjduq1QGjE,14624
123
123
  schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzVfHxtdLkCPKM,1422
124
124
  schemathesis/specs/openapi/__init__.py,sha256=C5HOsfuDJGq_3mv8CRBvRvb0Diy1p0BFdqyEXMS-loE,238
125
125
  schemathesis/specs/openapi/_cache.py,sha256=HpglmETmZU0RCHxp3DO_sg5_B_nzi54Zuw9vGzzYCxY,4295
126
- schemathesis/specs/openapi/_hypothesis.py,sha256=005E_gH4YGhOORQyJtP6vkOOM0-FgiES06JpXRcdL5c,22601
126
+ schemathesis/specs/openapi/_hypothesis.py,sha256=NuXucpwn8jjL_O0anja1TPqEuXyuFq8quIuECIW9BLY,22611
127
127
  schemathesis/specs/openapi/checks.py,sha256=mKJ-ZkbjhbXS4eWDZiv8zslXKFDqkE3Mp4N8TVDHiI0,29801
128
128
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
129
129
  schemathesis/specs/openapi/converter.py,sha256=lil8IewM5j8tvt4lpA9g_KITvIwx1M96i45DNSHNjoc,3505
130
130
  schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
131
- schemathesis/specs/openapi/examples.py,sha256=9dMY4d2WWz32JywKZzyLO5jdbMWcRqjjGHzhMqlqwIs,21129
131
+ schemathesis/specs/openapi/examples.py,sha256=11GMuwyTws8MizQ3CkfT3dQD4TFP22CGYBMUyESYsDM,21218
132
132
  schemathesis/specs/openapi/formats.py,sha256=8AIS7Uey-Z1wm1WYRqnsVqHwG9d316PdqfKLqwUs7us,3516
133
133
  schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKRcUOc41eEwKbo,2472
134
134
  schemathesis/specs/openapi/parameters.py,sha256=BevME4DWLQ-OFvc_7fREMjj99VAbVNxVb5i8OEX6Pfs,14453
@@ -140,25 +140,25 @@ schemathesis/specs/openapi/serialization.py,sha256=VdDLmeHqxlWM4cxQQcCkvrU6Xuriv
140
140
  schemathesis/specs/openapi/utils.py,sha256=ER4vJkdFVDIE7aKyxyYatuuHVRNutytezgE52pqZNE8,900
141
141
  schemathesis/specs/openapi/expressions/__init__.py,sha256=hfuRtXD75tQFhzSo6QgDZ3zByyWeZRKevB8edszAVj4,2272
142
142
  schemathesis/specs/openapi/expressions/errors.py,sha256=YLVhps-sYcslgVaahfcUYxUSHlIfWL-rQMeT5PZSMZ8,219
143
- schemathesis/specs/openapi/expressions/extractors.py,sha256=Py3of3_vBACP4ljiZIcgd-xQCrWIpcMsfQFc0EtAUoA,470
144
- schemathesis/specs/openapi/expressions/lexer.py,sha256=KFA8Z-Kh1IYUpKgwAnDtEucN9YLLpnFR1GQl8KddWlA,3987
145
- schemathesis/specs/openapi/expressions/nodes.py,sha256=KMTzuOXwzKQ09NU3m7Q9vDYI2Vgg6YiZJ7RnqnY2gbE,4049
143
+ schemathesis/specs/openapi/expressions/extractors.py,sha256=IvOrgq_1IWNnirOSV_wLi0UcWOTiL-mLvBLFzLwRpVA,498
144
+ schemathesis/specs/openapi/expressions/lexer.py,sha256=ZbYPbVX-2c2Dan-6fi4NrDlFT6N55Wrz-4921TKHlZs,4030
145
+ schemathesis/specs/openapi/expressions/nodes.py,sha256=qaFpAM3seIzmlYLr9So2kRCSNrteZTa7djcRiOD_ji4,4811
146
146
  schemathesis/specs/openapi/expressions/parser.py,sha256=e-ZxshrGE_5CVbgcZLYgdGSjdifgyzgKkLQp0dI0cJY,4503
147
- schemathesis/specs/openapi/negative/__init__.py,sha256=qSANRvaBWJcyz637TT8I0YOLWz03pC-uHW9Tmm1qrQU,3840
148
- schemathesis/specs/openapi/negative/mutations.py,sha256=r7kc8KVhDGMECvQtGZKHrzSJMRaknMwyfAbCq0BuQAo,19246
147
+ schemathesis/specs/openapi/negative/__init__.py,sha256=1sajF22SrE4pUK7-C6PiseZ9PiR5trN33cfUqEMGIbo,3915
148
+ schemathesis/specs/openapi/negative/mutations.py,sha256=ZLiNb4n2K1Oeq3eev8tgNqvlyP7cBIPUTLe7Gc6nvDM,19318
149
149
  schemathesis/specs/openapi/negative/types.py,sha256=a7buCcVxNBG6ILBM3A7oNTAX0lyDseEtZndBuej8MbI,174
150
150
  schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrrkuNdXX0SDnLoGYA,168
151
151
  schemathesis/specs/openapi/stateful/__init__.py,sha256=FSitLbJxjBYU814cqjI_QCkdyoIc-9xfT_1HQcYwsXw,15064
152
152
  schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8n5ePqSKB00XFxp-MA,3695
153
- schemathesis/specs/openapi/stateful/links.py,sha256=fU-dn0ds7Dk7QHSF781kMF3Vq_3QuAjoelEb3lVWig0,8805
153
+ schemathesis/specs/openapi/stateful/links.py,sha256=h5q40jUbcIk5DS_Tih1cvFJxS_QxxG0_9ZQnTs1A_zo,8806
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
- schemathesis/transport/prepare.py,sha256=c7__wdblBC4zqnmtcs99zoAeEY8jfXiGbdzh74icj6g,4668
157
- schemathesis/transport/requests.py,sha256=J0j4_9KUBLqgObAklG_Ay62EKdPUeDIcbOMeutl2ctk,9170
156
+ schemathesis/transport/prepare.py,sha256=iiB8KTAqnnuqjWzblIPiGVdkGIF7Yr1SAEz-KZzBNXw,4581
157
+ schemathesis/transport/requests.py,sha256=rziZTrZCVMAqgy6ldB8iTwhkpAsnjKSgK8hj5Sq3ThE,10656
158
158
  schemathesis/transport/serialization.py,sha256=igUXKZ_VJ9gV7P0TUc5PDQBJXl_s0kK9T3ljGWWvo6E,10339
159
- schemathesis/transport/wsgi.py,sha256=nqmIqYrhC_eqgJSgmDKWz2WSAMFMVVXThJCQLNf1cEQ,5970
160
- schemathesis-4.0.1.dist-info/METADATA,sha256=Kzo-8LBg_T20kmjJIPntAUY0h6gokghLLjmKyjFinO4,8471
161
- schemathesis-4.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
- schemathesis-4.0.1.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
- schemathesis-4.0.1.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
- schemathesis-4.0.1.dist-info/RECORD,,
159
+ schemathesis/transport/wsgi.py,sha256=KoAfvu6RJtzyj24VGB8e-Iaa9smpgXJ3VsM8EgAz2tc,6152
160
+ schemathesis-4.0.3.dist-info/METADATA,sha256=hm5ioN50c0UyShRq7AN-9qzDnKGLMYSxQwXw1Lw7jTc,8471
161
+ schemathesis-4.0.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
+ schemathesis-4.0.3.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
+ schemathesis-4.0.3.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
+ schemathesis-4.0.3.dist-info/RECORD,,