66from json import loads
77from six import iteritems
88
9+ from openapi_core .models import ModelFactory
10+
911log = logging .getLogger (__name__ )
1012
1113DEFAULT_CAST_CALLABLE_GETTER = {
1214 'integer' : int ,
1315 'number' : float ,
1416 'boolean' : lambda x : bool (strtobool (x )),
15- 'object' : loads ,
1617}
1718
1819
1920class Schema (object ):
2021 """Represents an OpenAPI Schema."""
2122
2223 def __init__ (
23- self , schema_type , properties = None , items = None , spec_format = None ,
24- required = False ):
24+ self , schema_type , model = None , properties = None , items = None ,
25+ spec_format = None , required = False ):
2526 self .type = schema_type
27+ self .model = model
2628 self .properties = properties and dict (properties ) or {}
2729 self .items = items
2830 self .format = spec_format
@@ -33,10 +35,10 @@ def __getitem__(self, name):
3335
3436 def get_cast_mapping (self ):
3537 mapping = DEFAULT_CAST_CALLABLE_GETTER .copy ()
36- if self . items :
37- mapping . update ({
38- 'array ' : lambda x : list ( map ( self .items . unmarshal , x )) ,
39- })
38+ mapping . update ({
39+ 'array' : self . _unmarshal_collection ,
40+ 'object ' : self ._unmarshal_object ,
41+ })
4042
4143 return defaultdict (lambda : lambda x : x , mapping )
4244
@@ -68,6 +70,19 @@ def unmarshal(self, value):
6870
6971 return casted
7072
73+ def _unmarshal_collection (self , value ):
74+ return list (map (self .items .unmarshal , value ))
75+
76+ def _unmarshal_object (self , value ):
77+ if isinstance (value , (str , bytes )):
78+ value = loads (value )
79+
80+ properties = {}
81+ for prop_name , prop in iteritems (self .properties ):
82+ prop_value = value .get (prop_name )
83+ properties [prop_name ] = prop .unmarshal (prop_value )
84+ return ModelFactory ().create (properties , name = self .model )
85+
7186
7287class PropertiesGenerator (object ):
7388
@@ -90,7 +105,9 @@ def __init__(self, dereferencer):
90105
91106 def create (self , schema_spec ):
92107 schema_deref = self .dereferencer .dereference (schema_spec )
108+
93109 schema_type = schema_deref ['type' ]
110+ model = schema_deref .get ('x-model' , None )
94111 required = schema_deref .get ('required' , False )
95112 properties_spec = schema_deref .get ('properties' , None )
96113 items_spec = schema_deref .get ('items' , None )
@@ -104,10 +121,50 @@ def create(self, schema_spec):
104121 items = self ._create_items (items_spec )
105122
106123 return Schema (
107- schema_type , properties = properties , items = items , required = required )
124+ schema_type , model = model , properties = properties , items = items ,
125+ required = required ,
126+ )
108127
109128 def _generate_properties (self , properties_spec ):
110129 return PropertiesGenerator (self .dereferencer ).generate (properties_spec )
111130
112131 def _create_items (self , items_spec ):
113- return SchemaFactory (self .dereferencer ).create (items_spec )
132+ return self .create (items_spec )
133+
134+
135+ class SchemaRegistry (SchemaFactory ):
136+
137+ def __init__ (self , dereferencer ):
138+ super (SchemaRegistry , self ).__init__ (dereferencer )
139+ self ._schemas = {}
140+
141+ def get_or_create (self , schema_spec ):
142+ schema_deref = self .dereferencer .dereference (schema_spec )
143+ model = schema_deref .get ('x-model' , None )
144+
145+ if model and model in self ._schemas :
146+ return self ._schemas [model ], False
147+
148+ return self .create (schema_deref ), True
149+
150+ def _create_items (self , items_spec ):
151+ schema , _ = self .get_or_create (items_spec )
152+ return schema
153+
154+
155+ class SchemasGenerator (object ):
156+
157+ def __init__ (self , dereferencer ):
158+ self .dereferencer = dereferencer
159+
160+ def generate (self , schemas_spec ):
161+ schemas_deref = self .dereferencer .dereference (schemas_spec )
162+
163+ for schema_name , schema_spec in iteritems (schemas_deref ):
164+ schema = self ._create_schema (schema_spec )
165+ yield schema_name , schema
166+
167+ def _create_schema (self , schema_spec ):
168+ schema , _ = SchemaRegistry (self .dereferencer ).get_or_create (
169+ schema_spec )
170+ return schema
0 commit comments