schemathesis 3.38.7__py3-none-any.whl → 3.38.8__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.
@@ -237,17 +237,17 @@ def _iter_coverage_cases(
237
237
  template: dict[str, Any] = {}
238
238
  responses = find_in_responses(operation)
239
239
  for parameter in operation.iter_parameters():
240
+ location = parameter.location
241
+ name = parameter.name
240
242
  schema = parameter.as_json_schema(operation, update_quantifiers=False)
241
243
  for value in find_matching_in_responses(responses, parameter.name):
242
244
  schema.setdefault("examples", []).append(value)
243
245
  gen = coverage.cover_schema_iter(
244
- coverage.CoverageContext(data_generation_methods=data_generation_methods), schema
246
+ coverage.CoverageContext(location=location, data_generation_methods=data_generation_methods), schema
245
247
  )
246
248
  value = next(gen, NOT_SET)
247
249
  if isinstance(value, NotSet):
248
250
  continue
249
- location = parameter.location
250
- name = parameter.name
251
251
  container = template.setdefault(LOCATION_TO_CONTAINER[location], {})
252
252
  if location in ("header", "cookie", "path", "query") and not isinstance(value.value, str):
253
253
  container[name] = _stringify_value(value.value, location)
@@ -263,7 +263,7 @@ def _iter_coverage_cases(
263
263
  if examples:
264
264
  schema.setdefault("examples", []).extend(examples)
265
265
  gen = coverage.cover_schema_iter(
266
- coverage.CoverageContext(data_generation_methods=data_generation_methods), schema
266
+ coverage.CoverageContext(location="body", data_generation_methods=data_generation_methods), schema
267
267
  )
268
268
  value = next(gen, NOT_SET)
269
269
  if isinstance(value, NotSet):
@@ -417,7 +417,7 @@ def _iter_coverage_cases(
417
417
  subschema: dict[str, Any], _location: str, _container_name: str
418
418
  ) -> Generator[Case, None, None]:
419
419
  for more in coverage.cover_schema_iter(
420
- coverage.CoverageContext(data_generation_methods=[DataGenerationMethod.negative]),
420
+ coverage.CoverageContext(location=_location, data_generation_methods=[DataGenerationMethod.negative]),
421
421
  subschema,
422
422
  ):
423
423
  yield make_case(
@@ -432,17 +432,26 @@ def _iter_coverage_cases(
432
432
  # 1. Generate only required properties
433
433
  if required and all_params != required:
434
434
  only_required = {k: v for k, v in base_container.items() if k in required}
435
- yield make_case(
436
- only_required, "Only required properties", location, container_name, None, DataGenerationMethod.positive
437
- )
435
+ if DataGenerationMethod.positive in data_generation_methods:
436
+ yield make_case(
437
+ only_required,
438
+ "Only required properties",
439
+ location,
440
+ container_name,
441
+ None,
442
+ DataGenerationMethod.positive,
443
+ )
438
444
  if DataGenerationMethod.negative in data_generation_methods:
439
445
  subschema = _combination_schema(only_required, required, parameter_set)
440
- yield from _yield_negative(subschema, location, container_name)
446
+ for case in _yield_negative(subschema, location, container_name):
447
+ # Already generated in one of the blocks above
448
+ if location != "path" and not case.meta.description.startswith("Missing required property"):
449
+ yield case
441
450
 
442
451
  # 2. Generate combinations with required properties and one optional property
443
452
  for opt_param in optional:
444
453
  combo = {k: v for k, v in base_container.items() if k in required or k == opt_param}
445
- if combo != base_container:
454
+ if combo != base_container and DataGenerationMethod.positive in data_generation_methods:
446
455
  yield make_case(
447
456
  combo,
448
457
  f"All required properties and optional '{opt_param}'",
@@ -456,7 +465,7 @@ def _iter_coverage_cases(
456
465
  yield from _yield_negative(subschema, location, container_name)
457
466
 
458
467
  # 3. Generate one combination for each size from 2 to N-1 of optional parameters
459
- if len(optional) > 1:
468
+ if len(optional) > 1 and DataGenerationMethod.positive in data_generation_methods:
460
469
  for size in range(2, len(optional)):
461
470
  for combination in combinations(optional, size):
462
471
  combo = {k: v for k, v in base_container.items() if k in required or k in combination}
@@ -323,6 +323,15 @@ REPORT_TO_SERVICE = ReportToService()
323
323
  multiple=True,
324
324
  metavar="",
325
325
  )
326
+ @grouped_option(
327
+ "--experimental-missing-required-header-allowed-statuses",
328
+ "missing_required_header_allowed_statuses",
329
+ help="Comma-separated list of status codes expected for test cases with a missing required header",
330
+ type=CsvListChoice(),
331
+ callback=callbacks.convert_status_codes,
332
+ metavar="",
333
+ envvar="SCHEMATHESIS_EXPERIMENTAL_MISSING_REQUIRED_HEADER_ALLOWED_STATUSES",
334
+ )
326
335
  @grouped_option(
327
336
  "--experimental-positive-data-acceptance-allowed-statuses",
328
337
  "positive_data_acceptance_allowed_statuses",
@@ -855,6 +864,7 @@ def run(
855
864
  set_cookie: dict[str, str],
856
865
  set_path: dict[str, str],
857
866
  experiments: list,
867
+ missing_required_header_allowed_statuses: list[str],
858
868
  positive_data_acceptance_allowed_statuses: list[str],
859
869
  negative_data_rejection_allowed_statuses: list[str],
860
870
  checks: Iterable[str] = DEFAULT_CHECKS_NAMES,
@@ -1172,6 +1182,11 @@ def run(
1172
1182
  selected_checks += (positive_data_acceptance,)
1173
1183
  if positive_data_acceptance_allowed_statuses:
1174
1184
  checks_config.positive_data_acceptance.allowed_statuses = positive_data_acceptance_allowed_statuses
1185
+ if missing_required_header_allowed_statuses:
1186
+ from ..specs.openapi.checks import missing_required_header
1187
+
1188
+ selected_checks += (missing_required_header,)
1189
+ checks_config.missing_required_header.allowed_statuses = missing_required_header_allowed_statuses
1175
1190
  if negative_data_rejection_allowed_statuses:
1176
1191
  checks_config.negative_data_rejection.allowed_statuses = negative_data_rejection_allowed_statuses
1177
1192
 
@@ -21,6 +21,7 @@ from ..internal.copy import fast_deepcopy
21
21
  from ..specs.openapi.converter import update_pattern_in_schema
22
22
  from ..specs.openapi.formats import STRING_FORMATS, get_default_format_strategies
23
23
  from ..specs.openapi.patterns import update_quantifier
24
+ from ..transports.headers import has_invalid_characters, is_latin_1_encodable
24
25
  from ._hypothesis import get_single_example
25
26
  from ._methods import DataGenerationMethod
26
27
 
@@ -103,42 +104,55 @@ def cached_draw(strategy: st.SearchStrategy) -> Any:
103
104
  @dataclass
104
105
  class CoverageContext:
105
106
  data_generation_methods: list[DataGenerationMethod]
106
- location_stack: list[str | int]
107
+ location: str
108
+ path: list[str | int]
107
109
 
108
- __slots__ = ("data_generation_methods", "location_stack")
110
+ __slots__ = ("location", "data_generation_methods", "path")
109
111
 
110
112
  def __init__(
111
113
  self,
114
+ *,
115
+ location: str,
112
116
  data_generation_methods: list[DataGenerationMethod] | None = None,
113
- location_stack: list[str | int] | None = None,
117
+ path: list[str | int] | None = None,
114
118
  ) -> None:
119
+ self.location = location
115
120
  self.data_generation_methods = (
116
121
  data_generation_methods if data_generation_methods is not None else DataGenerationMethod.all()
117
122
  )
118
- self.location_stack = location_stack or []
123
+ self.path = path or []
119
124
 
120
125
  @contextmanager
121
- def location(self, key: str | int) -> Generator[None, None, None]:
122
- self.location_stack.append(key)
126
+ def at(self, key: str | int) -> Generator[None, None, None]:
127
+ self.path.append(key)
123
128
  try:
124
129
  yield
125
130
  finally:
126
- self.location_stack.pop()
131
+ self.path.pop()
127
132
 
128
133
  @property
129
- def current_location(self) -> str:
130
- return "/" + "/".join(str(key) for key in self.location_stack)
134
+ def current_path(self) -> str:
135
+ return "/" + "/".join(str(key) for key in self.path)
131
136
 
132
137
  def with_positive(self) -> CoverageContext:
133
138
  return CoverageContext(
134
- data_generation_methods=[DataGenerationMethod.positive], location_stack=self.location_stack
139
+ location=self.location,
140
+ data_generation_methods=[DataGenerationMethod.positive],
141
+ path=self.path,
135
142
  )
136
143
 
137
144
  def with_negative(self) -> CoverageContext:
138
145
  return CoverageContext(
139
- data_generation_methods=[DataGenerationMethod.negative], location_stack=self.location_stack
146
+ location=self.location,
147
+ data_generation_methods=[DataGenerationMethod.negative],
148
+ path=self.path,
140
149
  )
141
150
 
151
+ def is_valid_for_location(self, value: Any) -> bool:
152
+ if self.location in ("header", "cookie") and isinstance(value, str):
153
+ return is_latin_1_encodable(value) and not has_invalid_characters("", value)
154
+ return True
155
+
142
156
  def generate_from(self, strategy: st.SearchStrategy) -> Any:
143
157
  return cached_draw(strategy)
144
158
 
@@ -322,7 +336,7 @@ def cover_schema_iter(
322
336
  if DataGenerationMethod.negative in ctx.data_generation_methods:
323
337
  template = None
324
338
  for key, value in schema.items():
325
- with _ignore_unfixable(), ctx.location(key):
339
+ with _ignore_unfixable(), ctx.at(key):
326
340
  if key == "enum":
327
341
  yield from _negative_enum(ctx, value, seen)
328
342
  elif key == "const":
@@ -350,21 +364,17 @@ def cover_schema_iter(
350
364
  elif key == "maximum":
351
365
  next = value + 1
352
366
  if next not in seen:
353
- yield NegativeValue(
354
- next, description="Value greater than maximum", location=ctx.current_location
355
- )
367
+ yield NegativeValue(next, description="Value greater than maximum", location=ctx.current_path)
356
368
  seen.add(next)
357
369
  elif key == "minimum":
358
370
  next = value - 1
359
371
  if next not in seen:
360
- yield NegativeValue(
361
- next, description="Value smaller than minimum", location=ctx.current_location
362
- )
372
+ yield NegativeValue(next, description="Value smaller than minimum", location=ctx.current_path)
363
373
  seen.add(next)
364
374
  elif key == "exclusiveMaximum" or key == "exclusiveMinimum" and value not in seen:
365
375
  verb = "greater" if key == "exclusiveMaximum" else "smaller"
366
376
  limit = "maximum" if key == "exclusiveMaximum" else "minimum"
367
- yield NegativeValue(value, description=f"Value {verb} than {limit}", location=ctx.current_location)
377
+ yield NegativeValue(value, description=f"Value {verb} than {limit}", location=ctx.current_path)
368
378
  seen.add(value)
369
379
  elif key == "multipleOf":
370
380
  for value_ in _negative_multiple_of(ctx, schema, value):
@@ -391,7 +401,7 @@ def cover_schema_iter(
391
401
  k = _to_hashable_key(value)
392
402
  if k not in seen:
393
403
  yield NegativeValue(
394
- value, description="String smaller than minLength", location=ctx.current_location
404
+ value, description="String smaller than minLength", location=ctx.current_path
395
405
  )
396
406
  seen.add(k)
397
407
  elif key == "maxLength" and value < BUFFER_SIZE:
@@ -413,7 +423,7 @@ def cover_schema_iter(
413
423
  k = _to_hashable_key(value)
414
424
  if k not in seen:
415
425
  yield NegativeValue(
416
- value, description="String larger than maxLength", location=ctx.current_location
426
+ value, description="String larger than maxLength", location=ctx.current_path
417
427
  )
418
428
  seen.add(k)
419
429
  except (InvalidArgument, Unsatisfiable):
@@ -428,12 +438,12 @@ def cover_schema_iter(
428
438
  yield NegativeValue(
429
439
  {**template, UNKNOWN_PROPERTY_KEY: UNKNOWN_PROPERTY_VALUE},
430
440
  description="Object with unexpected properties",
431
- location=ctx.current_location,
441
+ location=ctx.current_path,
432
442
  )
433
443
  elif key == "allOf":
434
444
  nctx = ctx.with_negative()
435
445
  if len(value) == 1:
436
- with nctx.location(0):
446
+ with nctx.at(0):
437
447
  yield from cover_schema_iter(nctx, value[0], seen)
438
448
  else:
439
449
  with _ignore_unfixable():
@@ -443,7 +453,7 @@ def cover_schema_iter(
443
453
  nctx = ctx.with_negative()
444
454
  # NOTE: Other sub-schemas are not filtered out
445
455
  for idx, sub_schema in enumerate(value):
446
- with nctx.location(idx):
456
+ with nctx.at(idx):
447
457
  yield from cover_schema_iter(nctx, sub_schema, seen)
448
458
 
449
459
 
@@ -487,15 +497,17 @@ def _positive_string(ctx: CoverageContext, schema: dict) -> Generator[GeneratedV
487
497
  examples = schema.get("examples")
488
498
  default = schema.get("default")
489
499
  if example or examples or default:
490
- if example:
500
+ if example and ctx.is_valid_for_location(example):
491
501
  yield PositiveValue(example, description="Example value")
492
502
  if examples:
493
503
  for example in examples:
494
- yield PositiveValue(example, description="Example value")
504
+ if ctx.is_valid_for_location(example):
505
+ yield PositiveValue(example, description="Example value")
495
506
  if (
496
507
  default
497
508
  and not (example is not None and default == example)
498
509
  and not (examples is not None and any(default == ex for ex in examples))
510
+ and ctx.is_valid_for_location(default)
499
511
  ):
500
512
  yield PositiveValue(default, description="Default value")
501
513
  elif not min_length and not max_length:
@@ -755,7 +767,7 @@ def _negative_enum(
755
767
 
756
768
  strategy = (st.none() | st.booleans() | NUMERIC_STRATEGY | st.text()).filter(is_not_in_value)
757
769
  value = ctx.generate_from(strategy)
758
- yield NegativeValue(value, description="Invalid enum value", location=ctx.current_location)
770
+ yield NegativeValue(value, description="Invalid enum value", location=ctx.current_path)
759
771
  hashed = _to_hashable_key(value)
760
772
  seen.add(hashed)
761
773
 
@@ -765,12 +777,12 @@ def _negative_properties(
765
777
  ) -> Generator[GeneratedValue, None, None]:
766
778
  nctx = ctx.with_negative()
767
779
  for key, sub_schema in properties.items():
768
- with nctx.location(key):
780
+ with nctx.at(key):
769
781
  for value in cover_schema_iter(nctx, sub_schema):
770
782
  yield NegativeValue(
771
783
  {**template, key: value.value},
772
784
  description=f"Object with invalid '{key}' value: {value.description}",
773
- location=nctx.current_location,
785
+ location=nctx.current_path,
774
786
  parameter=key,
775
787
  )
776
788
 
@@ -784,12 +796,12 @@ def _negative_pattern_properties(
784
796
  key = ctx.generate_from(st.from_regex(pattern))
785
797
  except re.error:
786
798
  continue
787
- with nctx.location(pattern):
799
+ with nctx.at(pattern):
788
800
  for value in cover_schema_iter(nctx, sub_schema):
789
801
  yield NegativeValue(
790
802
  {**template, key: value.value},
791
803
  description=f"Object with invalid pattern key '{key}' ('{pattern}') value: {value.description}",
792
- location=nctx.current_location,
804
+ location=nctx.current_path,
793
805
  )
794
806
 
795
807
 
@@ -800,7 +812,7 @@ def _negative_items(ctx: CoverageContext, schema: dict[str, Any] | bool) -> Gene
800
812
  yield NegativeValue(
801
813
  [value.value],
802
814
  description=f"Array with invalid items: {value.description}",
803
- location=nctx.current_location,
815
+ location=nctx.current_path,
804
816
  )
805
817
 
806
818
 
@@ -822,7 +834,7 @@ def _negative_pattern(
822
834
  )
823
835
  ),
824
836
  description=f"Value not matching the '{pattern}' pattern",
825
- location=ctx.current_location,
837
+ location=ctx.current_path,
826
838
  )
827
839
 
828
840
 
@@ -836,13 +848,13 @@ def _negative_multiple_of(
836
848
  yield NegativeValue(
837
849
  ctx.generate_from_schema(_with_negated_key(schema, "multipleOf", multiple_of)),
838
850
  description=f"Non-multiple of {multiple_of}",
839
- location=ctx.current_location,
851
+ location=ctx.current_path,
840
852
  )
841
853
 
842
854
 
843
855
  def _negative_unique_items(ctx: CoverageContext, schema: dict) -> Generator[GeneratedValue, None, None]:
844
856
  unique = ctx.generate_from_schema({**schema, "type": "array", "minItems": 1, "maxItems": 1})
845
- yield NegativeValue(unique + unique, description="Non-unique items", location=ctx.current_location)
857
+ yield NegativeValue(unique + unique, description="Non-unique items", location=ctx.current_path)
846
858
 
847
859
 
848
860
  def _negative_required(
@@ -852,7 +864,7 @@ def _negative_required(
852
864
  yield NegativeValue(
853
865
  {k: v for k, v in template.items() if k != key},
854
866
  description=f"Missing required property: {key}",
855
- location=ctx.current_location,
867
+ location=ctx.current_path,
856
868
  parameter=key,
857
869
  )
858
870
 
@@ -878,7 +890,7 @@ def _negative_format(ctx: CoverageContext, schema: dict, format: str) -> Generat
878
890
  yield NegativeValue(
879
891
  ctx.generate_from(strategy),
880
892
  description=f"Value not matching the '{format}' format",
881
- location=ctx.current_location,
893
+ location=ctx.current_path,
882
894
  )
883
895
 
884
896
 
@@ -901,7 +913,7 @@ def _negative_type(ctx: CoverageContext, seen: set, ty: str | list[str]) -> Gene
901
913
  hashed = _to_hashable_key(value)
902
914
  if hashed in seen:
903
915
  continue
904
- yield NegativeValue(value, description="Incorrect type", location=ctx.current_location)
916
+ yield NegativeValue(value, description="Incorrect type", location=ctx.current_path)
905
917
  seen.add(hashed)
906
918
 
907
919
 
@@ -29,8 +29,14 @@ class PositiveDataAcceptanceConfig:
29
29
  allowed_statuses: list[str] = field(default_factory=lambda: ["2xx", "401", "403", "404"])
30
30
 
31
31
 
32
+ @dataclass
33
+ class MissingRequiredHeaderConfig:
34
+ allowed_statuses: list[str] = field(default_factory=lambda: ["406"])
35
+
36
+
32
37
  @dataclass
33
38
  class CheckConfig:
39
+ missing_required_header: MissingRequiredHeaderConfig = field(default_factory=MissingRequiredHeaderConfig)
34
40
  negative_data_rejection: NegativeDataRejectionConfig = field(default_factory=NegativeDataRejectionConfig)
35
41
  positive_data_acceptance: PositiveDataAcceptanceConfig = field(default_factory=PositiveDataAcceptanceConfig)
36
42
 
schemathesis/models.py CHANGED
@@ -622,6 +622,7 @@ class Case:
622
622
  cookies=fast_deepcopy(self.cookies),
623
623
  query=fast_deepcopy(self.query),
624
624
  body=fast_deepcopy(self.body),
625
+ meta=self.meta,
625
626
  generation_time=self.generation_time,
626
627
  id=self.id,
627
628
  _auth=self._auth,
@@ -269,6 +269,20 @@ def positive_data_acceptance(ctx: CheckContext, response: GenericResponse, case:
269
269
  return None
270
270
 
271
271
 
272
+ def missing_required_header(ctx: CheckContext, response: GenericResponse, case: Case) -> bool | None:
273
+ if (
274
+ case.meta
275
+ and case.meta.parameter_location == "header"
276
+ and case.meta.description
277
+ and case.meta.description.startswith("Missing ")
278
+ ):
279
+ config = ctx.config.missing_required_header
280
+ allowed_statuses = expand_status_codes(config.allowed_statuses or [])
281
+ if response.status_code not in allowed_statuses:
282
+ raise AssertionError(f"Unexpected response status for a missing header: {response.status_code}")
283
+ return None
284
+
285
+
272
286
  def has_only_additional_properties_in_non_body_parameters(case: Case) -> bool:
273
287
  # Check if the case contains only additional properties in query, headers, or cookies.
274
288
  # This function is used to determine if negation is solely in the form of extra properties,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: schemathesis
3
- Version: 3.38.7
3
+ Version: 3.38.8
4
4
  Summary: Property-based testing framework for Open API and GraphQL based apps
5
5
  Project-URL: Documentation, https://schemathesis.readthedocs.io/en/stable/
6
6
  Project-URL: Changelog, https://schemathesis.readthedocs.io/en/stable/changelog.html
@@ -1,7 +1,7 @@
1
1
  schemathesis/__init__.py,sha256=UW2Bq8hDDkcBeAAA7PzpBFXkOOxkmHox-mfQwzHDjL0,1914
2
2
  schemathesis/_compat.py,sha256=y4RZd59i2NCnZ91VQhnKeMn_8t3SgvLOk2Xm8nymUHY,1837
3
3
  schemathesis/_dependency_versions.py,sha256=pjEkkGAfOQJYNb-9UOo84V8nj_lKHr_TGDVdFwY2UU0,816
4
- schemathesis/_hypothesis.py,sha256=7hQItl5JqtctCiN7gL4DhWmj8A0Ku6t1_pkxEqkID1g,23463
4
+ schemathesis/_hypothesis.py,sha256=ykQfiCkqguKcGVekVD8rMlTVOHT6BcURUa-0vMwT1HE,24044
5
5
  schemathesis/_lazy_import.py,sha256=aMhWYgbU2JOltyWBb32vnWBb6kykOghucEzI_F70yVE,470
6
6
  schemathesis/_override.py,sha256=TAjYB3eJQmlw9K_xiR9ptt9Wj7if4U7UFlUhGjpBAoM,1625
7
7
  schemathesis/_patches.py,sha256=Hsbpn4UVeXUQD2Kllrbq01CSWsTYENWa0VJTyhX5C2k,895
@@ -18,7 +18,7 @@ schemathesis/graphql.py,sha256=XiuKcfoOB92iLFC8zpz2msLkM0_V0TLdxPNBqrrGZ8w,216
18
18
  schemathesis/hooks.py,sha256=p5AXgjVGtka0jn9MOeyBaRUtNbqZTs4iaJqytYTacHc,14856
19
19
  schemathesis/lazy.py,sha256=Ddhkk7Tpc_VcRGYkCtKDmP2gpjxVmEZ3b01ZTNjbm8I,19004
20
20
  schemathesis/loaders.py,sha256=MoEhcdOEBJxNRn5X-ZNhWB9jZDHQQNpkNfEdQjf_NDw,4590
21
- schemathesis/models.py,sha256=Xn1rEF0_g3HNqJaJB9sC8N3gJ9suFPPlgc8ho01VyF0,49769
21
+ schemathesis/models.py,sha256=zE-j-5uyQdIxnWx-rqJyXCbyrWZlrTyiTml109yZeN4,49797
22
22
  schemathesis/parameters.py,sha256=izlu4MFYT1RWrC4RBxrV6weeCal-ODbdLQLMb0PYCZY,2327
23
23
  schemathesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  schemathesis/sanitization.py,sha256=Lycn1VVfula9B6XpzkxTHja7CZ7RHqbUh9kBic0Yi4M,9056
@@ -28,7 +28,7 @@ schemathesis/targets.py,sha256=XIGRghvEzbmEJjse9aZgNEj67L3jAbiazm2rxURWgDE,2351
28
28
  schemathesis/throttling.py,sha256=aisUc4MJDGIOGUAs9L2DlWWpdd4KyAFuNVKhYoaUC9M,1719
29
29
  schemathesis/types.py,sha256=Tem2Q_zyMCd0Clp5iGKv6Fu13wdcbxVE8tCVH9WWt7A,1065
30
30
  schemathesis/utils.py,sha256=LwqxqoAKmRiAdj-qUbNmgQgsamc49V5lc5TnOIDuuMA,4904
31
- schemathesis/cli/__init__.py,sha256=rAebJYQrORWsl4WR6sLUseJCQQZbDEsaQex52kmn6kI,74536
31
+ schemathesis/cli/__init__.py,sha256=GlM52jH2p8pSoHnSc0mfxNRTGVLslT_9rTLLy3jgbgo,75272
32
32
  schemathesis/cli/__main__.py,sha256=MWaenjaUTZIfNPFzKmnkTiawUri7DVldtg3mirLwzU8,92
33
33
  schemathesis/cli/callbacks.py,sha256=-VA_I_mVma9WxFNtUR8d2KNICKJD5ScayfSdKKPEP5Y,16321
34
34
  schemathesis/cli/cassettes.py,sha256=zji-B-uuwyr0Z0BzQX-DLMV6lWb58JtLExcUE1v3m4Y,20153
@@ -61,9 +61,9 @@ schemathesis/fixups/utf8_bom.py,sha256=lWT9RNmJG8i-l5AXIpaCT3qCPUwRgzXPW3eoOjmZE
61
61
  schemathesis/generation/__init__.py,sha256=29Zys_tD6kfngaC4zHeC6TOBZQcmo7CWm7KDSYsHStQ,1581
62
62
  schemathesis/generation/_hypothesis.py,sha256=74fzLPHugZgMQXerWYFAMqCAjtAXz5E4gek7Gnkhli4,1756
63
63
  schemathesis/generation/_methods.py,sha256=r8oVlJ71_gXcnEhU-byw2E0R2RswQQFm8U7yGErSqbw,1204
64
- schemathesis/generation/coverage.py,sha256=Y-eKsEDe6INu-2SjlzGpuzayRXF_wdDwTBLsW4pGlrc,38843
64
+ schemathesis/generation/coverage.py,sha256=VUUhzD-X-nCDYqu-nxqiAAYKJMoa2MgzvGsa7x2xUmI,39177
65
65
  schemathesis/internal/__init__.py,sha256=93HcdG3LF0BbQKbCteOsFMa1w6nXl8yTmx87QLNJOik,161
66
- schemathesis/internal/checks.py,sha256=SBx2gesB-XzgVSMX_u7Mb416jSxJ68eQKtcdkWlkyOo,2441
66
+ schemathesis/internal/checks.py,sha256=EI5EjN_PI9QWNwJlsnUKjC6B1r0arRdpqniVZT-N0mE,2672
67
67
  schemathesis/internal/copy.py,sha256=DcL56z-d69kKR_5u8mlHvjSL1UTyUKNMAwexrwHFY1s,1031
68
68
  schemathesis/internal/datetime.py,sha256=zPLBL0XXLNfP-KYel3H2m8pnsxjsA_4d-zTOhJg2EPQ,136
69
69
  schemathesis/internal/deprecation.py,sha256=Ty5VBFBlufkITpP0WWTPIPbnB7biDi0kQgXVYWZp820,1273
@@ -107,7 +107,7 @@ schemathesis/specs/graphql/validation.py,sha256=uINIOt-2E7ZuQV2CxKzwez-7L9tDtqzM
107
107
  schemathesis/specs/openapi/__init__.py,sha256=HDcx3bqpa6qWPpyMrxAbM3uTo0Lqpg-BUNZhDJSJKnw,279
108
108
  schemathesis/specs/openapi/_cache.py,sha256=PAiAu4X_a2PQgD2lG5H3iisXdyg4SaHpU46bRZvfNkM,4320
109
109
  schemathesis/specs/openapi/_hypothesis.py,sha256=nU8UDn1PzGCre4IVmwIuO9-CZv1KJe1fYY0d2BojhSo,22981
110
- schemathesis/specs/openapi/checks.py,sha256=NZwcqmLnINq3rUUUmdof0GGB0AjaqSF5dOQy08nsJPg,23902
110
+ schemathesis/specs/openapi/checks.py,sha256=MbFRk78U1m5iVGVOJNKifM2KgaGHQaT1DOF6HdR1UZQ,24496
111
111
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
112
112
  schemathesis/specs/openapi/converter.py,sha256=Yxw9lS_JKEyi-oJuACT07fm04bqQDlAu-iHwzkeDvE4,3546
113
113
  schemathesis/specs/openapi/definitions.py,sha256=WTkWwCgTc3OMxfKsqh6YDoGfZMTThSYrHGp8h0vLAK0,93935
@@ -153,8 +153,8 @@ schemathesis/transports/auth.py,sha256=urSTO9zgFO1qU69xvnKHPFQV0SlJL3d7_Ojl0tLnZ
153
153
  schemathesis/transports/content_types.py,sha256=MiKOm-Hy5i75hrROPdpiBZPOTDzOwlCdnthJD12AJzI,2187
154
154
  schemathesis/transports/headers.py,sha256=hr_AIDOfUxsJxpHfemIZ_uNG3_vzS_ZeMEKmZjbYiBE,990
155
155
  schemathesis/transports/responses.py,sha256=OFD4ZLqwEFpo7F9vaP_SVgjhxAqatxIj38FS4XVq8Qs,1680
156
- schemathesis-3.38.7.dist-info/METADATA,sha256=iBsAbz1uaJxY_GUPTnjdD2uMxS3HCk6lX_4IVj_s2yY,12923
157
- schemathesis-3.38.7.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
158
- schemathesis-3.38.7.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
159
- schemathesis-3.38.7.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
160
- schemathesis-3.38.7.dist-info/RECORD,,
156
+ schemathesis-3.38.8.dist-info/METADATA,sha256=640ItX9m5YtdbKoT_P64ZVwFWnMtp2a7wrJN6G9XUpM,12923
157
+ schemathesis-3.38.8.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
158
+ schemathesis-3.38.8.dist-info/entry_points.txt,sha256=VHyLcOG7co0nOeuk8WjgpRETk5P1E2iCLrn26Zkn5uk,158
159
+ schemathesis-3.38.8.dist-info/licenses/LICENSE,sha256=PsPYgrDhZ7g9uwihJXNG-XVb55wj2uYhkl2DD8oAzY0,1103
160
+ schemathesis-3.38.8.dist-info/RECORD,,