Schema-First 0.16.0__tar.gz → 0.16.2__tar.gz

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.
Files changed (48) hide show
  1. {schema_first-0.16.0 → schema_first-0.16.2}/PKG-INFO +3 -3
  2. {schema_first-0.16.0 → schema_first-0.16.2}/pyproject.toml +3 -3
  3. {schema_first-0.16.0 → schema_first-0.16.2}/src/Schema_First.egg-info/PKG-INFO +3 -3
  4. {schema_first-0.16.0 → schema_first-0.16.2}/src/Schema_First.egg-info/requires.txt +2 -2
  5. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/query/validator.py +16 -3
  6. {schema_first-0.16.0 → schema_first-0.16.2}/tests/test_query_validators.py +60 -3
  7. {schema_first-0.16.0 → schema_first-0.16.2}/README.md +0 -0
  8. {schema_first-0.16.0 → schema_first-0.16.2}/setup.cfg +0 -0
  9. {schema_first-0.16.0 → schema_first-0.16.2}/src/Schema_First.egg-info/SOURCES.txt +0 -0
  10. {schema_first-0.16.0 → schema_first-0.16.2}/src/Schema_First.egg-info/dependency_links.txt +0 -0
  11. {schema_first-0.16.0 → schema_first-0.16.2}/src/Schema_First.egg-info/top_level.txt +0 -0
  12. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/__init__.py +0 -0
  13. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/exceptions.py +0 -0
  14. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/loaders/__init__.py +0 -0
  15. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/loaders/exc.py +0 -0
  16. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/loaders/yaml_loader.py +0 -0
  17. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/__init__.py +0 -0
  18. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/exc.py +0 -0
  19. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/__init__.py +0 -0
  20. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/base.py +0 -0
  21. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/constants.py +0 -0
  22. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/fields.py +0 -0
  23. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/components_object_schema.py +0 -0
  24. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/contact_object_schema.py +0 -0
  25. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/example_object_schema.py +0 -0
  26. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/external_docs_object_schema.py +0 -0
  27. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/header_object_schema.py +0 -0
  28. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/info_object_schema.py +0 -0
  29. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/license_object_schema.py +0 -0
  30. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/media_type_object_schema.py +0 -0
  31. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/openapi_object_schema.py +0 -0
  32. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/operation_object_schema.py +0 -0
  33. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/parameter_object_schema.py +0 -0
  34. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/path_item_object_schema.py +0 -0
  35. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/reference_object_schema.py +0 -0
  36. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/request_body_object_schema.py +0 -0
  37. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/responses_object_schema.py +0 -0
  38. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/schema_object_schema.py +0 -0
  39. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/security_scheme_object_schema.py +0 -0
  40. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/server_object_schema.py +0 -0
  41. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/server_variable_object_schema.py +0 -0
  42. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/v3_2/tag_object_schema.py +0 -0
  43. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/openapi/schemas/validators.py +0 -0
  44. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/query/exceptions.py +0 -0
  45. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/specification/__init__.py +0 -0
  46. {schema_first-0.16.0 → schema_first-0.16.2}/src/schema_first/specification/spilli_api.py +0 -0
  47. {schema_first-0.16.0 → schema_first-0.16.2}/tests/test_specification.py +0 -0
  48. {schema_first-0.16.0 → schema_first-0.16.2}/tests/test_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Schema-First
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: OpenAPI specification validator and converter to Marshmallow schemas.
5
5
  Author-email: Konstantin Fadeev <jredkiy@yandex.ru>
6
6
  License-Expression: LGPL-2.1-only
@@ -16,11 +16,11 @@ Provides-Extra: dev
16
16
  Requires-Dist: bandit>=1.9.3; extra == "dev"
17
17
  Requires-Dist: build>=1.4.0; extra == "dev"
18
18
  Requires-Dist: openapi-spec-validator>=0.7.1; extra == "dev"
19
- Requires-Dist: pre-commit>=4.5.1; extra == "dev"
19
+ Requires-Dist: pre-commit>=4.6.2; extra == "dev"
20
20
  Requires-Dist: pytest>=9.1.1; extra == "dev"
21
21
  Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
22
22
  Requires-Dist: python-dotenv>=1.2.1; extra == "dev"
23
- Requires-Dist: tox==4.18.0; extra == "dev"
23
+ Requires-Dist: tox==4.59.0; extra == "dev"
24
24
  Requires-Dist: twine==6.2.0; extra == "dev"
25
25
 
26
26
  # Schema-First
@@ -20,18 +20,18 @@ license-files = ["LICENSE.txt"]
20
20
  name = "Schema-First"
21
21
  readme = "README.md"
22
22
  requires-python = ">=3.12"
23
- version = "0.16.0"
23
+ version = "0.16.2"
24
24
 
25
25
  [project.optional-dependencies]
26
26
  dev = [
27
27
  "bandit>=1.9.3",
28
28
  "build>=1.4.0",
29
29
  'openapi-spec-validator>=0.7.1',
30
- "pre-commit>=4.5.1",
30
+ "pre-commit>=4.6.2",
31
31
  "pytest>=9.1.1",
32
32
  "pytest-cov>=7.0.0",
33
33
  "python-dotenv>=1.2.1",
34
- "tox==4.18.0",
34
+ "tox==4.59.0",
35
35
  "twine==6.2.0"
36
36
  ]
37
37
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Schema-First
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: OpenAPI specification validator and converter to Marshmallow schemas.
5
5
  Author-email: Konstantin Fadeev <jredkiy@yandex.ru>
6
6
  License-Expression: LGPL-2.1-only
@@ -16,11 +16,11 @@ Provides-Extra: dev
16
16
  Requires-Dist: bandit>=1.9.3; extra == "dev"
17
17
  Requires-Dist: build>=1.4.0; extra == "dev"
18
18
  Requires-Dist: openapi-spec-validator>=0.7.1; extra == "dev"
19
- Requires-Dist: pre-commit>=4.5.1; extra == "dev"
19
+ Requires-Dist: pre-commit>=4.6.2; extra == "dev"
20
20
  Requires-Dist: pytest>=9.1.1; extra == "dev"
21
21
  Requires-Dist: pytest-cov>=7.0.0; extra == "dev"
22
22
  Requires-Dist: python-dotenv>=1.2.1; extra == "dev"
23
- Requires-Dist: tox==4.18.0; extra == "dev"
23
+ Requires-Dist: tox==4.59.0; extra == "dev"
24
24
  Requires-Dist: twine==6.2.0; extra == "dev"
25
25
 
26
26
  # Schema-First
@@ -5,9 +5,9 @@ PyYAML>=6.0.3
5
5
  bandit>=1.9.3
6
6
  build>=1.4.0
7
7
  openapi-spec-validator>=0.7.1
8
- pre-commit>=4.5.1
8
+ pre-commit>=4.6.2
9
9
  pytest>=9.1.1
10
10
  pytest-cov>=7.0.0
11
11
  python-dotenv>=1.2.1
12
- tox==4.18.0
12
+ tox==4.59.0
13
13
  twine==6.2.0
@@ -1,6 +1,7 @@
1
1
  import typing as t
2
2
 
3
3
  from marshmallow import fields
4
+ from marshmallow import INCLUDE
4
5
  from marshmallow import Schema
5
6
  from marshmallow import ValidationError
6
7
 
@@ -49,10 +50,18 @@ class HTTPQueryValidator:
49
50
  if not params_schema:
50
51
  continue
51
52
 
52
- request_fields[name_params] = fields.Nested(params_schema)
53
+ if name_params == 'headers':
54
+ request_fields[name_params] = fields.Nested(params_schema, unknown=INCLUDE)
55
+ else:
56
+ request_fields[name_params] = fields.Nested(params_schema)
57
+
58
+ if 'headers' not in parameters:
59
+ request_fields['headers'] = fields.Raw()
60
+
61
+ if not parameters:
62
+ request_fields['headers'] = fields.Raw()
53
63
 
54
64
  request_schema = Schema.from_dict(request_fields)
55
- request_schema.Meta.unknown = 'raise'
56
65
 
57
66
  return request_schema
58
67
 
@@ -76,6 +85,10 @@ class HTTPQueryValidator:
76
85
  body_schema = content_type.get('schema')
77
86
  if body_schema:
78
87
  response_fields['body'] = fields.Nested(body_schema)
88
+ else:
89
+ # If body must be empty.
90
+ if data.get('content_type'):
91
+ response_fields['content_type'] = fields.String()
79
92
 
80
93
  response_schema = Schema.from_dict(response_fields)
81
94
  response_schema.Meta.unknown = 'raise'
@@ -119,7 +132,7 @@ class HTTPQueryValidator:
119
132
  endpoint: str,
120
133
  method: t.Literal['post', 'get', 'update', 'patch', 'delete'],
121
134
  status_code: str,
122
- content_type: t.Literal['application/json'] or ... = ...,
135
+ content_type: str or ... = ...,
123
136
  body: dict[str, t.Any] or ... = ...,
124
137
  ):
125
138
  all_kwargs = {
@@ -4,6 +4,7 @@ from schema_first.query.exceptions import EndpointValidation
4
4
  from schema_first.query.exceptions import QueryValidatorException
5
5
  from schema_first.query.exceptions import ResponseValidation
6
6
  from schema_first.query.validator import HTTPQueryValidator
7
+ from schema_first.query.validator import RequestValidation
7
8
 
8
9
 
9
10
  def test_query_validators__request(fx_openapi_3_2_0, fx_open_spec):
@@ -67,12 +68,10 @@ def test_query_validators__request__bad_endpoint(fx_openapi_3_2_0, fx_open_spec)
67
68
  @pytest.mark.parametrize(
68
69
  ('spec', 'data'),
69
70
  [
70
- ('no_params.yaml', {'headers': {'field': 'value'}}),
71
71
  ('only_headers.yaml', {'cookies': {'field': 'value'}}),
72
72
  ('only_headers.yaml', {'paths': {'field': 'value'}}),
73
73
  ('only_headers.yaml', {'queries': {'field': 'value'}}),
74
74
  ('only_headers.yaml', {'content_type': 'application/json', 'body': {'field': 'value'}}),
75
- ('only_query.yaml', {'headers': {'field': 'value'}}),
76
75
  ('only_headers.yaml', {'body': {'field': 'value'}}),
77
76
  ],
78
77
  )
@@ -91,6 +90,59 @@ def test_query_validators__request_errors(fx_openapi_3_2_0, fx_open_spec, spec,
91
90
  query_validator.request_handler(**request)
92
91
 
93
92
 
93
+ def test_query_validators__request__headers(fx_openapi_3_2_0, fx_open_spec):
94
+ file_path = fx_openapi_3_2_0('query_validator/only_headers.yaml')
95
+ spec = fx_open_spec(file_path)
96
+ query_validator = HTTPQueryValidator(spec)
97
+
98
+ request = {
99
+ 'endpoint': '/endpoint',
100
+ 'method': 'post',
101
+ 'headers': {'header_field': 'value', 'header_field_1': 'value_1'},
102
+ }
103
+
104
+ serialized_request = query_validator.request_handler(**request)
105
+
106
+ assert serialized_request == request
107
+
108
+
109
+ def test_query_validators__request__headers__errors(fx_openapi_3_2_0, fx_open_spec):
110
+ file_path = fx_openapi_3_2_0('query_validator/only_headers.yaml')
111
+ spec = fx_open_spec(file_path)
112
+ query_validator = HTTPQueryValidator(spec)
113
+
114
+ request = {
115
+ 'endpoint': '/endpoint',
116
+ 'method': 'post',
117
+ 'headers': {'header_field': 1, 'header_field_2': 'value_2'},
118
+ }
119
+
120
+ with pytest.raises(RequestValidation) as exc:
121
+ query_validator.request_handler(**request)
122
+
123
+ assert exc.value.args[0] == (
124
+ "Request <{'endpoint': '/endpoint', 'method': 'post', 'headers': "
125
+ "{'header_field': 1, 'header_field_2': 'value_2'}}> validation error "
126
+ "<({'headers': {'header_field': ['Not a valid string.']}},)>."
127
+ )
128
+
129
+
130
+ def test_query_validators__request__headers_not_in_spec(fx_openapi_3_2_0, fx_open_spec):
131
+ file_path = fx_openapi_3_2_0('query_validator/only_query.yaml')
132
+ spec = fx_open_spec(file_path)
133
+ query_validator = HTTPQueryValidator(spec)
134
+
135
+ request = {
136
+ 'endpoint': '/endpoint',
137
+ 'method': 'post',
138
+ 'headers': {'header_field_1': 'value_1', 'header_field_2': 'value_2'},
139
+ }
140
+
141
+ serialized_request = query_validator.request_handler(**request)
142
+
143
+ assert serialized_request == request
144
+
145
+
94
146
  def test_query_validators__response(fx_openapi_3_2_0, fx_open_spec):
95
147
  file_path = fx_openapi_3_2_0('query_validator/openapi.yaml')
96
148
  spec = fx_open_spec(file_path)
@@ -114,7 +166,12 @@ def test_query_validators__response__empty_body_in_spec(fx_openapi_3_2_0, fx_ope
114
166
  spec = fx_open_spec(file_path)
115
167
  query_validator = HTTPQueryValidator(spec)
116
168
 
117
- request = {'endpoint': '/endpoint', 'method': 'get', 'status_code': '204'}
169
+ request = {
170
+ 'endpoint': '/endpoint',
171
+ 'method': 'get',
172
+ 'content_type': 'application/json',
173
+ 'status_code': '204',
174
+ }
118
175
 
119
176
  serialized_request = query_validator.response_handler(**request)
120
177
 
File without changes
File without changes