Skip to content

Schema additional properties support #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions openapi_core/schema/schemas/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def create(self, schema_spec):
deprecated = schema_deref.get('deprecated', False)
all_of_spec = schema_deref.get('allOf', None)
one_of_spec = schema_deref.get('oneOf', None)
additional_properties_spec = schema_deref.get('additionalProperties')

properties = None
if properties_spec:
Expand All @@ -45,11 +46,16 @@ def create(self, schema_spec):
if items_spec:
items = self._create_items(items_spec)

additional_properties = None
if additional_properties_spec:
additional_properties = self.create(additional_properties_spec)

return Schema(
schema_type=schema_type, model=model, properties=properties,
items=items, schema_format=schema_format, required=required,
default=default, nullable=nullable, enum=enum,
deprecated=deprecated, all_of=all_of, one_of=one_of,
additional_properties=additional_properties,
)

@property
Expand Down
11 changes: 9 additions & 2 deletions openapi_core/schema/schemas/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class Schema(object):
def __init__(
self, schema_type=None, model=None, properties=None, items=None,
schema_format=None, required=None, default=None, nullable=False,
enum=None, deprecated=False, all_of=None, one_of=None):
enum=None, deprecated=False, all_of=None, one_of=None,
additional_properties=None):
self.type = schema_type and SchemaType(schema_type)
self.model = model
self.properties = properties and dict(properties) or {}
Expand All @@ -41,6 +42,7 @@ def __init__(
self.deprecated = deprecated
self.all_of = all_of and list(all_of) or []
self.one_of = one_of and list(one_of) or []
self.additional_properties = additional_properties

self._all_required_properties_cache = None
self._all_optional_properties_cache = None
Expand Down Expand Up @@ -183,11 +185,16 @@ def _unmarshal_properties(self, value, one_of_schema=None):

value_props_names = value.keys()
extra_props = set(value_props_names) - set(all_props_names)
if extra_props:
if extra_props and self.additional_properties is None:
raise UndefinedSchemaProperty(
"Undefined properties in schema: {0}".format(extra_props))

properties = {}
for prop_name in extra_props:
prop_value = value[prop_name]
properties[prop_name] = self.additional_properties.unmarshal(
prop_value)

for prop_name, prop in iteritems(all_props):
try:
prop_value = value[prop_name]
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/data/v3.0/petstore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ components:
properties:
rootCause:
type: string
additionalProperties:
type: string
responses:
ErrorResponse:
description: unexpected error
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/test_petstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,3 +757,38 @@ def test_post_tags_wrong_property_type(self, spec):

with pytest.raises(InvalidMediaTypeValue):
request.get_body(spec)

def test_post_tags_additional_properties(
self, spec, response_validator):
host_url = 'http://petstore.swagger.io/v1'
path_pattern = '/v1/tags'
pet_name = 'Dog'
data_json = {
'name': pet_name,
}
data = json.dumps(data_json)

request = MockRequest(
host_url, 'POST', '/tags',
path_pattern=path_pattern, data=data,
)

parameters = request.get_parameters(spec)
body = request.get_body(spec)

assert parameters == {}
assert body == data_json

data_json = {
'code': 400,
'message': 'Bad request',
'rootCause': 'Tag already exist',
'additionalinfo': 'Tag Dog already exist',
}
data = json.dumps(data_json)
response = MockResponse(data, status_code=404)

response_result = response_validator.validate(request, response)

assert response_result.errors == []
assert response_result.data == data_json