schemathesis 4.0.10__py3-none-any.whl → 4.0.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.
@@ -207,15 +207,24 @@ class Case:
207
207
  transport_ = transport.get(kwargs["app"])
208
208
  else:
209
209
  transport_ = self.operation.schema.transport
210
- response = transport_.send(
211
- self,
212
- session=session,
213
- base_url=base_url,
214
- headers=headers,
215
- params=params,
216
- cookies=cookies,
217
- **kwargs,
218
- )
210
+ try:
211
+ response = transport_.send(
212
+ self,
213
+ session=session,
214
+ base_url=base_url,
215
+ headers=headers,
216
+ params=params,
217
+ cookies=cookies,
218
+ **kwargs,
219
+ )
220
+ except Exception as exc:
221
+ # May happen in ASGI / WSGI apps
222
+ if not hasattr(exc, "__notes__"):
223
+ exc.__notes__ = [] # type: ignore[attr-defined]
224
+ verify = kwargs.get("verify", True)
225
+ curl = self.as_curl_command(headers=headers, verify=verify)
226
+ exc.__notes__.append(f"\nReproduce with: \n\n {curl}") # type: ignore[attr-defined]
227
+ raise
219
228
  dispatch("after_call", hook_context, self, response)
220
229
  return response
221
230
 
@@ -41,6 +41,7 @@ from schemathesis.generation.case import Case
41
41
  from schemathesis.generation.meta import CaseMetadata
42
42
  from schemathesis.openapi.checks import JsonSchemaError, MissingContentType
43
43
  from schemathesis.specs.openapi.stateful import links
44
+ from schemathesis.specs.openapi.utils import expand_status_code
44
45
 
45
46
  from ...generation import GenerationMode
46
47
  from ...hooks import HookContext, HookDispatcher
@@ -556,12 +557,10 @@ class BaseOpenAPISchema(BaseSchema):
556
557
  except KeyError as exc:
557
558
  path = operation.path
558
559
  self._raise_invalid_schema(exc, path, operation.method)
559
- status_code = str(response.status_code)
560
- if status_code in responses:
561
- return self.resolver.resolve_in_scope(responses[status_code], operation.definition.scope)
562
- if "default" in responses:
563
- return self.resolver.resolve_in_scope(responses["default"], operation.definition.scope)
564
- return None
560
+ definition = _get_response_definition_by_status(response.status_code, responses)
561
+ if definition is None:
562
+ return None
563
+ return self.resolver.resolve_in_scope(definition, operation.definition.scope)
565
564
 
566
565
  def get_headers(
567
566
  self, operation: APIOperation, response: Response
@@ -598,12 +597,8 @@ class BaseOpenAPISchema(BaseSchema):
598
597
  def validate_response(self, operation: APIOperation, response: Response) -> bool | None:
599
598
  __tracebackhide__ = True
600
599
  responses = {str(key): value for key, value in operation.definition.raw.get("responses", {}).items()}
601
- status_code = str(response.status_code)
602
- if status_code in responses:
603
- definition = responses[status_code]
604
- elif "default" in responses:
605
- definition = responses["default"]
606
- else:
600
+ definition = _get_response_definition_by_status(response.status_code, responses)
601
+ if definition is None:
607
602
  # No response defined for the received response status code
608
603
  return None
609
604
  scopes, schema = self.get_response_schema(definition, operation.definition.scope)
@@ -760,6 +755,24 @@ class BaseOpenAPISchema(BaseSchema):
760
755
  return schema
761
756
 
762
757
 
758
+ def _get_response_definition_by_status(status_code: int, responses: dict[str, Any]) -> dict[str, Any] | None:
759
+ # Cast to string, as integers are often there due to YAML deserialization
760
+ responses = {str(status): definition for status, definition in responses.items()}
761
+ if str(status_code) in responses:
762
+ return responses[str(status_code)]
763
+ # More specific should go first
764
+ keys = sorted(responses, key=lambda k: k.count("X"))
765
+ for key in keys:
766
+ if key == "default":
767
+ continue
768
+ status_codes = expand_status_code(key)
769
+ if status_code in status_codes:
770
+ return responses[key]
771
+ if "default" in responses:
772
+ return responses["default"]
773
+ return None
774
+
775
+
763
776
  def _maybe_raise_one_or_more(failures: list[Failure]) -> None:
764
777
  if not failures:
765
778
  return
@@ -113,10 +113,13 @@ def prepare_request(case: Case, headers: Mapping[str, Any] | None, *, config: Sa
113
113
  kwargs = REQUESTS_TRANSPORT.serialize_case(case, base_url=base_url, headers=headers)
114
114
  if config.enabled:
115
115
  kwargs["url"] = sanitize_url(kwargs["url"], config=config)
116
+ kwargs["headers"] = dict(kwargs["headers"])
116
117
  sanitize_value(kwargs["headers"], config=config)
117
118
  if kwargs["cookies"]:
119
+ kwargs["cookies"] = dict(kwargs["cookies"])
118
120
  sanitize_value(kwargs["cookies"], config=config)
119
121
  if kwargs["params"]:
122
+ kwargs["params"] = dict(kwargs["params"])
120
123
  sanitize_value(kwargs["params"], config=config)
121
124
 
122
125
  return requests.Request(**kwargs).prepare()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: schemathesis
3
- Version: 4.0.10
3
+ Version: 4.0.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
@@ -84,7 +84,7 @@ schemathesis/engine/phases/unit/__init__.py,sha256=BvZh39LZmXg90Cy_Tn0cQY5y7eWzY
84
84
  schemathesis/engine/phases/unit/_executor.py,sha256=9MmZoKSBVSPk0LWwN3PZ3iaO9nzpT1Z70yzdEE48YYw,16489
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=MuqnKsJBpGm2gaqDFdJi1yGSWgBhqJUwtYaX97kfXgo,11820
87
+ schemathesis/generation/case.py,sha256=zwAwFQ-Fp7SOxCXYOQyAdwAtNwVJe63PdLpvqackFQY,12296
88
88
  schemathesis/generation/coverage.py,sha256=0d52xHf1HUbilPmCeJlplnw7knSdc0lEv4Hr0HXYUTE,49949
89
89
  schemathesis/generation/meta.py,sha256=adkoMuCfzSjHJ9ZDocQn0GnVldSCkLL3eVR5A_jafwM,2552
90
90
  schemathesis/generation/metrics.py,sha256=cZU5HdeAMcLFEDnTbNE56NuNq4P0N4ew-g1NEz5-kt4,2836
@@ -134,7 +134,7 @@ schemathesis/specs/openapi/media_types.py,sha256=F5M6TKl0s6Z5X8mZpPsWDEdPBvxclKR
134
134
  schemathesis/specs/openapi/parameters.py,sha256=ifu_QQCMUzsUHQAkvsOvLuokns6CzesssmQ3Nd3zxII,14594
135
135
  schemathesis/specs/openapi/patterns.py,sha256=cBj8W4wn7VLJd4nABaIH5f502-zBDiqljxLgPWUn-50,15609
136
136
  schemathesis/specs/openapi/references.py,sha256=40YcDExPLR2B8EOwt-Csw-5MYFi2xj_DXf91J0Pc9d4,8855
137
- schemathesis/specs/openapi/schemas.py,sha256=4bL-nOFOykfOGHbkmUor9MnCqhAzW5S5oIQbL36wvVc,51972
137
+ schemathesis/specs/openapi/schemas.py,sha256=knaGUtxcy4CKeOpvTrVgPifnqKh9eSYdXRPhExFKElk,52539
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
@@ -153,12 +153,12 @@ schemathesis/specs/openapi/stateful/control.py,sha256=QaXLSbwQWtai5lxvvVtQV3BLJ8
153
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=iiB8KTAqnnuqjWzblIPiGVdkGIF7Yr1SAEz-KZzBNXw,4581
156
+ schemathesis/transport/prepare.py,sha256=erYXRaxpQokIDzaIuvt_csHcw72iHfCyNq8VNEzXd0o,4743
157
157
  schemathesis/transport/requests.py,sha256=rziZTrZCVMAqgy6ldB8iTwhkpAsnjKSgK8hj5Sq3ThE,10656
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.10.dist-info/METADATA,sha256=VMiIU9pSV3BpGkj_5Jl9RrgdusrmR9tqLsDTpZCfxnw,8472
161
- schemathesis-4.0.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
- schemathesis-4.0.10.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
- schemathesis-4.0.10.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
- schemathesis-4.0.10.dist-info/RECORD,,
160
+ schemathesis-4.0.12.dist-info/METADATA,sha256=78zt_-8O1SSPvAASeKxQkRRFrEqKcVKvvXZ7x2fP0RE,8472
161
+ schemathesis-4.0.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
162
+ schemathesis-4.0.12.dist-info/entry_points.txt,sha256=hiK3un-xfgPdwj9uj16YVDtTNpO128bmk0U82SMv8ZQ,152
163
+ schemathesis-4.0.12.dist-info/licenses/LICENSE,sha256=2Ve4J8v5jMQAWrT7r1nf3bI8Vflk3rZVQefiF2zpxwg,1121
164
+ schemathesis-4.0.12.dist-info/RECORD,,