Lazy schema references

This commit is contained in:
p1c2u 2018-07-28 21:57:49 +01:00
parent db37be8ac7
commit 3ab55e44bd
7 changed files with 76 additions and 8 deletions

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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))

View file

@ -1,3 +1,4 @@
openapi-spec-validator
six
yarl<1.2.0
lazy-object-proxy

View file

@ -298,6 +298,8 @@ components:
properties:
rootCause:
type: string
suberror:
$ref: "#/components/schemas/ExtendedError"
additionalProperties:
type: string
responses:

View 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']