schemathesis 4.0.18__py3-none-any.whl → 4.0.20__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.
@@ -52,7 +52,7 @@ class InvalidSchema(SchemathesisError):
52
52
 
53
53
  @classmethod
54
54
  def from_jsonschema_error(
55
- cls, error: ValidationError, path: str | None, method: str | None, config: OutputConfig
55
+ cls, error: ValidationError | JsonSchemaError, path: str | None, method: str | None, config: OutputConfig
56
56
  ) -> InvalidSchema:
57
57
  if error.absolute_path:
58
58
  part = error.absolute_path[-1]
@@ -513,6 +513,8 @@ def ignored_auth(ctx: CheckContext, response: Response, case: Case) -> bool | No
513
513
  _remove_auth_from_container(container, security_parameters, location=location)
514
514
  kwargs[container_name] = container
515
515
  kwargs.pop("session", None)
516
+ if case.operation.app is not None:
517
+ kwargs.setdefault("app", case.operation.app)
516
518
  ctx._record_case(parent_id=case.id, case=no_auth_case)
517
519
  no_auth_response = case.operation.schema.transport.send(no_auth_case, **kwargs)
518
520
  ctx._record_response(case_id=no_auth_case.id, response=no_auth_response)
@@ -34,7 +34,7 @@ def to_json_schema(
34
34
  update_pattern_in_schema(schema)
35
35
  # Sometimes `required` is incorrectly has a boolean value
36
36
  properties = schema.get("properties")
37
- if properties:
37
+ if isinstance(properties, dict):
38
38
  for name, subschema in properties.items():
39
39
  if not isinstance(subschema, dict):
40
40
  continue
@@ -174,8 +174,18 @@ def _handle_anchored_pattern(parsed: list, pattern: str, min_length: int | None,
174
174
  continue
175
175
  if pattern[current_position] == "\\":
176
176
  # Escaped value
177
- current_position += 2
178
177
  result += "\\"
178
+ # Could be an octal value
179
+ if (
180
+ current_position + 2 < len(pattern)
181
+ and pattern[current_position + 1] == "0"
182
+ and pattern[current_position + 2] in ("0", "1", "2", "3", "4", "5", "6", "7")
183
+ ):
184
+ result += pattern[current_position + 1]
185
+ result += pattern[current_position + 2]
186
+ current_position += 3
187
+ continue
188
+ current_position += 2
179
189
  else:
180
190
  current_position += 1
181
191
  result += chr(value)
@@ -349,13 +359,58 @@ def _handle_repeat_quantifier(
349
359
  ) -> str:
350
360
  """Handle repeat quantifiers (e.g., '+', '*', '?')."""
351
361
  min_repeat, max_repeat, _ = value
352
- min_length, max_length = _build_size(min_repeat, max_repeat, min_length, max_length)
353
- if min_length > max_length:
354
- return pattern
362
+
363
+ # First, analyze the inner pattern
355
364
  inner = _strip_quantifier(pattern)
356
365
  if inner.startswith("(") and inner.endswith(")"):
357
366
  inner = inner[1:-1]
358
- return f"({inner})" + _build_quantifier(min_length, max_length)
367
+
368
+ # Determine the length of the inner pattern
369
+ inner_length = 1 # default assumption for non-literal patterns
370
+ try:
371
+ parsed = sre_parse.parse(inner)
372
+ if all(item[0] == LITERAL for item in parsed):
373
+ inner_length = len(parsed)
374
+ if max_length and max_length > 0 and inner_length > max_length:
375
+ return pattern
376
+ except re.error:
377
+ pass
378
+
379
+ if inner_length == 0:
380
+ # Empty pattern contributes 0 chars regardless of repetitions
381
+ # For length constraints, only 0 repetitions make sense
382
+ if min_length is not None and min_length > 0:
383
+ return pattern # Can't satisfy positive length with empty pattern
384
+ return f"({inner})" + _build_quantifier(0, 0)
385
+
386
+ # Convert external length constraints to repetition constraints
387
+ external_min_repeat = None
388
+ external_max_repeat = None
389
+
390
+ if min_length is not None:
391
+ # Need at least ceil(min_length / inner_length) repetitions
392
+ external_min_repeat = (min_length + inner_length - 1) // inner_length
393
+
394
+ if max_length is not None:
395
+ # Can have at most floor(max_length / inner_length) repetitions
396
+ external_max_repeat = max_length // inner_length
397
+
398
+ # Merge original repetition constraints with external constraints
399
+ final_min_repeat = min_repeat
400
+ if external_min_repeat is not None:
401
+ final_min_repeat = max(min_repeat, external_min_repeat)
402
+
403
+ final_max_repeat = max_repeat
404
+ if external_max_repeat is not None:
405
+ if max_repeat == MAXREPEAT:
406
+ final_max_repeat = external_max_repeat
407
+ else:
408
+ final_max_repeat = min(max_repeat, external_max_repeat)
409
+
410
+ if final_min_repeat > final_max_repeat:
411
+ return pattern
412
+
413
+ return f"({inner})" + _build_quantifier(final_min_repeat, final_max_repeat)
359
414
 
360
415
 
361
416
  def _handle_literal_or_in_quantifier(pattern: str, min_length: int | None, max_length: int | None) -> str:
@@ -646,6 +646,10 @@ class BaseOpenAPISchema(BaseSchema):
646
646
  # Use a recent JSON Schema format checker to get most of formats checked for older drafts as well
647
647
  format_checker=jsonschema.Draft202012Validator.FORMAT_CHECKER,
648
648
  )
649
+ except jsonschema.SchemaError as exc:
650
+ raise InvalidSchema.from_jsonschema_error(
651
+ exc, path=operation.path, method=operation.method, config=self.config.output
652
+ ) from exc
649
653
  except jsonschema.ValidationError as exc:
650
654
  failures.append(
651
655
  JsonSchemaError.from_exception(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.0.18
3
+ Version: 4.0.20
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
@@ -51,7 +51,7 @@ schemathesis/core/compat.py,sha256=9BWCrFoqN2sJIaiht_anxe8kLjYMR7t0iiOkXqLRUZ8,1
51
51
  schemathesis/core/control.py,sha256=IzwIc8HIAEMtZWW0Q0iXI7T1niBpjvcLlbuwOSmy5O8,130
52
52
  schemathesis/core/curl.py,sha256=yuaCe_zHLGwUjEeloQi6W3tOA3cGdnHDNI17-5jia0o,1723
53
53
  schemathesis/core/deserialization.py,sha256=qjXUPaz_mc1OSgXzTUSkC8tuVR8wgVQtb9g3CcAF6D0,2951
54
- schemathesis/core/errors.py,sha256=KuFLy5ZOGn8KlD4ai5HK_WFlB3fJ2rSKwV1yD4fn4BU,16295
54
+ schemathesis/core/errors.py,sha256=Afs2EFyJpcy9Pr1MvnP-jeoiPiAW14MtV3YJYgio2E8,16313
55
55
  schemathesis/core/failures.py,sha256=MYyRnom-XeUEuBmq2ffdz34xhxmpSHWaQunfHtliVsY,8932
56
56
  schemathesis/core/fs.py,sha256=ItQT0_cVwjDdJX9IiI7EnU75NI2H3_DCEyyUjzg_BgI,472
57
57
  schemathesis/core/hooks.py,sha256=qhbkkRSf8URJ4LKv2wmKRINKpquUOgxQzWBHKWRWo3Q,475
@@ -124,17 +124,17 @@ schemathesis/specs/graphql/validation.py,sha256=-W1Noc1MQmTb4RX-gNXMeU2qkgso4mzV
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
126
  schemathesis/specs/openapi/_hypothesis.py,sha256=H-4pzT7dECY-AcDGhebKdTSELhGOdyA1WCbZQSMZY3E,22309
127
- schemathesis/specs/openapi/checks.py,sha256=0YiMoUy_wsnPvbOrsbnQ2iDxLloNe2-dc5-hnsst0ss,29863
127
+ schemathesis/specs/openapi/checks.py,sha256=t3ZIyzRPd_KnJzdp57Y_9CZLYC98NAqsE3dgNfuCOBA,29971
128
128
  schemathesis/specs/openapi/constants.py,sha256=JqM_FHOenqS_MuUE9sxVQ8Hnw0DNM8cnKDwCwPLhID4,783
129
- schemathesis/specs/openapi/converter.py,sha256=3Fikg9dzOG9XwFiVI0R1KbZioG7Cwc6BOQhPFYItqto,4151
129
+ schemathesis/specs/openapi/converter.py,sha256=LkpCCAxZzET4Qa_3YStSNuhGlsm5G6TVwpxYu6lPO4g,4169
130
130
  schemathesis/specs/openapi/definitions.py,sha256=8htclglV3fW6JPBqs59lgM4LnA25Mm9IptXBPb_qUT0,93949
131
131
  schemathesis/specs/openapi/examples.py,sha256=V1fbsbMto_So7lTWnyGa7f3u9On2br8yZ-cPzcC2-Bw,21542
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=ifu_QQCMUzsUHQAkvsOvLuokns6CzesssmQ3Nd3zxII,14594
135
- schemathesis/specs/openapi/patterns.py,sha256=XhxZzIaCli3E67YZ9V6wQFvBkqDOEVwRrcUSEypjtHU,15890
135
+ schemathesis/specs/openapi/patterns.py,sha256=GqPZEXMRdWENQxanWjBOalIZ2MQUjuxk21kmdiI703E,18027
136
136
  schemathesis/specs/openapi/references.py,sha256=40YcDExPLR2B8EOwt-Csw-5MYFi2xj_DXf91J0Pc9d4,8855
137
- schemathesis/specs/openapi/schemas.py,sha256=FXD6yLindLNtjiW5D_GllWxfMAigSKjpjl8_GbqJXxE,52557
137
+ schemathesis/specs/openapi/schemas.py,sha256=ZhFYxYzm0u9VpPMD5f_tt15l29OMa4-lrofOWf4Q6yM,52790
138
138
  schemathesis/specs/openapi/security.py,sha256=6UWYMhL-dPtkTineqqBFNKca1i4EuoTduw-EOLeE0aQ,7149
139
139
  schemathesis/specs/openapi/serialization.py,sha256=VdDLmeHqxlWM4cxQQcCkvrU6XurivolwEEaT13ohelA,11972
140
140
  schemathesis/specs/openapi/utils.py,sha256=ER4vJkdFVDIE7aKyxyYatuuHVRNutytezgE52pqZNE8,900
@@ -157,8 +157,8 @@ schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEz
157
157
  schemathesis/transport/requests.py,sha256=46aplzhSmBupegPNMawma-iJWCegWkEd6mzdWLTpgM4,10742
158
158
  schemathesis/transport/serialization.py,sha256=igUXKZ_VJ9gV7P0TUc5PDQBJXl_s0kK9T3ljGWWvo6E,10339
159
159
  schemathesis/transport/wsgi.py,sha256=KoAfvu6RJtzyj24VGB8e-Iaa9smpgXJ3VsM8EgAz2tc,6152
160
- schemathesis-4.0.18.dist-info/METADATA,sha256=KCyTL3AhvoLowCLdICpuDsX3kXYyf7QQ1B7Fh_wb4pY,8472
161
- schemathesis-4.0.18.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
- schemathesis-4.0.18.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
- schemathesis-4.0.18.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
- schemathesis-4.0.18.dist-info/RECORD,,
160
+ schemathesis-4.0.20.dist-info/METADATA,sha256=diXsxXNsEftDBd6avKFKX7nsuQTNRm3oKazIVDFJlhE,8472
161
+ schemathesis-4.0.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
+ schemathesis-4.0.20.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
+ schemathesis-4.0.20.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
+ schemathesis-4.0.20.dist-info/RECORD,,