schemathesis 4.3.11__py3-none-any.whl → 4.3.12__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.

Potentially problematic release.


This version of schemathesis might be problematic. Click here for more details.

@@ -37,16 +37,20 @@ class StepInput:
37
37
 
38
38
  case: Case
39
39
  transition: Transition | None # None for initial steps
40
- # Whether this transition was actually applied
40
+ # What parameters were actually applied
41
41
  # Data extraction failures can prevent it, as well as transitions can be skipped in some cases
42
42
  # to improve discovery of bugs triggered by non-stateful inputs during stateful testing
43
- is_applied: bool
43
+ applied_parameters: list[str]
44
44
 
45
- __slots__ = ("case", "transition", "is_applied")
45
+ __slots__ = ("case", "transition", "applied_parameters")
46
46
 
47
47
  @classmethod
48
48
  def initial(cls, case: Case) -> StepInput:
49
- return cls(case=case, transition=None, is_applied=False)
49
+ return cls(case=case, transition=None, applied_parameters=[])
50
+
51
+ @property
52
+ def is_applied(self) -> bool:
53
+ return bool(self.applied_parameters)
50
54
 
51
55
 
52
56
  @dataclass
@@ -69,8 +73,9 @@ class ExtractedParam:
69
73
 
70
74
  definition: Any
71
75
  value: Result[Any, Exception]
76
+ is_required: bool
72
77
 
73
- __slots__ = ("definition", "value")
78
+ __slots__ = ("definition", "value", "is_required")
74
79
 
75
80
 
76
81
  @dataclass
@@ -8,6 +8,7 @@ import jsonschema
8
8
  from hypothesis import strategies as st
9
9
  from hypothesis.stateful import Bundle, Rule, precondition, rule
10
10
 
11
+ from schemathesis.core import NOT_SET
11
12
  from schemathesis.core.errors import InvalidStateMachine, InvalidTransition
12
13
  from schemathesis.core.parameters import ParameterLocation
13
14
  from schemathesis.core.result import Ok
@@ -49,7 +50,7 @@ class OpenAPIStateMachine(APIStateMachine):
49
50
  # The proportion of negative tests generated for "root" transitions
50
51
  NEGATIVE_TEST_CASES_THRESHOLD = 10
51
52
  # How often some transition is skipped
52
- USE_TRANSITION_THRESHOLD = 85
53
+ BASE_EXPLORATION_RATE = 0.15
53
54
 
54
55
 
55
56
  @dataclass
@@ -162,6 +163,7 @@ def create_state_machine(schema: BaseOpenAPISchema) -> type[APIStateMachine]:
162
163
  for target in operations:
163
164
  if target.label in transitions.operations:
164
165
  incoming = transitions.operations[target.label].incoming
166
+ config = schema.config.generation_for(operation=target, phase="stateful")
165
167
  if incoming:
166
168
  for link in incoming:
167
169
  bundle_name = f"{link.source.label} -> {link.status_code}"
@@ -169,7 +171,6 @@ def create_state_machine(schema: BaseOpenAPISchema) -> type[APIStateMachine]:
169
171
  f"{link.source.label} -> {link.status_code} -> {link.name} -> {target.label}"
170
172
  )
171
173
  assert name not in rules, name
172
- config = schema.config.generation_for(operation=target, phase="stateful")
173
174
  rules[name] = precondition(is_transition_allowed(bundle_name, link.source.label, target.label))(
174
175
  transition(
175
176
  name=name,
@@ -181,7 +182,6 @@ def create_state_machine(schema: BaseOpenAPISchema) -> type[APIStateMachine]:
181
182
  )
182
183
  if target.label in roots.reliable or (not roots.reliable and target.label in roots.fallback):
183
184
  name = _normalize_name(f"RANDOM -> {target.label}")
184
- config = schema.config.generation_for(operation=target, phase="stateful")
185
185
  if len(config.modes) == 1:
186
186
  case_strategy = target.as_strategy(generation_mode=config.modes[0], phase=TestPhase.STATEFUL)
187
187
  else:
@@ -249,50 +249,97 @@ def is_likely_root_transition(operation: APIOperation) -> bool:
249
249
 
250
250
 
251
251
  def into_step_input(
252
- target: APIOperation, link: OpenApiLink, modes: list[GenerationMode]
252
+ *, target: APIOperation, link: OpenApiLink, modes: list[GenerationMode]
253
253
  ) -> Callable[[StepOutput], st.SearchStrategy[StepInput]]:
254
+ """A single transition between API operations."""
255
+
254
256
  def builder(_output: StepOutput) -> st.SearchStrategy[StepInput]:
255
257
  @st.composite # type: ignore[misc]
256
258
  def inner(draw: st.DrawFn, output: StepOutput) -> StepInput:
259
+ random = draw(st.randoms(use_true_random=True))
260
+
261
+ def biased_coin(p: float) -> bool:
262
+ return random.random() < p
263
+
264
+ # Extract transition data from previous operation's output
257
265
  transition = link.extract(output)
258
266
 
259
- kwargs: dict[str, Any] = {
260
- container: {
261
- name: extracted.value.ok()
262
- for name, extracted in data.items()
263
- if isinstance(extracted.value, Ok) and extracted.value.ok() not in (None, UNRESOLVABLE)
264
- }
265
- for container, data in transition.parameters.items()
266
- }
267
+ overrides: dict[str, Any] = {}
268
+ applied_parameters = []
269
+ for container, data in transition.parameters.items():
270
+ overrides[container] = {}
271
+
272
+ for name, extracted in data.items():
273
+ # Skip if extraction failed or returned unusable value
274
+ if not isinstance(extracted.value, Ok) or extracted.value.ok() in (None, UNRESOLVABLE):
275
+ continue
276
+
277
+ param_key = f"{container}.{name}"
278
+
279
+ # Calculate exploration rate based on parameter characteristics
280
+ exploration_rate = BASE_EXPLORATION_RATE
281
+
282
+ # Path parameters are critical for routing - use link values more often
283
+ if container == "path_parameters":
284
+ exploration_rate *= 0.5
285
+
286
+ # Required parameters should follow links more often, optional ones explored more
287
+ # Path params are always required, so they get both multipliers
288
+ if extracted.is_required:
289
+ exploration_rate *= 0.5
290
+ else:
291
+ # Explore optional parameters more to avoid only testing link-provided values
292
+ exploration_rate *= 3.0
293
+
294
+ if biased_coin(1 - exploration_rate):
295
+ overrides[container][name] = extracted.value.ok()
296
+ applied_parameters.append(param_key)
267
297
 
298
+ # Get the extracted body value
268
299
  if (
269
300
  transition.request_body is not None
270
301
  and isinstance(transition.request_body.value, Ok)
271
302
  and transition.request_body.value.ok() is not UNRESOLVABLE
272
- and not link.merge_body
273
- and draw(st.integers(min_value=0, max_value=99)) < USE_TRANSITION_THRESHOLD
274
303
  ):
275
- kwargs["body"] = transition.request_body.value.ok()
276
-
277
- is_applied = bool(kwargs)
304
+ request_body = transition.request_body.value.ok()
305
+ else:
306
+ request_body = NOT_SET
307
+
308
+ # Link suppose to replace the entire extracted body
309
+ if request_body is not NOT_SET and not link.merge_body and biased_coin(1 - BASE_EXPLORATION_RATE):
310
+ overrides["body"] = request_body
311
+ if isinstance(overrides["body"], dict):
312
+ applied_parameters.extend(f"body.{field}" for field in overrides["body"])
313
+ else:
314
+ applied_parameters.append("body")
278
315
 
279
316
  cases = st.one_of(
280
- target.as_strategy(generation_mode=mode, phase=TestPhase.STATEFUL, **kwargs) for mode in modes
317
+ [target.as_strategy(generation_mode=mode, phase=TestPhase.STATEFUL, **overrides) for mode in modes]
281
318
  )
282
319
  case = draw(cases)
283
- if (
284
- transition.request_body is not None
285
- and isinstance(transition.request_body.value, Ok)
286
- and transition.request_body.value.ok() is not UNRESOLVABLE
287
- and link.merge_body
288
- and draw(st.integers(min_value=0, max_value=99)) < USE_TRANSITION_THRESHOLD
289
- ):
290
- new = transition.request_body.value.ok()
291
- if isinstance(case.body, dict) and isinstance(new, dict):
292
- case.body = {**case.body, **new}
293
- else:
294
- case.body = new
295
- is_applied = True
320
+ if request_body is not NOT_SET and link.merge_body:
321
+ if isinstance(request_body, dict):
322
+ selected_fields = {}
323
+
324
+ for field_name, field_value in request_body.items():
325
+ if field_value is UNRESOLVABLE:
326
+ continue
327
+
328
+ if biased_coin(1 - BASE_EXPLORATION_RATE):
329
+ selected_fields[field_name] = field_value
330
+ applied_parameters.append(f"body.{field_name}")
331
+
332
+ if selected_fields:
333
+ if isinstance(case.body, dict):
334
+ case.body = {**case.body, **selected_fields}
335
+ else:
336
+ # Can't merge into non-dict, replace entirely
337
+ case.body = selected_fields
338
+ elif biased_coin(1 - BASE_EXPLORATION_RATE):
339
+ case.body = request_body
340
+ applied_parameters.append("body")
341
+
342
+ # Re-validate generation mode after merging body
296
343
  if case.meta and case.meta.generation.mode == GenerationMode.NEGATIVE:
297
344
  # It is possible that the new body is now valid and the whole test case could be valid too
298
345
  for alternative in case.operation.body:
@@ -304,7 +351,7 @@ def into_step_input(
304
351
  )
305
352
  if all(info.mode == GenerationMode.POSITIVE for info in case.meta.components.values()):
306
353
  case.meta.generation.mode = GenerationMode.POSITIVE
307
- return StepInput(case=case, transition=transition, is_applied=is_applied)
354
+ return StepInput(case=case, transition=transition, applied_parameters=applied_parameters)
308
355
 
309
356
  return inner(output=_output)
310
357
 
@@ -10,7 +10,11 @@ from typing import TYPE_CHECKING, Any
10
10
  from schemathesis.core import NOT_SET
11
11
  from schemathesis.core.compat import RefResolutionError
12
12
  from schemathesis.core.result import Ok
13
- from schemathesis.specs.openapi.stateful.dependencies.inputs import extract_inputs, update_input_field_bindings
13
+ from schemathesis.specs.openapi.stateful.dependencies.inputs import (
14
+ extract_inputs,
15
+ merge_related_resources,
16
+ update_input_field_bindings,
17
+ )
14
18
  from schemathesis.specs.openapi.stateful.dependencies.models import (
15
19
  CanonicalizationCache,
16
20
  Cardinality,
@@ -25,6 +29,7 @@ from schemathesis.specs.openapi.stateful.dependencies.models import (
25
29
  ResourceMap,
26
30
  )
27
31
  from schemathesis.specs.openapi.stateful.dependencies.outputs import extract_outputs
32
+ from schemathesis.specs.openapi.stateful.dependencies.resources import remove_unused_resources
28
33
 
29
34
  if TYPE_CHECKING:
30
35
  from schemathesis.schemas import APIOperation
@@ -88,6 +93,12 @@ def analyze(schema: BaseOpenAPISchema) -> DependencyGraph:
88
93
  for resource in updated_resources:
89
94
  update_input_field_bindings(resource, operations)
90
95
 
96
+ # Merge parameter-inferred resources with schema-defined ones
97
+ merge_related_resources(operations, resources)
98
+
99
+ # Clean up orphaned resources
100
+ remove_unused_resources(operations, resources)
101
+
91
102
  return DependencyGraph(operations=operations, resources=resources)
92
103
 
93
104
 
@@ -14,6 +14,7 @@ from schemathesis.specs.openapi.stateful.dependencies.models import (
14
14
  DefinitionSource,
15
15
  InputSlot,
16
16
  OperationMap,
17
+ OutputSlot,
17
18
  ResourceDefinition,
18
19
  ResourceMap,
19
20
  )
@@ -39,7 +40,7 @@ def extract_inputs(
39
40
  creating placeholder resources if not yet discovered from their schemas.
40
41
  """
41
42
  known_dependencies = set()
42
- for param in operation.path_parameters:
43
+ for param in operation.iter_parameters():
43
44
  input_slot = _resolve_parameter_dependency(
44
45
  parameter_name=param.name,
45
46
  parameter_location=param.location,
@@ -310,3 +311,118 @@ def update_input_field_bindings(resource_name: str, operations: OperationMap) ->
310
311
  )
311
312
  if new_field is not None:
312
313
  input_slot.resource_field = new_field
314
+
315
+
316
+ def merge_related_resources(operations: OperationMap, resources: ResourceMap) -> None:
317
+ """Merge parameter-inferred resources with schema-defined resources from related operations."""
318
+ candidates = find_producer_consumer_candidates(operations)
319
+
320
+ for producer_name, consumer_name in candidates:
321
+ producer = operations[producer_name]
322
+ consumer = operations[consumer_name]
323
+
324
+ # Try to upgrade each input slot
325
+ for input_slot in consumer.inputs:
326
+ result = try_merge_input_resource(input_slot, producer.outputs, resources)
327
+
328
+ if result is not None:
329
+ new_resource_name, new_field_name = result
330
+ # Update input slot to use the better resource definition
331
+ input_slot.resource = resources[new_resource_name]
332
+ input_slot.resource_field = new_field_name
333
+
334
+
335
+ def try_merge_input_resource(
336
+ input_slot: InputSlot,
337
+ producer_outputs: list[OutputSlot],
338
+ resources: ResourceMap,
339
+ ) -> tuple[str, str] | None:
340
+ """Try to upgrade an input's resource to a producer's resource."""
341
+ consumer_resource = input_slot.resource
342
+
343
+ # Only upgrade parameter-inferred resources (low confidence)
344
+ if consumer_resource.source != DefinitionSource.PARAMETER_INFERENCE:
345
+ return None
346
+
347
+ # Try each producer output
348
+ for output in producer_outputs:
349
+ producer_resource = resources[output.resource.name]
350
+
351
+ # Only merge to schema-defined resources (high confidence)
352
+ if producer_resource.source != DefinitionSource.SCHEMA_WITH_PROPERTIES:
353
+ continue
354
+
355
+ # Try to match the input parameter to producer's fields
356
+ param_name = input_slot.parameter_name
357
+ if not isinstance(param_name, str):
358
+ continue
359
+
360
+ for resource_name in (input_slot.resource.name, producer_resource.name):
361
+ matched_field = naming.find_matching_field(
362
+ parameter=param_name,
363
+ resource=resource_name,
364
+ fields=producer_resource.fields,
365
+ )
366
+
367
+ if matched_field is not None:
368
+ return (producer_resource.name, matched_field)
369
+
370
+ return None
371
+
372
+
373
+ def find_producer_consumer_candidates(operations: OperationMap) -> list[tuple[str, str]]:
374
+ """Find operation pairs that might produce/consume the same resource via REST patterns."""
375
+ candidates = []
376
+
377
+ # Group by base path to reduce comparisons
378
+ paths: dict[str, list[str]] = {}
379
+ for name, node in operations.items():
380
+ base = _extract_base_path(node.path)
381
+ paths.setdefault(base, []).append(name)
382
+
383
+ # Within each path group, find POST/PUT → GET/DELETE/PATCH patterns
384
+ for names in paths.values():
385
+ for producer_name in names:
386
+ producer = operations[producer_name]
387
+ # Producer must create/update and return data
388
+ if producer.method not in ("post", "put") or not producer.outputs:
389
+ continue
390
+
391
+ for consumer_name in names:
392
+ consumer = operations[consumer_name]
393
+ # Consumer must have path parameters
394
+ if not consumer.inputs:
395
+ continue
396
+ # Paths must be related (collection + item pattern)
397
+ if _is_collection_item_pattern(producer.path, consumer.path):
398
+ candidates.append((producer_name, consumer_name))
399
+
400
+ return candidates
401
+
402
+
403
+ def _extract_base_path(path: str) -> str:
404
+ """Extract collection path: /blog/posts/{id} -> /blog/posts."""
405
+ parts = [p for p in path.split("/") if not p.startswith("{")]
406
+ return "/".join(parts).rstrip("/")
407
+
408
+
409
+ def _is_collection_item_pattern(collection_path: str, item_path: str) -> bool:
410
+ """Check if paths follow REST collection/item pattern."""
411
+ # /blog/posts + /blog/posts/{postId}
412
+ normalized_collection = collection_path.rstrip("/")
413
+ normalized_item = item_path.rstrip("/")
414
+
415
+ # Must start with collection path
416
+ if not normalized_item.startswith(normalized_collection + "/"):
417
+ return False
418
+
419
+ # Extract the segment after collection path
420
+ remainder = normalized_item[len(normalized_collection) + 1 :]
421
+
422
+ # Must be a single path parameter: {paramName} with no slashes
423
+ return (
424
+ remainder.startswith("{")
425
+ and remainder.endswith("}")
426
+ and len(remainder) > 2 # Not empty {}
427
+ and "/" not in remainder
428
+ )
@@ -13,6 +13,7 @@ from schemathesis.specs.openapi.stateful.dependencies.models import (
13
13
  CanonicalizationCache,
14
14
  Cardinality,
15
15
  DefinitionSource,
16
+ OperationMap,
16
17
  ResourceDefinition,
17
18
  ResourceMap,
18
19
  extend_pointer,
@@ -310,3 +311,18 @@ def _extract_resource_from_schema(
310
311
  resources[resource_name] = resource
311
312
 
312
313
  return resource
314
+
315
+
316
+ def remove_unused_resources(operations: OperationMap, resources: ResourceMap) -> None:
317
+ """Remove resources that aren't referenced by any operation."""
318
+ # Collect all resource names currently in use
319
+ used_resources = set()
320
+ for operation in operations.values():
321
+ for input_slot in operation.inputs:
322
+ used_resources.add(input_slot.resource.name)
323
+ for output_slot in operation.outputs:
324
+ used_resources.add(output_slot.resource.name)
325
+
326
+ unused = set(resources.keys()) - used_resources
327
+ for resource_name in unused:
328
+ del resources[resource_name]
@@ -23,8 +23,9 @@ class NormalizedParameter:
23
23
  name: str
24
24
  expression: str
25
25
  container_name: str
26
+ is_required: bool
26
27
 
27
- __slots__ = ("location", "name", "expression", "container_name")
28
+ __slots__ = ("location", "name", "expression", "container_name", "is_required")
28
29
 
29
30
 
30
31
  @dataclass(repr=False)
@@ -131,15 +132,21 @@ class OpenApiLink:
131
132
  except Exception as exc:
132
133
  errors.append(TransitionValidationError(str(exc)))
133
134
 
135
+ is_required = False
134
136
  if hasattr(self, "target"):
135
137
  try:
136
138
  container_name = self._get_parameter_container(location, name)
137
139
  except TransitionValidationError as exc:
138
140
  errors.append(exc)
139
141
  continue
142
+
143
+ for param in self.target.iter_parameters():
144
+ if param.name == name:
145
+ is_required = param.is_required
146
+ break
140
147
  else:
141
148
  continue
142
- result.append(NormalizedParameter(location, name, expression, container_name))
149
+ result.append(NormalizedParameter(location, name, expression, container_name, is_required=is_required))
143
150
  return result
144
151
 
145
152
  def _get_parameter_container(self, location: ParameterLocation | None, name: str) -> str:
@@ -178,7 +185,9 @@ class OpenApiLink:
178
185
  value = Ok(expressions.evaluate(parameter.expression, output))
179
186
  except Exception as exc:
180
187
  value = Err(exc)
181
- container[parameter.name] = ExtractedParam(definition=parameter.expression, value=value)
188
+ container[parameter.name] = ExtractedParam(
189
+ definition=parameter.expression, value=value, is_required=parameter.is_required
190
+ )
182
191
  return extracted
183
192
 
184
193
  def extract_body(self, output: StepOutput) -> ExtractedParam | None:
@@ -188,7 +197,7 @@ class OpenApiLink:
188
197
  value = Ok(expressions.evaluate(self.body, output, evaluate_nested=True))
189
198
  except Exception as exc:
190
199
  value = Err(exc)
191
- return ExtractedParam(definition=self.body, value=value)
200
+ return ExtractedParam(definition=self.body, value=value, is_required=True)
192
201
  return None
193
202
 
194
203
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.3.11
3
+ Version: 4.3.12
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
@@ -104,7 +104,7 @@ schemathesis/generation/hypothesis/examples.py,sha256=6eGaKUEC3elmKsaqfKj1sLvM8E
104
104
  schemathesis/generation/hypothesis/given.py,sha256=sTZR1of6XaHAPWtHx2_WLlZ50M8D5Rjux0GmWkWjDq4,2337
105
105
  schemathesis/generation/hypothesis/reporting.py,sha256=uDVow6Ya8YFkqQuOqRsjbzsbyP4KKfr3jA7ZaY4FuKY,279
106
106
  schemathesis/generation/stateful/__init__.py,sha256=s7jiJEnguIj44IsRyMi8afs-8yjIUuBbzW58bH5CHjs,1042
107
- schemathesis/generation/stateful/state_machine.py,sha256=25kkYImw5byNwuTtt97aNE3kTHAF8rZ-p3ax_bmd3JI,9135
107
+ schemathesis/generation/stateful/state_machine.py,sha256=3whIW5WDL_-IZIeZLB-qlxIr0_DNC6fb6pZ_0U7ifkE,9285
108
108
  schemathesis/graphql/__init__.py,sha256=_eO6MAPHGgiADVGRntnwtPxmuvk666sAh-FAU4cG9-0,326
109
109
  schemathesis/graphql/checks.py,sha256=IADbxiZjgkBWrC5yzHDtohRABX6zKXk5w_zpWNwdzYo,3186
110
110
  schemathesis/graphql/loaders.py,sha256=2tgG4HIvFmjHLr_KexVXnT8hSBM-dKG_fuXTZgE97So,9445
@@ -159,16 +159,16 @@ schemathesis/specs/openapi/negative/__init__.py,sha256=B78vps314fJOMZwlPdv7vUHo7
159
159
  schemathesis/specs/openapi/negative/mutations.py,sha256=9U352xJsdZBR-Zfy1V7_X3a5i91LIUS9Zqotrzp3BLA,21000
160
160
  schemathesis/specs/openapi/negative/types.py,sha256=a7buCcVxNBG6ILBM3A7oNTAX0lyDseEtZndBuej8MbI,174
161
161
  schemathesis/specs/openapi/negative/utils.py,sha256=ozcOIuASufLqZSgnKUACjX-EOZrrkuNdXX0SDnLoGYA,168
162
- schemathesis/specs/openapi/stateful/__init__.py,sha256=EkGiy1ksv0lH7IDBfR6Bdo1D9kaT5dLIJUwoz-p7hkw,16594
162
+ schemathesis/specs/openapi/stateful/__init__.py,sha256=T-iYOxPh3GfvKUxrc2f2u_GSeO0HUYajn2qVw2F6sGA,18802
163
163
  schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8n5ePqSKB00XFxp-MA,3695
164
164
  schemathesis/specs/openapi/stateful/inference.py,sha256=B99jSTDVi2yKxU7-raIb91xpacOrr0nZkEZY5Ej3eCY,9783
165
- schemathesis/specs/openapi/stateful/links.py,sha256=SSA66mU50FFBz7e6sA37CfL-Vt0OY3gont72oFSvZYU,8163
166
- schemathesis/specs/openapi/stateful/dependencies/__init__.py,sha256=0JM-FrY6Awv6gl-qDHaaK7pXbt_GKutBKPyIaph8apA,7842
167
- schemathesis/specs/openapi/stateful/dependencies/inputs.py,sha256=PSactImp4OqsYMHUl2gB2pgvUlZCCKJRJKeaalclFzU,11511
165
+ schemathesis/specs/openapi/stateful/links.py,sha256=P4CISEi-BVRtXd9cXBnHuvxInxW1LBa7DVYcnaZAhBU,8530
166
+ schemathesis/specs/openapi/stateful/dependencies/__init__.py,sha256=9FWF7tiP7GaOwapRFIYjsu16LxkosKCzBvzjkSTCsjU,8183
167
+ schemathesis/specs/openapi/stateful/dependencies/inputs.py,sha256=sQydINThS6vp9-OnTKCb_unoVP4m3Ho-0xTG0K7ps8Q,15915
168
168
  schemathesis/specs/openapi/stateful/dependencies/models.py,sha256=Kl482Hwq2M8lYAdqGmf_8Yje3voSj1WLDUIujRUDWDQ,12286
169
169
  schemathesis/specs/openapi/stateful/dependencies/naming.py,sha256=NnXEFY1W3i18jEEYGgC_8oLoE7YOxdXgcMYtZvLj10w,12920
170
170
  schemathesis/specs/openapi/stateful/dependencies/outputs.py,sha256=zvVUfQWNIuhMkKDpz5hsVGkkvkefLt1EswpJAnHajOw,1186
171
- schemathesis/specs/openapi/stateful/dependencies/resources.py,sha256=p58XoADpMKFAun0Bx_rul-kiUlfA9PXjxHJ97dT2tBE,11202
171
+ schemathesis/specs/openapi/stateful/dependencies/resources.py,sha256=MLitJnn1vUihhzuCIA-l7uXG6ne3YTUlnyAAbKaz2Ls,11824
172
172
  schemathesis/specs/openapi/stateful/dependencies/schemas.py,sha256=RaG1BJH4D7-o5Qs2rIRQvS8ERntMUEs2I5jXUFaKMRo,14147
173
173
  schemathesis/specs/openapi/types/__init__.py,sha256=VPsWtLJle__Kodw_QqtQ3OuvBzBcCIKsTOrXy3eA7OU,66
174
174
  schemathesis/specs/openapi/types/v3.py,sha256=Vondr9Amk6JKCIM6i6RGcmTUjFfPgOOqzBXqerccLpo,1468
@@ -178,8 +178,8 @@ schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEz
178
178
  schemathesis/transport/requests.py,sha256=wriRI9fprTplE_qEZLEz1TerX6GwkE3pwr6ZnU2o6vQ,10648
179
179
  schemathesis/transport/serialization.py,sha256=GwO6OAVTmL1JyKw7HiZ256tjV4CbrRbhQN0ep1uaZwI,11157
180
180
  schemathesis/transport/wsgi.py,sha256=kQtasFre6pjdJWRKwLA_Qb-RyQHCFNpaey9ubzlFWKI,5907
181
- schemathesis-4.3.11.dist-info/METADATA,sha256=yx5kZtdpuluVpHR7jIERaQlKLfLpYa7h__hOuJMAyyU,8566
182
- schemathesis-4.3.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
183
- schemathesis-4.3.11.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
184
- schemathesis-4.3.11.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
185
- schemathesis-4.3.11.dist-info/RECORD,,
181
+ schemathesis-4.3.12.dist-info/METADATA,sha256=udwQ_n-qA4_1ZwxJDDhMNe6WUrUp4LJ8mnDdbOhapFY,8566
182
+ schemathesis-4.3.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
183
+ schemathesis-4.3.12.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
184
+ schemathesis-4.3.12.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
185
+ schemathesis-4.3.12.dist-info/RECORD,,