Skip to content

Commit 328fc00

Browse files
committed
Schema source
1 parent 82a24f7 commit 328fc00

File tree

8 files changed

+115
-5
lines changed

8 files changed

+115
-5
lines changed

openapi_core/extensions/models/factories.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"""OpenAPI X-Model extension factories module"""
2-
from openapi_core.extensions.models.models import Model
2+
from openapi_core.extensions.models.models import Model, DictModel
33

44

55
class ModelClassFactory(object):
66

7-
base_class = Model
7+
base_class = DictModel
88

99
def create(self, name):
1010
return type(name, (self.base_class, ), {})

openapi_core/extensions/models/models.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@ def __dict__(self):
99
raise NotImplementedError
1010

1111

12+
class DictModel(dict, BaseModel):
13+
14+
@property
15+
def __dict__(self):
16+
return self
17+
18+
def __getattr__(self, name):
19+
try:
20+
return self[name]
21+
except KeyError:
22+
raise AttributeError
23+
24+
1225
class Model(BaseModel):
1326
"""Model class for OpenAPI X-Model."""
1427

openapi_core/schema/schemas/factories.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def create(self, schema_spec):
5656
default=default, nullable=nullable, enum=enum,
5757
deprecated=deprecated, all_of=all_of, one_of=one_of,
5858
additional_properties=additional_properties,
59+
_source=schema_deref,
5960
)
6061

6162
@property

openapi_core/schema/schemas/models.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __init__(
6161
self, schema_type=None, model=None, properties=None, items=None,
6262
schema_format=None, required=None, default=None, nullable=False,
6363
enum=None, deprecated=False, all_of=None, one_of=None,
64-
additional_properties=None):
64+
additional_properties=None, _source=None):
6565
self.type = SchemaType(schema_type)
6666
self.model = model
6767
self.properties = properties and dict(properties) or {}
@@ -76,9 +76,28 @@ def __init__(
7676
self.one_of = one_of and list(one_of) or []
7777
self.additional_properties = additional_properties
7878

79+
self._source = _source
80+
7981
self._all_required_properties_cache = None
8082
self._all_optional_properties_cache = None
8183

84+
@property
85+
def __dict__(self):
86+
data = {
87+
'type': self.type.value,
88+
}
89+
90+
if self.format:
91+
data['format'] = self.format
92+
93+
if self.all_of:
94+
data['allOf'] = list(map(lambda x: x.__dict__, self.all_of))
95+
96+
if self.one_of:
97+
data['oneOf'] = list(map(lambda x: x.__dict__, self.one_of))
98+
99+
return data
100+
82101
def __getitem__(self, name):
83102
return self.properties[name]
84103

openapi_core/schema/schemas/validators.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from jsonschema import validators
2+
from jsonschema.validators import Draft4Validator
3+
4+
15
class TypeValidator(object):
26

37
def __init__(self, *types, **options):
@@ -24,3 +28,63 @@ def __call__(self, value):
2428
return False
2529

2630
return True
31+
32+
33+
class Draft4ExtendedValidatorFactory(Draft4Validator):
34+
"""Draft4Validator with extra validators factory."""
35+
36+
@classmethod
37+
def create(cls):
38+
"""Creates a customized Draft4ExtendedValidator."""
39+
spec_validators = cls._get_spec_validators()
40+
return validators.extend(Draft4Validator, spec_validators)
41+
42+
@classmethod
43+
def _get_spec_validators(cls):
44+
from jsonschema import _validators
45+
46+
return {
47+
'$ref': _validators.ref,
48+
'properties': _validators.properties_draft4,
49+
'additionalProperties': _validators.additionalProperties,
50+
'patternProperties': _validators.patternProperties,
51+
'type': _validators.type_draft4,
52+
'dependencies': _validators.dependencies,
53+
'required': _validators.required_draft4,
54+
'minProperties': _validators.minProperties_draft4,
55+
'maxProperties': _validators.maxProperties_draft4,
56+
'allOf': _validators.allOf_draft4,
57+
'oneOf': _validators.oneOf_draft4,
58+
'anyOf': _validators.anyOf_draft4,
59+
'not': _validators.not_draft4,
60+
}
61+
62+
63+
64+
class SchemaValidator(object):
65+
66+
def __init__(self, spec_dict, schema_dict):
67+
self.spec_dict = spec_dict
68+
self.schema_dict = schema_dict
69+
70+
def __call__(self, value):
71+
nullable = self.spec_dict.get('nullable', 'false')
72+
if nullable == 'true' and value is None:
73+
return True
74+
75+
validator = self.validator_cls(self.schema_dict)
76+
validator.validate(value)
77+
return True
78+
79+
def iter_errors(self, value):
80+
nullable = self.spec_dict.get('nullable', 'false')
81+
if nullable == 'true' and value is None:
82+
return
83+
84+
validator = self.validator_cls(self.schema_dict)
85+
for err in validator.iter_errors(value):
86+
yield err
87+
88+
@property
89+
def validator_cls(self):
90+
return Draft4ExtendedValidatorFactory.create()

openapi_core/schema/specs/factories.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ def create(self, spec_dict, spec_url=''):
3434
paths = self.paths_generator.generate(paths)
3535
components = self.components_factory.create(components_spec)
3636
spec = Spec(
37-
info, list(paths), servers=list(servers), components=components)
37+
info, list(paths), servers=list(servers), components=components,
38+
_source=spec_dict_deref,
39+
)
3840
return spec
3941

4042
@property

openapi_core/schema/specs/models.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
class Spec(object):
1414
"""Represents an OpenAPI Specification for a service."""
1515

16-
def __init__(self, info, paths, servers=None, components=None):
16+
def __init__(
17+
self, info, paths, servers=None, components=None, _source=None):
1718
self.info = info
1819
self.paths = paths and dict(paths)
1920
self.servers = servers or []
2021
self.components = components
2122

23+
self._source = _source
24+
2225
def __getitem__(self, path_name):
2326
return self.paths[path_name]
2427

openapi_core/validation/request/validators.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ def _get_parameters(self, request, operation):
5858
else:
5959
parameters[param.location.value][param_name] = value
6060

61+
if param.schema and value is not None:
62+
from jsonschema.exceptions import ValidationError
63+
from openapi_core.schema.schemas.validators import SchemaValidator
64+
validator = SchemaValidator(
65+
self.spec._source, param.schema.__dict__)
66+
errs = validator.iter_errors(value)
67+
errors.extend(errs)
68+
6169
return parameters, errors
6270

6371
def _get_body(self, request, operation):

0 commit comments

Comments
 (0)