Skip to content

Commit 469c558

Browse files
authored
Merge pull request #43 from p1c2u/feature/schema-additional-properties-support
Schema additional properties support
2 parents 19bfff8 + 78f55ee commit 469c558

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

openapi_core/schema/schemas/factories.py

+6
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def create(self, schema_spec):
2828
deprecated = schema_deref.get('deprecated', False)
2929
all_of_spec = schema_deref.get('allOf', None)
3030
one_of_spec = schema_deref.get('oneOf', None)
31+
additional_properties_spec = schema_deref.get('additionalProperties')
3132

3233
properties = None
3334
if properties_spec:
@@ -45,11 +46,16 @@ def create(self, schema_spec):
4546
if items_spec:
4647
items = self._create_items(items_spec)
4748

49+
additional_properties = None
50+
if additional_properties_spec:
51+
additional_properties = self.create(additional_properties_spec)
52+
4853
return Schema(
4954
schema_type=schema_type, model=model, properties=properties,
5055
items=items, schema_format=schema_format, required=required,
5156
default=default, nullable=nullable, enum=enum,
5257
deprecated=deprecated, all_of=all_of, one_of=one_of,
58+
additional_properties=additional_properties,
5359
)
5460

5561
@property

openapi_core/schema/schemas/models.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ class Schema(object):
2828
def __init__(
2929
self, schema_type=None, model=None, properties=None, items=None,
3030
schema_format=None, required=None, default=None, nullable=False,
31-
enum=None, deprecated=False, all_of=None, one_of=None):
31+
enum=None, deprecated=False, all_of=None, one_of=None,
32+
additional_properties=None):
3233
self.type = schema_type and SchemaType(schema_type)
3334
self.model = model
3435
self.properties = properties and dict(properties) or {}
@@ -41,6 +42,7 @@ def __init__(
4142
self.deprecated = deprecated
4243
self.all_of = all_of and list(all_of) or []
4344
self.one_of = one_of and list(one_of) or []
45+
self.additional_properties = additional_properties
4446

4547
self._all_required_properties_cache = None
4648
self._all_optional_properties_cache = None
@@ -183,11 +185,16 @@ def _unmarshal_properties(self, value, one_of_schema=None):
183185

184186
value_props_names = value.keys()
185187
extra_props = set(value_props_names) - set(all_props_names)
186-
if extra_props:
188+
if extra_props and self.additional_properties is None:
187189
raise UndefinedSchemaProperty(
188190
"Undefined properties in schema: {0}".format(extra_props))
189191

190192
properties = {}
193+
for prop_name in extra_props:
194+
prop_value = value[prop_name]
195+
properties[prop_name] = self.additional_properties.unmarshal(
196+
prop_value)
197+
191198
for prop_name, prop in iteritems(all_props):
192199
try:
193200
prop_value = value[prop_name]

tests/integration/data/v3.0/petstore.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ components:
284284
properties:
285285
rootCause:
286286
type: string
287+
additionalProperties:
288+
type: string
287289
responses:
288290
ErrorResponse:
289291
description: unexpected error

tests/integration/test_petstore.py

+35
Original file line numberDiff line numberDiff line change
@@ -757,3 +757,38 @@ def test_post_tags_wrong_property_type(self, spec):
757757

758758
with pytest.raises(InvalidMediaTypeValue):
759759
request.get_body(spec)
760+
761+
def test_post_tags_additional_properties(
762+
self, spec, response_validator):
763+
host_url = 'http://petstore.swagger.io/v1'
764+
path_pattern = '/v1/tags'
765+
pet_name = 'Dog'
766+
data_json = {
767+
'name': pet_name,
768+
}
769+
data = json.dumps(data_json)
770+
771+
request = MockRequest(
772+
host_url, 'POST', '/tags',
773+
path_pattern=path_pattern, data=data,
774+
)
775+
776+
parameters = request.get_parameters(spec)
777+
body = request.get_body(spec)
778+
779+
assert parameters == {}
780+
assert body == data_json
781+
782+
data_json = {
783+
'code': 400,
784+
'message': 'Bad request',
785+
'rootCause': 'Tag already exist',
786+
'additionalinfo': 'Tag Dog already exist',
787+
}
788+
data = json.dumps(data_json)
789+
response = MockResponse(data, status_code=404)
790+
791+
response_result = response_validator.validate(request, response)
792+
793+
assert response_result.errors == []
794+
assert response_result.data == data_json

0 commit comments

Comments
 (0)