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

@@ -5,6 +5,8 @@ from __future__ import annotations
5
5
  import enum
6
6
  import re
7
7
  import traceback
8
+ from dataclasses import dataclass
9
+ from textwrap import indent
8
10
  from types import TracebackType
9
11
  from typing import TYPE_CHECKING, Any, Callable, NoReturn
10
12
 
@@ -33,6 +35,60 @@ class SchemathesisError(Exception):
33
35
  """Base exception class for all Schemathesis errors."""
34
36
 
35
37
 
38
+ class DefinitionKind(str, enum.Enum):
39
+ SCHEMA = "Schema Object"
40
+ SECURITY_SCHEME = "Security Scheme Object"
41
+ RESPONSES = "Responses Object"
42
+ PARAMETER = "Parameter Object"
43
+
44
+
45
+ @dataclass
46
+ class SchemaLocation:
47
+ kind: DefinitionKind
48
+ # Hint about where the definition is located
49
+ hint: str | None
50
+ # Open API spec version
51
+ version: str
52
+
53
+ __slots__ = ("kind", "hint", "version")
54
+
55
+ @classmethod
56
+ def response_schema(cls, version: str) -> SchemaLocation:
57
+ return cls(kind=DefinitionKind.SCHEMA, hint="in response definition", version=version)
58
+
59
+ @classmethod
60
+ def maybe_from_error_path(cls, path: list[str | int], version: str) -> SchemaLocation | None:
61
+ if len(path) == 3 and path[:2] == ["components", "securitySchemes"]:
62
+ return cls(kind=DefinitionKind.SECURITY_SCHEME, hint=f"definition for `{path[2]}`", version=version)
63
+ if len(path) == 3 and path[:2] == ["components", "schemas"]:
64
+ return cls(kind=DefinitionKind.SCHEMA, hint=f"definition for `{path[2]}`", version=version)
65
+ if len(path) == 4 and path[0] == "paths" and path[-1] == "responses":
66
+ return cls(kind=DefinitionKind.RESPONSES, hint=None, version=version)
67
+ if len(path) == 5 and path[0] == "paths" and path[3] == "parameters":
68
+ return cls(kind=DefinitionKind.PARAMETER, hint=f"at index {path[4]}", version=version)
69
+
70
+ return None
71
+
72
+ @property
73
+ def message(self) -> str:
74
+ message = f"Invalid {self.kind.value}"
75
+ if self.hint is not None:
76
+ message += f" {self.hint}"
77
+ else:
78
+ message += " definition"
79
+ return message
80
+
81
+ @property
82
+ def specification_url(self) -> str:
83
+ anchor = {
84
+ DefinitionKind.SCHEMA: "schema-object",
85
+ DefinitionKind.SECURITY_SCHEME: "security-scheme-object",
86
+ DefinitionKind.RESPONSES: "responses-object",
87
+ DefinitionKind.PARAMETER: "parameter-object",
88
+ }[self.kind]
89
+ return f"https://spec.openapis.org/oas/v{self.version}#{anchor}"
90
+
91
+
36
92
  class InvalidSchema(SchemathesisError):
37
93
  """Indicates errors in API schema validation or processing."""
38
94
 
@@ -56,9 +112,16 @@ class InvalidSchema(SchemathesisError):
56
112
 
57
113
  @classmethod
58
114
  def from_jsonschema_error(
59
- cls, error: ValidationError | JsonSchemaError, path: str | None, method: str | None, config: OutputConfig
115
+ cls,
116
+ error: ValidationError | JsonSchemaError,
117
+ path: str | None,
118
+ method: str | None,
119
+ config: OutputConfig,
120
+ location: SchemaLocation | None = None,
60
121
  ) -> InvalidSchema:
61
- if error.absolute_path:
122
+ if location is not None:
123
+ message = location.message
124
+ elif error.absolute_path:
62
125
  part = error.absolute_path[-1]
63
126
  if isinstance(part, int) and len(error.absolute_path) > 1:
64
127
  parent = error.absolute_path[-2]
@@ -70,14 +133,18 @@ class InvalidSchema(SchemathesisError):
70
133
  error_path = " -> ".join(str(entry) for entry in error.path) or "[root]"
71
134
  message += f"\n\nLocation:\n {error_path}"
72
135
  instance = truncate_json(error.instance, config=config)
73
- message += f"\n\nProblematic definition:\n{instance}"
136
+ message += f"\n\nProblematic definition:\n{indent(instance, ' ')}"
74
137
  message += "\n\nError details:\n "
75
138
  # This default message contains the instance which we already printed
76
139
  if "is not valid under any of the given schemas" in error.message:
77
140
  message += "The provided definition doesn't match any of the expected formats or types."
78
141
  else:
79
142
  message += error.message
80
- message += f"\n\n{SCHEMA_ERROR_SUGGESTION}"
143
+ message += "\n\n"
144
+ if location is not None:
145
+ message += f"See: {location.specification_url}"
146
+ else:
147
+ message += SCHEMA_ERROR_SUGGESTION
81
148
  return cls(message, path=path, method=method)
82
149
 
83
150
  @classmethod
@@ -86,12 +153,14 @@ class InvalidSchema(SchemathesisError):
86
153
  ) -> InvalidSchema:
87
154
  notes = getattr(error, "__notes__", [])
88
155
  # Some exceptions don't have the actual reference in them, hence we add it manually via notes
89
- pointer = f"'{notes[0]}'"
90
- message = "Unresolvable JSON pointer in the schema"
156
+ reference = str(notes[0])
157
+ message = "Unresolvable reference in the schema"
91
158
  # Get the pointer value from "Unresolvable JSON pointer: 'components/UnknownParameter'"
92
- message += f"\n\nError details:\n JSON pointer: {pointer}"
93
- message += "\n This typically means that the schema is referencing a component that doesn't exist."
94
- message += f"\n\n{SCHEMA_ERROR_SUGGESTION}"
159
+ message += f"\n\nError details:\n Reference: {reference}"
160
+ if not reference.startswith(("http://", "https://", "#/")):
161
+ message += "\n File reference could not be resolved. Check that the file exists."
162
+ elif reference.startswith(("#/components", "#/definitions")):
163
+ message += "\n Component does not exist in the schema."
95
164
  return cls(message, path=path, method=method)
96
165
 
97
166
  def as_failing_test_function(self) -> Callable:
@@ -154,13 +223,13 @@ class InvalidStateMachine(SchemathesisError):
154
223
  for source, target_groups in by_source.items():
155
224
  for (target, status), transitions in target_groups.items():
156
225
  for transition in transitions:
157
- result += f"\n\n {_format_transition(source, status, transition.name, target)}\n"
226
+ result += f"\n\n {format_transition(source, status, transition.name, target)}\n"
158
227
  for error in transition.errors:
159
228
  result += f"\n - {error.message}"
160
229
  return result
161
230
 
162
231
 
163
- def _format_transition(source: str, status: str, transition: str, target: str) -> str:
232
+ def format_transition(source: str, status: str, transition: str, target: str) -> str:
164
233
  return f"{source} -> [{status}] {transition} -> {target}"
165
234
 
166
235
 
@@ -25,6 +25,7 @@ from schemathesis.core.errors import (
25
25
  InvalidRegexType,
26
26
  InvalidSchema,
27
27
  MalformedMediaType,
28
+ SchemaLocation,
28
29
  SerializationNotPossible,
29
30
  )
30
31
  from schemathesis.core.failures import Failure, FailureGroup
@@ -198,6 +199,9 @@ def run_test(
198
199
  path=operation.path,
199
200
  method=operation.method,
200
201
  config=ctx.config.output,
202
+ location=SchemaLocation.maybe_from_error_path(
203
+ list(exc.absolute_path), ctx.schema.specification.version
204
+ ),
201
205
  )
202
206
  )
203
207
  except InvalidArgument as exc:
@@ -50,6 +50,9 @@ class StepInput:
50
50
 
51
51
  @property
52
52
  def is_applied(self) -> bool:
53
+ # If the transition has no parameters or body, count it as applied
54
+ if self.transition is not None and not self.transition.parameters and self.transition.request_body is None:
55
+ return True
53
56
  return bool(self.applied_parameters)
54
57
 
55
58
 
@@ -27,7 +27,13 @@ from requests.structures import CaseInsensitiveDict
27
27
  from schemathesis.core import INJECTED_PATH_PARAMETER_KEY, NOT_SET, NotSet, Specification, deserialization, media_types
28
28
  from schemathesis.core.adapter import OperationParameter, ResponsesContainer
29
29
  from schemathesis.core.compat import RefResolutionError
30
- from schemathesis.core.errors import InfiniteRecursiveReference, InvalidSchema, OperationNotFound
30
+ from schemathesis.core.errors import (
31
+ SCHEMA_ERROR_SUGGESTION,
32
+ InfiniteRecursiveReference,
33
+ InvalidSchema,
34
+ OperationNotFound,
35
+ SchemaLocation,
36
+ )
31
37
  from schemathesis.core.failures import Failure, FailureGroup, MalformedJson
32
38
  from schemathesis.core.result import Err, Ok, Result
33
39
  from schemathesis.core.transport import Response
@@ -61,7 +67,6 @@ if TYPE_CHECKING:
61
67
  from schemathesis.generation.stateful import APIStateMachine
62
68
 
63
69
  HTTP_METHODS = frozenset({"get", "put", "post", "delete", "options", "head", "patch", "trace"})
64
- SCHEMA_ERROR_MESSAGE = "Ensure that the definition complies with the OpenAPI specification"
65
70
  SCHEMA_PARSING_ERRORS = (KeyError, AttributeError, RefResolutionError, InvalidSchema, InfiniteRecursiveReference)
66
71
 
67
72
 
@@ -317,9 +322,13 @@ class BaseOpenAPISchema(BaseSchema):
317
322
  self.validate()
318
323
  except jsonschema.ValidationError as exc:
319
324
  raise InvalidSchema.from_jsonschema_error(
320
- exc, path=path, method=method, config=self.config.output
325
+ exc,
326
+ path=path,
327
+ method=method,
328
+ config=self.config.output,
329
+ location=SchemaLocation.maybe_from_error_path(list(exc.absolute_path), self.specification.version),
321
330
  ) from None
322
- raise InvalidSchema(SCHEMA_ERROR_MESSAGE, path=path, method=method) from error
331
+ raise InvalidSchema(SCHEMA_ERROR_SUGGESTION, path=path, method=method) from error
323
332
 
324
333
  def validate(self) -> None:
325
334
  with suppress(TypeError):
@@ -540,7 +549,11 @@ class BaseOpenAPISchema(BaseSchema):
540
549
  definition.validator.validate(data)
541
550
  except jsonschema.SchemaError as exc:
542
551
  raise InvalidSchema.from_jsonschema_error(
543
- exc, path=operation.path, method=operation.method, config=self.config.output
552
+ exc,
553
+ path=operation.path,
554
+ method=operation.method,
555
+ config=self.config.output,
556
+ location=SchemaLocation.response_schema(self.specification.version),
544
557
  ) from exc
545
558
  except jsonschema.ValidationError as exc:
546
559
  failures.append(
@@ -167,9 +167,7 @@ def create_state_machine(schema: BaseOpenAPISchema) -> type[APIStateMachine]:
167
167
  if incoming:
168
168
  for link in incoming:
169
169
  bundle_name = f"{link.source.label} -> {link.status_code}"
170
- name = _normalize_name(
171
- f"{link.source.label} -> {link.status_code} -> {link.name} -> {target.label}"
172
- )
170
+ name = _normalize_name(link.full_name)
173
171
  assert name not in rules, name
174
172
  rules[name] = precondition(is_transition_allowed(bundle_name, link.source.label, target.label))(
175
173
  transition(
@@ -237,8 +235,8 @@ def classify_root_transitions(operations: list[APIOperation], transitions: ApiTr
237
235
 
238
236
  def is_likely_root_transition(operation: APIOperation) -> bool:
239
237
  """Check if operation is likely to succeed as a root transition."""
240
- # POST operations with request bodies are likely to create resources
241
- if operation.method == "post" and operation.body:
238
+ # POST operations are likely to create resources
239
+ if operation.method == "post":
242
240
  return True
243
241
 
244
242
  # GET operations without path parameters are likely to return lists
@@ -394,13 +394,13 @@ def find_matching_field(*, parameter: str, resource: str, fields: list[str]) ->
394
394
  return field
395
395
 
396
396
  # Extract parameter components
397
- parameter_prefix, param_suffix = _split_parameter_name(parameter)
397
+ parameter_prefix, parameter_suffix = _split_parameter_name(parameter)
398
398
  parameter_prefix_normalized = _normalize_for_matching(parameter_prefix)
399
399
 
400
400
  # Parameter has resource prefix, field might not
401
401
  # Example: `channelId` - `Channel.id`
402
402
  if parameter_prefix and parameter_prefix_normalized == resource_normalized:
403
- suffix_normalized = _normalize_for_matching(param_suffix)
403
+ suffix_normalized = _normalize_for_matching(parameter_suffix)
404
404
 
405
405
  for field in fields:
406
406
  field_normalized = _normalize_for_matching(field)
@@ -409,8 +409,8 @@ def find_matching_field(*, parameter: str, resource: str, fields: list[str]) ->
409
409
 
410
410
  # Parameter has no prefix, field might have resource prefix
411
411
  # Example: `id` - `Channel.channelId`
412
- if not parameter_prefix and param_suffix:
413
- expected_field_normalized = resource_normalized + _normalize_for_matching(param_suffix)
412
+ if not parameter_prefix and parameter_suffix:
413
+ expected_field_normalized = resource_normalized + _normalize_for_matching(parameter_suffix)
414
414
 
415
415
  for field in fields:
416
416
  field_normalized = _normalize_for_matching(field)
@@ -433,7 +433,7 @@ def _normalize_for_matching(text: str) -> str:
433
433
  return text.lower().replace("_", "").replace("-", "")
434
434
 
435
435
 
436
- def _split_parameter_name(param_name: str) -> tuple[str, str]:
436
+ def _split_parameter_name(parameter_name: str) -> tuple[str, str]:
437
437
  """Split parameter into (prefix, suffix) components.
438
438
 
439
439
  Examples:
@@ -444,13 +444,16 @@ def _split_parameter_name(param_name: str) -> tuple[str, str]:
444
444
  "channel_id" -> ("channel", "_id")
445
445
 
446
446
  """
447
- if param_name.endswith("Id") and len(param_name) > 2:
448
- return (param_name[:-2], "Id")
447
+ if parameter_name.endswith("Id") and len(parameter_name) > 2:
448
+ return (parameter_name[:-2], "Id")
449
449
 
450
- if param_name.endswith("_id") and len(param_name) > 3:
451
- return (param_name[:-3], "_id")
450
+ if parameter_name.endswith("_id") and len(parameter_name) > 3:
451
+ return (parameter_name[:-3], "_id")
452
452
 
453
- return ("", param_name)
453
+ if parameter_name.endswith("_guid") and len(parameter_name) > 5:
454
+ return (parameter_name[:-5], "_guid")
455
+
456
+ return ("", parameter_name)
454
457
 
455
458
 
456
459
  def strip_affixes(name: str, prefixes: list[str], suffixes: list[str]) -> str:
@@ -294,7 +294,13 @@ def _extract_resource_from_schema(
294
294
  properties = resolved.get("properties")
295
295
  if properties:
296
296
  fields = sorted(properties)
297
- types = {field: set(get_type(subschema)) for field, subschema in properties.items()}
297
+ types = {}
298
+ for field, subschema in properties.items():
299
+ if isinstance(subschema, dict):
300
+ _, resolved_subschema = maybe_resolve(subschema, resolver, "")
301
+ else:
302
+ resolved_subschema = subschema
303
+ types[field] = set(get_type(cast(dict, resolved_subschema)))
298
304
  source = DefinitionSource.SCHEMA_WITH_PROPERTIES
299
305
  else:
300
306
  fields = []
@@ -232,30 +232,38 @@ def unwrap_schema(
232
232
  _, resolved = maybe_resolve(array_schema, resolver, "")
233
233
  pointer = f"/{encode_pointer(array_field)}"
234
234
 
235
+ uses_parent_ref = False
235
236
  # Try to unwrap one more time
236
237
  if resolved.get("type") == "array" or "items" in resolved:
237
238
  nested_items = resolved.get("items")
238
239
  if isinstance(nested_items, dict):
239
240
  _, resolved_items = maybe_resolve(nested_items, resolver, "")
240
- external_tag = _detect_externally_tagged_pattern(resolved_items, path)
241
+ external_tag = _detect_externally_tagged_pattern(resolved_items, path, parent_ref)
241
242
  if external_tag:
242
- nested_properties = resolved_items["properties"][external_tag]
243
+ external_tag_, uses_parent_ref = external_tag
244
+ nested_properties = resolved_items["properties"][external_tag_]
243
245
  _, resolved = maybe_resolve(nested_properties, resolver, "")
244
- pointer += f"/{encode_pointer(external_tag)}"
246
+ pointer += f"/{encode_pointer(external_tag_)}"
245
247
 
248
+ ref = parent_ref if uses_parent_ref else array_schema.get("$ref")
246
249
  return UnwrappedSchema(pointer=pointer, schema=resolved, ref=array_schema.get("$ref"))
247
250
 
248
251
  # External tag
249
- external_tag = _detect_externally_tagged_pattern(schema, path)
252
+ external_tag = _detect_externally_tagged_pattern(schema, path, parent_ref)
250
253
  if external_tag:
251
- tagged_schema = properties[external_tag]
254
+ external_tag_, uses_parent_ref = external_tag
255
+ tagged_schema = properties[external_tag_]
252
256
  _, resolved_tagged = maybe_resolve(tagged_schema, resolver, "")
253
257
 
254
258
  resolved = try_unwrap_all_of(resolved_tagged)
255
- ref = resolved.get("$ref") or resolved_tagged.get("$ref") or tagged_schema.get("$ref")
259
+ ref = (
260
+ parent_ref
261
+ if uses_parent_ref
262
+ else resolved.get("$ref") or resolved_tagged.get("$ref") or tagged_schema.get("$ref")
263
+ )
256
264
 
257
265
  _, resolved = maybe_resolve(resolved, resolver, "")
258
- return UnwrappedSchema(pointer=f"/{encode_pointer(external_tag)}", schema=resolved, ref=ref)
266
+ return UnwrappedSchema(pointer=f"/{encode_pointer(external_tag_)}", schema=resolved, ref=ref)
259
267
 
260
268
  # No wrapper - single object at root
261
269
  return UnwrappedSchema(pointer="/", schema=schema, ref=schema.get("$ref"))
@@ -391,7 +399,9 @@ def _is_pagination_wrapper(
391
399
  return None
392
400
 
393
401
 
394
- def _detect_externally_tagged_pattern(schema: Mapping[str, Any], path: str) -> str | None:
402
+ def _detect_externally_tagged_pattern(
403
+ schema: Mapping[str, Any], path: str, parent_ref: str | None
404
+ ) -> tuple[str, bool] | None:
395
405
  """Detect externally tagged resource pattern.
396
406
 
397
407
  Pattern: {ResourceName: [...]} or {resourceName: [...]}
@@ -420,12 +430,18 @@ def _detect_externally_tagged_pattern(schema: Mapping[str, Any], path: str) -> s
420
430
  # `data_request`
421
431
  naming.to_snake_case(resource_name),
422
432
  }
433
+ parent_names = set()
434
+ if parent_ref is not None:
435
+ maybe_resource_name = resource_name_from_ref(parent_ref)
436
+ parent_names.add(naming.to_plural(maybe_resource_name.lower()))
437
+ parent_names.add(naming.to_snake_case(maybe_resource_name))
438
+ possible_names = possible_names.union(parent_names)
423
439
 
424
440
  for name, subschema in properties.items():
425
441
  if name.lower() not in possible_names:
426
442
  continue
427
443
 
428
444
  if isinstance(subschema, dict) and "object" in get_type(subschema):
429
- return name
445
+ return name, name.lower() in parent_names
430
446
 
431
447
  return None
@@ -5,7 +5,7 @@ from functools import lru_cache
5
5
  from typing import Any, Callable
6
6
 
7
7
  from schemathesis.core import NOT_SET, NotSet
8
- from schemathesis.core.errors import InvalidTransition, OperationNotFound, TransitionValidationError
8
+ from schemathesis.core.errors import InvalidTransition, OperationNotFound, TransitionValidationError, format_transition
9
9
  from schemathesis.core.parameters import ParameterLocation
10
10
  from schemathesis.core.result import Err, Ok, Result
11
11
  from schemathesis.generation.stateful.state_machine import ExtractedParam, StepOutput, Transition
@@ -94,6 +94,10 @@ class OpenApiLink:
94
94
 
95
95
  self._cached_extract = lru_cache(8)(self._extract_impl)
96
96
 
97
+ @property
98
+ def full_name(self) -> str:
99
+ return format_transition(self.source.label, self.status_code, self.name, self.target.label)
100
+
97
101
  def _normalize_parameters(
98
102
  self, parameters: dict[str, str], errors: list[TransitionValidationError]
99
103
  ) -> list[NormalizedParameter]:
@@ -165,7 +169,7 @@ class OpenApiLink:
165
169
  def _extract_impl(self, wrapper: StepOutputWrapper) -> Transition:
166
170
  output = wrapper.output
167
171
  return Transition(
168
- id=f"{self.source.label} -> [{self.status_code}] {self.name} -> {self.target.label}",
172
+ id=self.full_name,
169
173
  parent_id=output.case.id,
170
174
  is_inferred=self.is_inferred,
171
175
  parameters=self.extract_parameters(output),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.3.12
3
+ Version: 4.3.13
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
@@ -52,7 +52,7 @@ schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1
52
52
  schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
53
53
  schemathesis/core/curl.py,sha256=jrPL9KpNHteyJ6A1oxJRSkL5bfuBeuPs3xh9Z_ml2cE,1892
54
54
  schemathesis/core/deserialization.py,sha256=qjXUPaz_mc1OSgXzTUSkC8tuVR8wgVQtb9g3CcAF6D0,2951
55
- schemathesis/core/errors.py,sha256=KlcDlsxg9sHKdo-NtFDluhk1iwQbSHdpDGykf8CxOKY,17357
55
+ schemathesis/core/errors.py,sha256=sr23WgbD-52n5fmC-QBn2suzNUbsB1okvXIs_L5EyR0,19918
56
56
  schemathesis/core/failures.py,sha256=yFpAxWdEnm0Ri8z8RqRI9H7vcLH5ztOeSIi4m4SGx5g,8996
57
57
  schemathesis/core/fs.py,sha256=ItQT0_cVwjDdJX9IiI7EnU75NI2H3_DCEyyUjzg_BgI,472
58
58
  schemathesis/core/hooks.py,sha256=qhbkkRSf8URJ4LKv2wmKRINKpquUOgxQzWBHKWRWo3Q,475
@@ -89,7 +89,7 @@ schemathesis/engine/phases/stateful/__init__.py,sha256=Lz1rgNqCfUSIz173XqCGsiMuU
89
89
  schemathesis/engine/phases/stateful/_executor.py,sha256=yRpUJqKLTKMVRy7hEXPwmI23CtgGIprz341lCJwvTrU,15613
90
90
  schemathesis/engine/phases/stateful/context.py,sha256=A7X1SLDOWFpCvFN9IiIeNVZM0emjqatmJL_k9UsO7vM,2946
91
91
  schemathesis/engine/phases/unit/__init__.py,sha256=9dDcxyj887pktnE9YDIPNaR-vc7iqKQWIrFr77SbUTQ,8786
92
- schemathesis/engine/phases/unit/_executor.py,sha256=YDibV3lkC2UMHLvh1FSmnlaQ-SJS-R0MU2qEF4NBbf0,17235
92
+ schemathesis/engine/phases/unit/_executor.py,sha256=4wr7POpPfeI7_Mx6i2pk2efyK1FxKGjXdMwi_MURTDU,17427
93
93
  schemathesis/engine/phases/unit/_pool.py,sha256=iU0hdHDmohPnEv7_S1emcabuzbTf-Cznqwn0pGQ5wNQ,2480
94
94
  schemathesis/generation/__init__.py,sha256=tvNO2FLiY8z3fZ_kL_QJhSgzXfnT4UqwSXMHCwfLI0g,645
95
95
  schemathesis/generation/case.py,sha256=SLMw6zkzmeiZdaIij8_0tjTF70BrMlRSWREaqWii0uM,12508
@@ -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=3whIW5WDL_-IZIeZLB-qlxIr0_DNC6fb6pZ_0U7ifkE,9285
107
+ schemathesis/generation/stateful/state_machine.py,sha256=CiVtpBEeotpNOUkYO3vJLKRe89gdT1kjguZ88vbfqs0,9500
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
@@ -137,7 +137,7 @@ schemathesis/specs/openapi/formats.py,sha256=4tYRdckauHxkJCmOhmdwDq_eOpHPaKloi89
137
137
  schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKRcUOc41eEwKbo,2472
138
138
  schemathesis/specs/openapi/patterns.py,sha256=GqPZEXMRdWENQxanWjBOalIZ2MQUjuxk21kmdiI703E,18027
139
139
  schemathesis/specs/openapi/references.py,sha256=AW1laU23BkiRf0EEFM538vyVFLXycGUiucGVV461le0,1927
140
- schemathesis/specs/openapi/schemas.py,sha256=uTxwggtWi5dWjuKlSDs0DthlNNfcRvSJtrND-PaTkrg,33758
140
+ schemathesis/specs/openapi/schemas.py,sha256=ONFB8kMBrryZL_tKHWvxnBjyUHoHh_MAUqxjuVDc78c,34034
141
141
  schemathesis/specs/openapi/serialization.py,sha256=RPNdadne5wdhsGmjSvgKLRF58wpzpRx3wura8PsHM3o,12152
142
142
  schemathesis/specs/openapi/utils.py,sha256=XkOJT8qD-6uhq-Tmwxk_xYku1Gy5F9pKL3ldNg_DRZw,522
143
143
  schemathesis/specs/openapi/adapter/__init__.py,sha256=YEovBgLjnXd3WGPMJXq0KbSGHezkRlEv4dNRO7_evfk,249
@@ -159,17 +159,17 @@ 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=T-iYOxPh3GfvKUxrc2f2u_GSeO0HUYajn2qVw2F6sGA,18802
162
+ schemathesis/specs/openapi/stateful/__init__.py,sha256=RpGqyjKShp2X94obaHnCR9TO6Qt_ZAarlB-awlyMzUY,18654
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=P4CISEi-BVRtXd9cXBnHuvxInxW1LBa7DVYcnaZAhBU,8530
165
+ schemathesis/specs/openapi/stateful/links.py,sha256=TEZ7wudPdRdP-pg5XNIgYbual_9n2arBKnS2n8SxiaU,8629
166
166
  schemathesis/specs/openapi/stateful/dependencies/__init__.py,sha256=9FWF7tiP7GaOwapRFIYjsu16LxkosKCzBvzjkSTCsjU,8183
167
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
- schemathesis/specs/openapi/stateful/dependencies/naming.py,sha256=NnXEFY1W3i18jEEYGgC_8oLoE7YOxdXgcMYtZvLj10w,12920
169
+ schemathesis/specs/openapi/stateful/dependencies/naming.py,sha256=GoO_Tw04u_7ix6qsAzMDoJooXZqIRAIV8sLphL4mGnw,13084
170
170
  schemathesis/specs/openapi/stateful/dependencies/outputs.py,sha256=zvVUfQWNIuhMkKDpz5hsVGkkvkefLt1EswpJAnHajOw,1186
171
- schemathesis/specs/openapi/stateful/dependencies/resources.py,sha256=MLitJnn1vUihhzuCIA-l7uXG6ne3YTUlnyAAbKaz2Ls,11824
172
- schemathesis/specs/openapi/stateful/dependencies/schemas.py,sha256=RaG1BJH4D7-o5Qs2rIRQvS8ERntMUEs2I5jXUFaKMRo,14147
171
+ schemathesis/specs/openapi/stateful/dependencies/resources.py,sha256=eUWE26ZixPtSuHl7laF2asS_-6qklQRhyQlk7e99hlc,12087
172
+ schemathesis/specs/openapi/stateful/dependencies/schemas.py,sha256=TKM6hEuyLm5NB-jQeEbIXF7GZF-7mqYLq3OsTBRDpws,14878
173
173
  schemathesis/specs/openapi/types/__init__.py,sha256=VPsWtLJle__Kodw_QqtQ3OuvBzBcCIKsTOrXy3eA7OU,66
174
174
  schemathesis/specs/openapi/types/v3.py,sha256=Vondr9Amk6JKCIM6i6RGcmTUjFfPgOOqzBXqerccLpo,1468
175
175
  schemathesis/transport/__init__.py,sha256=6yg_RfV_9L0cpA6qpbH-SL9_3ggtHQji9CZrpIkbA6s,5321
@@ -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.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,,
181
+ schemathesis-4.3.13.dist-info/METADATA,sha256=n-G9iaIj5lgmV9oro_G7FL4f2tAeI9xOXaLe95r6WnA,8566
182
+ schemathesis-4.3.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
183
+ schemathesis-4.3.13.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
184
+ schemathesis-4.3.13.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
185
+ schemathesis-4.3.13.dist-info/RECORD,,