mirror of
https://github.com/correl/openapi-core.git
synced 2025-01-01 11:03:19 +00:00
Merge pull request #68 from p1c2u/feature/lazy-schema-references
Lazy schema references
This commit is contained in:
commit
a2ee03fce6
7 changed files with 76 additions and 8 deletions
|
@ -4,8 +4,9 @@ from six import iteritems
|
||||||
|
|
||||||
class PropertiesGenerator(object):
|
class PropertiesGenerator(object):
|
||||||
|
|
||||||
def __init__(self, dereferencer):
|
def __init__(self, dereferencer, schemas_registry):
|
||||||
self.dereferencer = dereferencer
|
self.dereferencer = dereferencer
|
||||||
|
self.schemas_registry = schemas_registry
|
||||||
|
|
||||||
def generate(self, properties):
|
def generate(self, properties):
|
||||||
for property_name, schema_spec in iteritems(properties):
|
for property_name, schema_spec in iteritems(properties):
|
||||||
|
@ -13,5 +14,5 @@ class PropertiesGenerator(object):
|
||||||
yield property_name, schema
|
yield property_name, schema
|
||||||
|
|
||||||
def _create_schema(self, schema_spec):
|
def _create_schema(self, schema_spec):
|
||||||
from openapi_core.schema.schemas.factories import SchemaFactory
|
schema, _ = self.schemas_registry.get_or_create(schema_spec)
|
||||||
return SchemaFactory(self.dereferencer).create(schema_spec)
|
return schema
|
||||||
|
|
|
@ -61,7 +61,7 @@ class SchemaFactory(object):
|
||||||
@property
|
@property
|
||||||
@lru_cache()
|
@lru_cache()
|
||||||
def properties_generator(self):
|
def properties_generator(self):
|
||||||
return PropertiesGenerator(self.dereferencer)
|
return PropertiesGenerator(self.dereferencer, self)
|
||||||
|
|
||||||
def _create_items(self, items_spec):
|
def _create_items(self, items_spec):
|
||||||
return self.create(items_spec)
|
return self.create(items_spec)
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
"""OpenAPI core schemas registries module"""
|
"""OpenAPI core schemas registries module"""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from lazy_object_proxy import Proxy
|
||||||
|
|
||||||
from openapi_core.schema.schemas.factories import SchemaFactory
|
from openapi_core.schema.schemas.factories import SchemaFactory
|
||||||
|
from openapi_core.schema.schemas.util import dicthash
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -13,10 +16,17 @@ class SchemaRegistry(SchemaFactory):
|
||||||
self._schemas = {}
|
self._schemas = {}
|
||||||
|
|
||||||
def get_or_create(self, schema_spec):
|
def get_or_create(self, schema_spec):
|
||||||
|
schema_hash = dicthash(schema_spec)
|
||||||
schema_deref = self.dereferencer.dereference(schema_spec)
|
schema_deref = self.dereferencer.dereference(schema_spec)
|
||||||
model = schema_deref.get('x-model', None)
|
|
||||||
|
|
||||||
if model and model in self._schemas:
|
if schema_hash in self._schemas:
|
||||||
return self._schemas[model], False
|
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"""
|
"""OpenAPI core schemas util module"""
|
||||||
from distutils.util import strtobool
|
from distutils.util import strtobool
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
|
||||||
def forcebool(val):
|
def forcebool(val):
|
||||||
|
@ -7,3 +8,7 @@ def forcebool(val):
|
||||||
val = strtobool(val)
|
val = strtobool(val)
|
||||||
|
|
||||||
return bool(val)
|
return bool(val)
|
||||||
|
|
||||||
|
|
||||||
|
def dicthash(d):
|
||||||
|
return hash(dumps(d, sort_keys=True))
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
openapi-spec-validator
|
openapi-spec-validator
|
||||||
six
|
six
|
||||||
yarl<1.2.0
|
yarl<1.2.0
|
||||||
|
lazy-object-proxy
|
||||||
|
|
|
@ -298,6 +298,8 @@ components:
|
||||||
properties:
|
properties:
|
||||||
rootCause:
|
rootCause:
|
||||||
type: string
|
type: string
|
||||||
|
suberror:
|
||||||
|
$ref: "#/components/schemas/ExtendedError"
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
type: string
|
type: string
|
||||||
responses:
|
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