def __init__(self, api, name, def_dict, method): super(Parameter, self).__init__(def_dict, api, parent=method, wire_name=name) self.ValidateName(name) self.schema = api # TODO(user): Deal with dots in names better. What we should do is: # For x.y, x.z create a little class X, with members y and z. Then # have the constructor method take an X. self._repeated = self.values.get('repeated', False) self._required = self.values.get('required', False) self._location = (self.values.get('location') or self.values.get('restParameterType') or 'query') # TODO(user): Why not just use Schema.Create here? referenced_schema = self.values.get('$ref') if referenced_schema: self._data_type = (api.SchemaByName(referenced_schema) or data_types.SchemaReference(referenced_schema, api)) elif def_dict.get('type') == 'array': self._data_type = Schema.Create(api, name, def_dict, name, method) elif self.values.get('enum'): self._data_type = data_types.Enum(def_dict, api, name, self.values.get('enum'), self.values.get('enumDescriptions'), parent=method) self.SetTemplateValue('enumType', self._data_type) else: self._data_type = data_types.PrimitiveDataType(def_dict, api, parent=self) if self._repeated: self._data_type = data_types.ArrayDataType(name, self._data_type, parent=self)
def _CreateArrayType(cls, api, def_dict, wire_name, class_name, schema_id, parent): items = def_dict.get('items') if not items: raise ApiException('array without items in: %s' % def_dict) tentative_class_name = class_name # TODO(user): THIS IS STUPID. We should not rename things items. # if we have an anonymous type within a map or array, it should be # called 'Item', and let the namespacing sort it out. if schema_id: _LOGGER.debug('Top level schema %s is an array', class_name) tentative_class_name += 'Items' base_type = api.DataTypeFromJson(items, tentative_class_name, parent=parent, wire_name=wire_name) _LOGGER.debug(' %s is ArrayOf<%s>', class_name, base_type.class_name) array_type = data_types.ArrayDataType(tentative_class_name, base_type, wire_name=wire_name, parent=parent) if schema_id: array_type.SetTemplateValue('className', schema_id) return array_type
def __init__(self, api, name, def_dict, method): super(Parameter, self).__init__(def_dict, api, parent=method) self.requires_imports = [] self.ValidateName(name) self.schema = api self.SetTemplateValue('wireName', name) # TODO(user): Deal with dots in names better. What we should do is: # For x.y, x.z create a little class X, with members y and z. Then # have the constructor method take an X. self._repeated = self.values.get('repeated', False) self._required = self.values.get('required', False) self._data_type = data_types.BuiltInDataType(def_dict, api, parent=self) if self._repeated: self._data_type = data_types.ArrayDataType(self._data_type, parent=self) if self.values.get('enum'): enum = Enum(api, name, self._data_type, self.values.get('enum'), self.values.get('enumDescriptions')) self.SetTemplateValue('enumType', enum)
def Create(api, default_name, def_dict, wire_name, parent=None): """Construct a Schema or DataType from a discovery dictionary. Schemas contain either object declarations, simple type declarations, or references to other Schemas. Object declarations conceptually map to real classes. Simple types will map to a target language built-in type. References should effectively be replaced by the referenced Schema. Args: api: (Api) the Api instance owning the Schema default_name: (str) the default name of the Schema. If there is an 'id' member in the definition, that is used for the name instead. def_dict: (dict) a discovery dictionary wire_name: The name which will identify objects of this type in data on the wire. parent: (Schema) The containing schema. To be used to establish nesting for anonymous sub-schemas. Returns: A Schema or DataType. Raises: ApiException: If the definition dict is not correct. """ schema_id = def_dict.get('id') if schema_id: name = schema_id else: name = default_name class_name = api.ToClassName(name, element_type='schema') # Schema objects come in several patterns. # # 1. Simple objects # { type: object, properties: { "foo": {schema} ... }} # # 2. Maps of objects # { type: object, additionalProperties: { "foo": {inner_schema} ... }} # # What we want is a data type which is Map<string, {inner_schema}> # The schema we create here is essentially a built in type which we # don't want to generate a class for. # # 3. Arrays of objects # { type: array, items: { inner_schema }} # # Same kind of issue as the map, but with List<{inner_schema}> # # 4. Primative data types, described by type and format. # { type: string, format: int32 } # # 5. Refs to another schema. # { $ref: name } if 'type' in def_dict: # The 'type' field of the schema can either be 'array', 'object', or a # base json type. json_type = def_dict['type'] if json_type == 'object': # Look for full object definition. You can have properties or # additionalProperties, but it does not do anything useful to have # both. # Replace properties dict with Property's props = def_dict.get('properties') if props: # This case 1 from above properties = [] schema = Schema(api, name, def_dict, parent=parent) if wire_name: schema.SetTemplateValue('wireName', wire_name) for prop_name, prop_dict in props.iteritems(): Trace(' adding prop: %s to %s' % (prop_name, name)) properties.append( Property(api, schema, prop_name, prop_dict)) Trace('Marking %s fully defined' % schema.values['className']) schema.SetTemplateValue('properties', properties) return schema # Look for case 2 additional_props = def_dict.get(_ADDITIONAL_PROPERTIES) if additional_props: Trace('Have only additionalProps for %s, dict=%s' % (name, str(additional_props))) # TODO(user): Remove this hack at the next large breaking change # The "Items" added to the end is unneeded and ugly. This is for # temporary backwards compatability. And in case 3 too. if additional_props.get('type') == 'array': name = '%sItems' % name # Note, since this is an interim, non class just to hold the map # make the parent schema the parent passed in, not myself. base_type = api.DataTypeFromJson(additional_props, name, parent=parent, wire_name=wire_name) map_type = data_types.MapDataType(base_type, parent=parent) Trace(' %s is MapOf<string, %s>' % (class_name, base_type.class_name)) return map_type raise ApiException('object without properties in: %s' % def_dict) elif json_type == 'array': # Case 3: Look for array definition items = def_dict.get('items') if not items: raise ApiException('array without items in: %s' % def_dict) tentative_class_name = class_name if schema_id: Trace('Top level schema %s is an array' % class_name) tentative_class_name += 'Items' base_type = api.DataTypeFromJson(items, tentative_class_name, parent=parent, wire_name=wire_name) Trace(' %s is ArrayOf<%s>' % (class_name, base_type.class_name)) array_type = data_types.ArrayDataType(base_type, parent=parent) # If I am not a top level schema, mark me as not generatable if not schema_id: array_type.SetTemplateValue('builtIn', True) else: Trace('Top level schema %s is an array' % class_name) array_type.SetTemplateValue('className', schema_id) return array_type else: # Case 4: This must be a basic type. Create a DataType for it. format_type = def_dict.get('format') if format_type: Trace(' Found Type: %s with Format: %s' % (json_type, format_type)) base_type = data_types.BuiltInDataType(def_dict, api, parent=parent) return base_type referenced_schema = def_dict.get('$ref') if referenced_schema: # Case 5: Reference to another Schema. # # There are 4 ways you can see '$ref' in discovery. # 1. In a property of a schema, pointing back to one previously defined # 2. In a property of a schema, pointing forward # 3. In a method request or response pointing to a defined schema # 4. In a method request or response or property of a schema pointing to # something undefined. # # This code is not reached in case 1. The way the Generators loads # schemas (see _BuildSchemaDefinitions), is to loop over them and add # them to a dict of schemas. A backwards reference would be in the table # so the DataTypeFromJson call in the Property constructor will resolve # to the defined schema. # # For case 2. Just creating this placeholder here is fine. When the # actual schema is hit in the loop in _BuildSchemaDefinitions, we will # replace the entry and DataTypeFromJson will resolve the to the new def. # # For case 3, we should not reach this code, because the # DataTypeFromJson would # have returned the defined schema. # # For case 4, we punt on the whole API. return data_types.SchemaReference(referenced_schema, api) raise ApiException('Cannot decode JSON Schema for: %s' % def_dict)