Schema-First 0.16.2__tar.gz → 0.16.4__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 (49) hide show
  1. {schema_first-0.16.2 → schema_first-0.16.4}/PKG-INFO +1 -1
  2. {schema_first-0.16.2 → schema_first-0.16.4}/pyproject.toml +3 -3
  3. {schema_first-0.16.2 → schema_first-0.16.4}/src/Schema_First.egg-info/PKG-INFO +1 -1
  4. schema_first-0.16.4/src/schema_first/openapi/schemas/base.py +15 -0
  5. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/info_object_schema.py +5 -5
  6. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/query/validator.py +6 -0
  7. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/specification/__init__.py +19 -8
  8. {schema_first-0.16.2 → schema_first-0.16.4}/tests/test_query_validators.py +18 -0
  9. {schema_first-0.16.2 → schema_first-0.16.4}/tests/test_specification.py +1 -1
  10. schema_first-0.16.2/src/schema_first/openapi/schemas/base.py +0 -28
  11. {schema_first-0.16.2 → schema_first-0.16.4}/README.md +0 -0
  12. {schema_first-0.16.2 → schema_first-0.16.4}/setup.cfg +0 -0
  13. {schema_first-0.16.2 → schema_first-0.16.4}/src/Schema_First.egg-info/SOURCES.txt +0 -0
  14. {schema_first-0.16.2 → schema_first-0.16.4}/src/Schema_First.egg-info/dependency_links.txt +0 -0
  15. {schema_first-0.16.2 → schema_first-0.16.4}/src/Schema_First.egg-info/requires.txt +0 -0
  16. {schema_first-0.16.2 → schema_first-0.16.4}/src/Schema_First.egg-info/top_level.txt +0 -0
  17. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/__init__.py +0 -0
  18. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/exceptions.py +0 -0
  19. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/loaders/__init__.py +0 -0
  20. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/loaders/exc.py +0 -0
  21. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/loaders/yaml_loader.py +0 -0
  22. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/__init__.py +0 -0
  23. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/exc.py +0 -0
  24. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/__init__.py +0 -0
  25. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/constants.py +0 -0
  26. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/fields.py +0 -0
  27. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/components_object_schema.py +0 -0
  28. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/contact_object_schema.py +0 -0
  29. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/example_object_schema.py +0 -0
  30. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/external_docs_object_schema.py +0 -0
  31. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/header_object_schema.py +0 -0
  32. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/license_object_schema.py +0 -0
  33. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/media_type_object_schema.py +0 -0
  34. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/openapi_object_schema.py +0 -0
  35. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/operation_object_schema.py +0 -0
  36. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/parameter_object_schema.py +0 -0
  37. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/path_item_object_schema.py +0 -0
  38. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/reference_object_schema.py +0 -0
  39. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/request_body_object_schema.py +0 -0
  40. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/responses_object_schema.py +0 -0
  41. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/schema_object_schema.py +0 -0
  42. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/security_scheme_object_schema.py +0 -0
  43. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/server_object_schema.py +0 -0
  44. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/server_variable_object_schema.py +0 -0
  45. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/v3_2/tag_object_schema.py +0 -0
  46. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/openapi/schemas/validators.py +0 -0
  47. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/query/exceptions.py +0 -0
  48. {schema_first-0.16.2 → schema_first-0.16.4}/src/schema_first/specification/spilli_api.py +0 -0
  49. {schema_first-0.16.2 → schema_first-0.16.4}/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.2
3
+ Version: 0.16.4
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
@@ -20,7 +20,7 @@ license-files = ["LICENSE.txt"]
20
20
  name = "Schema-First"
21
21
  readme = "README.md"
22
22
  requires-python = ">=3.12"
23
- version = "0.16.2"
23
+ version = "0.16.4"
24
24
 
25
25
  [project.optional-dependencies]
26
26
  dev = [
@@ -40,7 +40,7 @@ changelog = "https://github.com/flask-pro/schema-first/blob/master/CHANGES.md"
40
40
  repository = "https://github.com/flask-pro/schema-first"
41
41
 
42
42
  [tool.bandit]
43
- exclude_dirs = ["tests"]
43
+ exclude_dirs = ["tests", "venv"]
44
44
 
45
45
  [tool.black]
46
46
  extend-exclude = '''
@@ -51,7 +51,7 @@ extend-exclude = '''
51
51
  include = '\.pyi?$'
52
52
  line-length = 100
53
53
  skip-string-normalization = true
54
- target-version = ['py313']
54
+ target-version = ['py312']
55
55
 
56
56
  [tool.isort]
57
57
  include_trailing_comma = true
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Schema-First
3
- Version: 0.16.2
3
+ Version: 0.16.4
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
@@ -0,0 +1,15 @@
1
+ from marshmallow import RAISE
2
+ from marshmallow import Schema
3
+
4
+ from schema_first.openapi.schemas.fields import DESCRIPTION_FIELD
5
+ from schema_first.openapi.schemas.fields import SUMMARY_FIELD
6
+
7
+
8
+ class BaseSchema(Schema):
9
+ class Meta:
10
+ unknown = RAISE
11
+
12
+
13
+ class DocStringFields(Schema):
14
+ summary = SUMMARY_FIELD
15
+ description = DESCRIPTION_FIELD
@@ -1,11 +1,11 @@
1
1
  from marshmallow import fields
2
2
  from marshmallow import validate
3
3
 
4
- from ..base import BaseSchema
5
- from ..base import DocStringFields
6
- from ..constants import RE_VERSION
7
- from .contact_object_schema import ContactObjectSchema
8
- from .license_object_schema import LicenseObjectSchema
4
+ from schema_first.openapi.schemas.base import BaseSchema
5
+ from schema_first.openapi.schemas.base import DocStringFields
6
+ from schema_first.openapi.schemas.constants import RE_VERSION
7
+ from schema_first.openapi.schemas.v3_2.contact_object_schema import ContactObjectSchema
8
+ from schema_first.openapi.schemas.v3_2.license_object_schema import LicenseObjectSchema
9
9
 
10
10
 
11
11
  class InfoObjectSchema(DocStringFields, BaseSchema):
@@ -85,6 +85,12 @@ class HTTPQueryValidator:
85
85
  body_schema = content_type.get('schema')
86
86
  if body_schema:
87
87
  response_fields['body'] = fields.Nested(body_schema)
88
+ elif 'application/octet-stream' in content:
89
+ response_fields['content_type'] = fields.String()
90
+ response_fields['body'] = fields.Raw()
91
+ else:
92
+ raise NotImplementedError
93
+
88
94
  else:
89
95
  # If body must be empty.
90
96
  if data.get('content_type'):
@@ -8,6 +8,7 @@ from marshmallow import RAISE
8
8
  from marshmallow import Schema
9
9
  from marshmallow import validate
10
10
  from marshmallow.fields import Field
11
+ from marshmallow.fields import Nested
11
12
 
12
13
  from schema_first.openapi import OpenAPI
13
14
  from schema_first.specification.spilli_api import ConverterOpenAPIToSpilliAPI
@@ -103,8 +104,8 @@ class Specification:
103
104
  initialized_schema.required = field_schema.get('required', False)
104
105
  return initialized_schema
105
106
 
106
- def _convert_field_any_type(self, field_schema: dict):
107
- field_schema_converters = {
107
+ def _convert_field_any_type(self, field_schema: dict, as_schema: bool = False):
108
+ _converters = {
108
109
  'string': self._convert_string_field,
109
110
  'boolean': self._convert_boolean_field,
110
111
  'number': self._convert_number_field,
@@ -112,8 +113,14 @@ class Specification:
112
113
  'object': self._convert_object_field,
113
114
  'array': self._convert_array_field,
114
115
  }
116
+
117
+ field_type = field_schema['type']
118
+
115
119
  try:
116
- converted_field_schema = field_schema_converters[field_schema['type']](field_schema)
120
+ if field_type in ['object']:
121
+ converted_field_schema = _converters[field_type](field_schema, as_schema=as_schema)
122
+ else:
123
+ converted_field_schema = _converters[field_type](field_schema)
117
124
  except KeyError:
118
125
  raise NotImplementedError(
119
126
  f'Schema <{field_schema}> for type <{field_schema["type"]}> not be converted.'
@@ -121,7 +128,9 @@ class Specification:
121
128
 
122
129
  return converted_field_schema
123
130
 
124
- def _convert_object_field(self, open_api_schema: dict) -> type[Schema]:
131
+ def _convert_object_field(
132
+ self, open_api_schema: dict, many: bool = False, as_schema: bool = False
133
+ ) -> type[Schema] | Nested:
125
134
  marshmallow_schema = {}
126
135
  required_fields = open_api_schema.get('required', [])
127
136
  for field_name, field_schema in open_api_schema['properties'].items():
@@ -136,13 +145,15 @@ class Specification:
136
145
  else:
137
146
  marshmallow_schema['unknown'] = INCLUDE
138
147
 
139
- return Schema.from_dict(marshmallow_schema)
148
+ if as_schema:
149
+ return Schema.from_dict(marshmallow_schema)
150
+
151
+ return fields.Nested(Schema.from_dict(marshmallow_schema), many=many)
140
152
 
141
153
  def _convert_array_field(self, open_api_schema: dict) -> Field:
142
154
  array_item_schema = open_api_schema['items']
143
155
  if array_item_schema['type'] == 'object':
144
- nested_field = self._convert_object_field(array_item_schema)
145
- array_field = fields.Nested(nested_field, many=True)
156
+ array_field = self._convert_object_field(array_item_schema, many=True)
146
157
  else:
147
158
  nested_field = FIELDS_VIA_TYPES[array_item_schema['type']]()
148
159
  array_field = fields.List(nested_field)
@@ -154,7 +165,7 @@ class Specification:
154
165
  # Checking for object type is needed to skip already resolved schemes.
155
166
  # This is necessary because of passing variables by reference in Python.
156
167
  if k == 'schema' and isinstance(v, dict):
157
- obj[k] = self._convert_field_any_type(v)
168
+ obj[k] = self._convert_field_any_type(v, as_schema=True)
158
169
  else:
159
170
  self._reassembly_of_schemas(v)
160
171
 
@@ -178,6 +178,24 @@ def test_query_validators__response__empty_body_in_spec(fx_openapi_3_2_0, fx_ope
178
178
  assert serialized_request == request
179
179
 
180
180
 
181
+ def test_query_validators__binary_response(fx_openapi_3_2_0, fx_open_spec):
182
+ file_path = fx_openapi_3_2_0('query_validator/binary_response.yaml')
183
+ spec = fx_open_spec(file_path)
184
+ query_validator = HTTPQueryValidator(spec)
185
+
186
+ request = {
187
+ 'endpoint': '/endpoint',
188
+ 'method': 'get',
189
+ 'content_type': 'multipart/form-data',
190
+ 'status_code': '200',
191
+ 'body': b'content',
192
+ }
193
+
194
+ serialized_request = query_validator.response_handler(**request)
195
+
196
+ assert serialized_request == request
197
+
198
+
181
199
  def test_query_validators__response__empty_body_in_spec_error(fx_openapi_3_2_0, fx_open_spec):
182
200
  file_path = fx_openapi_3_2_0('query_validator/empty_body.yaml')
183
201
  spec = fx_open_spec(file_path)
@@ -62,7 +62,7 @@ def test_specification__multifile_required(fx_spec_as_file, fx_spec_required):
62
62
 
63
63
  @pytest.mark.xfail(reason='Schema specification not fully realisation.')
64
64
  def test_specification__multifile():
65
- file_path = Path(tests_dir_abspath, '_contrib', 'specs', 'v3.2', 'multifile', 'openapi.yaml')
65
+ file_path = Path(tests_dir_abspath, 'specs', 'openapi', 'v3.2', 'multifile', 'openapi.yaml')
66
66
  spec_as_dict, base_uri = read_from_filename(file_path)
67
67
  osv_validate(spec_as_dict, base_uri=base_uri)
68
68
 
@@ -1,28 +0,0 @@
1
- from marshmallow import RAISE
2
- from marshmallow import Schema
3
- from marshmallow import validates_schema
4
- from marshmallow import ValidationError
5
-
6
- from schema_first.openapi.schemas.fields import DESCRIPTION_FIELD
7
- from schema_first.openapi.schemas.fields import SUMMARY_FIELD
8
-
9
-
10
- class BaseSchema(Schema):
11
- class Meta:
12
- unknown = RAISE
13
-
14
- @validates_schema
15
- def validate_ref(self, data, **kwargs) -> None:
16
- if 'ref' in data:
17
- ALLOWED_FIELDS = {'ref', 'description', 'summary'}
18
- ALL_FIELDS = set(data)
19
- if ALL_FIELDS.difference(ALLOWED_FIELDS):
20
- raise ValidationError(
21
- f"If there is a <'ref'> field, then only <{ALLOWED_FIELDS}>,"
22
- f" but set <{ALL_FIELDS}>"
23
- )
24
-
25
-
26
- class DocStringFields(Schema):
27
- summary = SUMMARY_FIELD
28
- description = DESCRIPTION_FIELD
File without changes
File without changes