mirror of
https://github.com/correl/openapi-core.git
synced 2024-12-28 19:19:23 +00:00
Lazy schema references
This commit is contained in:
parent
db37be8ac7
commit
3ab55e44bd
7 changed files with 76 additions and 8 deletions
|
@ -4,8 +4,9 @@ from six import iteritems
|
|||
|
||||
class PropertiesGenerator(object):
|
||||
|
||||
def __init__(self, dereferencer):
|
||||
def __init__(self, dereferencer, schemas_registry):
|
||||
self.dereferencer = dereferencer
|
||||
self.schemas_registry = schemas_registry
|
||||
|
||||
def generate(self, properties):
|
||||
for property_name, schema_spec in iteritems(properties):
|
||||
|
@ -13,5 +14,5 @@ class PropertiesGenerator(object):
|
|||
yield property_name, schema
|
||||
|
||||
def _create_schema(self, schema_spec):
|
||||
from openapi_core.schema.schemas.factories import SchemaFactory
|
||||
return SchemaFactory(self.dereferencer).create(schema_spec)
|
||||
schema, _ = self.schemas_registry.get_or_create(schema_spec)
|
||||
return schema
|
||||
|
|
|
@ -61,7 +61,7 @@ class SchemaFactory(object):
|
|||
@property
|
||||
@lru_cache()
|
||||
def properties_generator(self):
|
||||
return PropertiesGenerator(self.dereferencer)
|
||||
return PropertiesGenerator(self.dereferencer, self)
|
||||
|
||||
def _create_items(self, items_spec):
|
||||
return self.create(items_spec)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
"""OpenAPI core schemas registries module"""
|
||||
import logging
|
||||
|
||||
from lazy_object_proxy import Proxy
|
||||
|
||||
from openapi_core.schema.schemas.factories import SchemaFactory
|
||||
from openapi_core.schema.schemas.util import dicthash
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -13,10 +16,17 @@ class SchemaRegistry(SchemaFactory):
|
|||
self._schemas = {}
|
||||
|
||||
def get_or_create(self, schema_spec):
|
||||
schema_hash = dicthash(schema_spec)
|
||||
schema_deref = self.dereferencer.dereference(schema_spec)
|
||||
model = schema_deref.get('x-model', None)
|
||||
|
||||
if model and model in self._schemas:
|
||||
return self._schemas[model], False
|
||||
if schema_hash in self._schemas:
|
||||
return self._schemas[schema_hash], False
|
||||
|
||||
return self.create(schema_deref), True
|
||||
if '$ref' in schema_spec:
|
||||
schema = Proxy(lambda: self.create(schema_deref))
|
||||
else:
|
||||
schema = self.create(schema_deref)
|
||||
|
||||
self._schemas[schema_hash] = schema
|
||||
|
||||
return schema, True
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""OpenAPI core schemas util module"""
|
||||
from distutils.util import strtobool
|
||||
from json import dumps
|
||||
|
||||
|
||||
def forcebool(val):
|
||||
|
@ -7,3 +8,7 @@ def forcebool(val):
|
|||
val = strtobool(val)
|
||||
|
||||
return bool(val)
|
||||
|
||||
|
||||
def dicthash(d):
|
||||
return hash(dumps(d, sort_keys=True))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
openapi-spec-validator
|
||||
six
|
||||
yarl<1.2.0
|
||||
lazy-object-proxy
|
||||
|
|
|
@ -298,6 +298,8 @@ components:
|
|||
properties:
|
||||
rootCause:
|
||||
type: string
|
||||
suberror:
|
||||
$ref: "#/components/schemas/ExtendedError"
|
||||
additionalProperties:
|
||||
type: string
|
||||
responses:
|
||||
|
|
49
tests/unit/schema/test_schemas_registry.py
Normal file
49
tests/unit/schema/test_schemas_registry.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
import pytest
|
||||
|
||||
from jsonschema.validators import RefResolver
|
||||
from openapi_spec_validator.validators import Dereferencer
|
||||
from openapi_spec_validator import default_handlers
|
||||
|
||||
from openapi_core.schema.schemas.registries import SchemaRegistry
|
||||
|
||||
|
||||
class TestSchemaRegistryGetOrCreate(object):
|
||||
|
||||
@pytest.fixture
|
||||
def schema_dict(self):
|
||||
return {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'message': {
|
||||
'type': 'string',
|
||||
},
|
||||
'suberror': {
|
||||
'$ref': '#/components/schemas/Error',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def spec_dict(self, schema_dict):
|
||||
return {
|
||||
'components': {
|
||||
'schemas': {
|
||||
'Error': schema_dict,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@pytest.fixture
|
||||
def dereferencer(self, spec_dict):
|
||||
spec_resolver = RefResolver('', spec_dict, handlers=default_handlers)
|
||||
return Dereferencer(spec_resolver)
|
||||
|
||||
@pytest.fixture
|
||||
def schemas_registry(self, dereferencer):
|
||||
return SchemaRegistry(dereferencer)
|
||||
|
||||
def test_recursion(self, schemas_registry, schema_dict):
|
||||
schema, _ = schemas_registry.get_or_create(schema_dict)
|
||||
|
||||
assert schema.properties['suberror'] ==\
|
||||
schema.properties['suberror'].properties['suberror']
|
Loading…
Reference in a new issue