Skip to content

Commit 56be4b1

Browse files
author
amcmanigal
committed
Fixing Subschema Required Properties Validation
Currently if valid swagger syntax is used for model composition an error will be thrown due to the lack of a type property. This was corrected by making object the default type. schema_type = schema_deref.get('type', 'object') I changed the swagger definition to test for this. Now PetCreate is a composite of PetCreatePartOne and PetCreatePartTwo. However, this caused `test_post_pets_empty_body` to fail, which turned out to be a bug in the required properties. In `_unmarshal_object` the `get_all_properties` method is called to get all properties from the subschemas. However, this is not done for required properties, meaning that only top level required properties will be correctly validated. I have added a `get_all_required_properties’ to fix this. This caused `test_get_pets` to fail. In this case the bug allowed an incorrect test case to be introduced. Pet requires `id`, but it also requires name because it inherits from PetCreate. I have fixed this test case by adding the missing required property. After these changes `test_get_pet_not_found` failed due to a string formatting error (double quotes vs single quotes). I fixed this by switching to dictionary comparisons.
1 parent 8d92c25 commit 56be4b1

File tree

5 files changed

+27
-4
lines changed

5 files changed

+27
-4
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,6 @@ ENV/
9999

100100
# mypy
101101
.mypy_cache/
102+
103+
# Jetbrains project files
104+
.idea/

openapi_core/schemas.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ def get_all_properties(self):
6363

6464
return properties
6565

66+
def get_all_required_properties(self):
67+
required = self.required.copy()
68+
69+
for subschema in self.all_of:
70+
subschema_req = subschema.get_all_required_properties()
71+
required += subschema_req
72+
73+
return required
74+
6675
def get_cast_mapping(self):
6776
mapping = DEFAULT_CAST_CALLABLE_GETTER.copy()
6877
mapping.update({
@@ -121,6 +130,7 @@ def _unmarshal_object(self, value):
121130
value = loads(value)
122131

123132
all_properties = self.get_all_properties()
133+
all_required_properties = self.get_all_required_properties()
124134
all_properties_keys = all_properties.keys()
125135
value_keys = value.keys()
126136

@@ -135,7 +145,7 @@ def _unmarshal_object(self, value):
135145
try:
136146
prop_value = value[prop_name]
137147
except KeyError:
138-
if prop_name in self.required:
148+
if prop_name in all_required_properties:
139149
raise MissingProperty(
140150
"Missing schema property {0}".format(prop_name))
141151
if not prop.nullable and not prop.default:
@@ -167,7 +177,7 @@ def __init__(self, dereferencer):
167177
def create(self, schema_spec):
168178
schema_deref = self.dereferencer.dereference(schema_spec)
169179

170-
schema_type = schema_deref.get('type')
180+
schema_type = schema_deref.get('type', 'object')
171181
schema_format = schema_deref.get('format')
172182
model = schema_deref.get('x-model', None)
173183
required = schema_deref.get('required', False)

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,13 @@ components:
144144
type: integer
145145
format: int64
146146
PetCreate:
147-
type: object
148147
x-model: PetCreate
148+
allOf:
149+
- $ref: "#/components/schemas/PetCreatePartOne"
150+
- $ref: "#/components/schemas/PetCreatePartTwo"
151+
PetCreatePartOne:
152+
type: object
153+
x-model: PetCreatePartOne
149154
required:
150155
- name
151156
properties:
@@ -155,6 +160,10 @@ components:
155160
$ref: "#/components/schemas/Tag"
156161
address:
157162
$ref: "#/components/schemas/Address"
163+
PetCreatePartTwo:
164+
type: object
165+
x-model: PetCreatePartTwo
166+
properties:
158167
position:
159168
$ref: "#/components/schemas/Position"
160169
healthy:

tests/integration/test_petstore.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,4 +654,4 @@ def test_get_pet_not_found(self, spec, response_validator):
654654
response_result = response_validator.validate(request, response)
655655

656656
assert response_result.errors == []
657-
assert response_result.data == data
657+
assert response_result.data == data_json

tests/integration/test_validators.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ def test_get_pets(self, validator):
245245
'data': [
246246
{
247247
'id': 1,
248+
'name': 'Sparky'
248249
},
249250
],
250251
}

0 commit comments

Comments
 (0)