def link_group(self, group): """Links a schema group object. Args: group: schema group object """ group.interface = self.get_obj(group.desc.type_name) options = group.desc.options.Extensions[wdl_options_pb2.implconfig] parent_interface = self.get_obj(group.desc.parent.parent.full_name) for mapping in options.trait_mapping: from_component = parent_interface.component_list.by_name( getattr(mapping, 'from')) to_component = group.interface.component_list.by_name(mapping.to) if not from_component or not to_component: raise exception.InvalidUsage('Implements mapping for %s is invalid.' % parent_interface.full_name) ref = schema.GroupComponentRef(to_component.base_name, to_component.number, '') ref.source_component = from_component group.component_list.append(ref) if options.HasField('min_version'): group.min_version = options.min_version
def get_extends(self, extends_name): extends = None if extends_name: extends = self.get_obj(extends_name) if not extends: raise exception.InvalidUsage('Cannot find extended object %s' % (extends_name)) return extends
def link_enum(self, enum): """Parses the protobuf enum descriptor turns into a Google Weave Enum. Args: enum: A protobuf enum description to add to schema Raises: InvalidType: Encountered an invalid type while linking DuplicateObject: Duplicate enum value pair encountered InvalidUsage: Option used in an invalid way """ options = enum.desc.options.Extensions[wdl_options_pb2.enumopts] enum_pairs = enum.pair_list if self.is_common(enum.full_name): self.link_common_enum(enum) elif (not enum.desc.parent or not isinstance( self.get_obj(enum.desc.parent.full_name), schema.StructEnumCollectionBase)): raise exception.InvalidType( ('Unexpected enum %s defined outside a typespace or trait' % enum)) if options is not None: if options.compatibility.HasField('min_version'): enum.min_version = options.compatibility.min_version if options.compatibility.HasField('max_version'): enum.max_version = options.compatibility.max_version for value in enum.desc.values.values(): description = self.parse_comments(value) pair_opts = value.options.Extensions[wdl_options_pb2.enumvalue] value.full_name.replace( inflection.underscore(enum.base_name).decode('utf-8').upper() + '_', '') enum_pair = schema.EnumPair(value.full_name, value.number, description) enum_pair.source_file = enum.source_file if pair_opts is not None: if pair_opts.compatibility.HasField('min_version'): enum_pair.min_version = pair_opts.compatibility.min_version if pair_opts.compatibility.HasField('max_version'): enum_pair.max_version = pair_opts.compatibility.max_version try: enum_pairs.append(enum_pair) except exception.DuplicateObject: pass enum.is_bitmask = options.bitmask if options.extends: raise exception.InvalidUsage('Extending enums is not yet supported.')
def validate_extendable(self, options, fields, parent_fields_dict=None): """Checks that the fields extend the parent fields. Args: options: The descriptor options. fields: The fields to check. parent_fields_dict: the parent fields to check against. """ if options.extendable: if (options.reserved_tag_min <= 0 or options.reserved_tag_max <= 1 or options.reserved_tag_max <= options.reserved_tag_min): raise exception.InvalidUsage('Extendable options are invalid') for field in fields: if (parent_fields_dict is not None and field.base_name in parent_fields_dict): continue # Ignore fields that are in parent if (field.number > options.reserved_tag_max or field.number < options.reserved_tag_min): raise exception.InvalidUsage( 'Field %s in %s number %d is outside reserved range. %d-%d' % (field.base_name, field.parent.full_name, field.number, options.reserved_tag_min, options.reserved_tag_max))
def link_resource_component(self, component): """Link and initialize an nwv resource component. Args: component: Uninitialized component objcet """ options = component.desc.options if options.HasExtension(wdl_options_pb2.traitinst): instance_id = options.Extensions[wdl_options_pb2.traitinst].instance component.instance_id = instance_id if not options.HasExtension(wdl_options_pb2.traitconfig): raise exception.InvalidUsage( 'Trait config missing on {}. Every trait instance ' 'component must define trait config options.'.format( component.full_name)) config_options = options.Extensions[wdl_options_pb2.traitconfig] component.published_by = schema.ResourceComponent.PublishedBy( config_options.published_by) if component.published_by == schema.ResourceComponent.PublishedBy.SELF: if not config_options.HasField('proxied'): raise exception.InvalidUsage( 'Trait component {} is published by SELF but does not ' 'explicitly define proxied.'.format(component.full_name)) elif (component.published_by == schema.ResourceComponent.PublishedBy.EXTERNAL): if not config_options.HasField('subscribed'): raise exception.InvalidUsage( 'Trait component {} is published by EXTERNAL but does ' 'not explicitly define subscribed.'.format(component.full_name)) component.subscribed = config_options.subscribed component.proxied = config_options.proxied component.trait = self.get_obj(component.desc.type_name) if config_options.HasField('min_version'): component.min_version = config_options.min_version refinement_options = config_options.prop_refinement for refinement_option in refinement_options: prop_name = refinement_option.property prop = component.trait.state_list.by_name(prop_name) if not prop: raise exception.InvalidType('Property {} does not exist on trait {}' .format(prop_name, component.full_name)) refinement = component.property_refinements[ prop_name] = schema.FieldRefinement(prop) refinement.implemented = not refinement_option.unimplemented field_desc = refinement.field.desc field_type = WRAPPER_TYPES.get(field_desc.type_name, field_desc.type) if refinement_option.initial_bool_value: if field_type != field_desc.TYPE_BOOL: raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'BOOL')) refinement.initial_value = refinement_option.initial_bool_value if refinement_option.initial_int_value: if field_type not in (field_desc.TYPE_INT32, field_desc.TYPE_INT64): raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'INT32 or INT64')) refinement.initial_value = refinement_option.initial_int_value if refinement_option.initial_uint_value: if field_type not in (field_desc.TYPE_UINT32, field_desc.TYPE_UINT64): raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'UINT32 or UINT64')) refinement.initial_value = refinement_option.initial_uint_value if refinement_option.initial_number_value: if field_type not in (field_desc.TYPE_FLOAT, field_desc.TYPE_DOUBLE): raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'FLOAT or DOUBLE')) refinement.initial_value = refinement_option.initial_number_value if refinement_option.initial_string_value: if field_type != field_desc.TYPE_STRING: raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'STRING')) refinement.initial_value = refinement_option.initial_string_value if refinement_option.initial_bytes_base16_value: if field_type != field_desc.TYPE_BYTES: raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type, 'BYTES')) value = refinement_option.initial_bytes_base16_value refinement.initial_bytes_base16_value = value if refinement_option.initial_resource_id_value: if field_desc.type_name != '.weave.common.ResourceId': raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.component, 'weave.common.ResourceId')) refinement.initial_value = refinement_option.initial_resource_id_value if refinement_option.initial_duration_value: if field_desc.type_name != '.google.protobuf.Duration': raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type_name, 'google.protobuf.Duration')) refinement.initial_value = [{ 'seconds': o.seconds, 'nanos': o.nanos } for o in refinement_option.initial_duration_value] if refinement_option.initial_timestamp_value: if field_desc.type_name != '.google.protobuf.Timestamp': raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type_name, 'google.protobuf.Timestamp')) refinement.initial_value = [{ 'seconds': o.seconds, 'nanos': o.nanos } for o in refinement_option.initial_timestamp_value] if refinement_option.initial_enum_value_name: if field_type != field_desc.TYPE_ENUM: raise exception.InvalidType( 'Inital value for for {} on {} is type {}, expected {}'.format( prop_name, component.full_name, field_desc.type_name, 'ENUM')) refinement.initial_value = refinement_option.initial_enum_value_name if refinement_option.initial_struct_value: raise exception.InvalidUsage( 'Component {} defines an initial value; initial values for' ' structs is not implemented.'.format(component.full_name)) # Every initial value option is an array # Flatten the array if the target property is not an array if (refinement.initial_value and field_desc.label != field_desc.LABEL_REPEATED): if len(refinement.initial_value) > 1: raise exception.InvalidType( 'Array of initial values given for {}, which is not' ' an array'.format(component.full_name)) refinement.initial_value = refinement.initial_value[0]
def link_field(self, field): """Links a schema field object. Args: field: Unintialized schema field object """ options = None if field.desc.options.HasExtension(wdl_options_pb2.prop): options = field.desc.options.Extensions[wdl_options_pb2.prop] elif field.desc.options.HasExtension(wdl_options_pb2.param): options = field.desc.options.Extensions[wdl_options_pb2.param] parent_writable = True if field.desc.parent.options.HasExtension(wdl_options_pb2.properties): props = field.desc.parent.options.Extensions[wdl_options_pb2.properties] if props.HasField('writable'): parent_writable = ( wdl_options_pb2.WriteAccess.Name(props.writable) == 'READ_WRITE') field.objc_class_prefix = field.desc.file.options.objc_class_prefix field.java_outer_classname = field.desc.file.options.java_outer_classname field.source_file = field.desc.file.name field.is_oneof = field.desc.is_oneof() if options: field.is_nullable = options.nullable field.writable = parent_writable if field.desc.options.HasExtension(wdl_options_pb2.prop): props = field.desc.options.Extensions[wdl_options_pb2.prop] if options.HasField('writable'): field.writable = ( wdl_options_pb2.WriteAccess.Name(props.writable) == 'READ_WRITE') field.is_optional = options.optional field.is_ephemeral = options.ephemeral if options is not None: if options.compatibility.HasField('min_version'): field.min_version = options.compatibility.min_version if options.compatibility.HasField('max_version'): field.max_version = options.compatibility.max_version field_desc = field.desc if field_desc.is_map(): # Unwrap maps to value field field_desc = field.desc.message_type.fields['value'] field.map_key = self.get_obj( field.desc.message_type.fields['key'].full_name) self.parse_options(field.map_key, field.desc.options.Extensions[wdl_options_pb2.keyprop]) field.map_value = self.get_obj( field.desc.message_type.fields['value'].full_name) self.parse_options(field.map_value, options) field.is_map = True else: field.is_array = field.desc.label == field_desc.LABEL_REPEATED field_type = field_desc.type if field_desc.type_name in WRAPPER_TYPES: field_type = WRAPPER_TYPES[field_desc.type_name] if not field.is_nullable and not self.is_common(field.full_name): # The fact that this was wrapped is lost, so can't be checked in # separate validator raise exception.InvalidUsage( 'Field %s is a wrapper type ' 'but is not nullable.' % field_desc.full_name) elif field.is_nullable and field_type != field_desc.TYPE_MESSAGE: raise exception.InvalidUsage('Field %s is nullable, but ' 'is not a wrapper or strudct ' 'type.' % field_desc.full_name) field.data_type = { field_desc.TYPE_FLOAT: schema.Field.DataType.FLOAT, field_desc.TYPE_DOUBLE: schema.Field.DataType.DOUBLE, field_desc.TYPE_UINT64: schema.Field.DataType.UINT64, field_desc.TYPE_UINT32: schema.Field.DataType.UINT32, field_desc.TYPE_INT64: schema.Field.DataType.INT64, field_desc.TYPE_INT32: schema.Field.DataType.INT32, field_desc.TYPE_FIXED64: schema.Field.DataType.INT64, field_desc.TYPE_FIXED32: schema.Field.DataType.INT32, field_desc.TYPE_SINT64: schema.Field.DataType.INT64, field_desc.TYPE_SINT32: schema.Field.DataType.INT32, field_desc.TYPE_STRING: schema.Field.DataType.STRING, field_desc.TYPE_ENUM: schema.Field.DataType.ENUM, field_desc.TYPE_BOOL: schema.Field.DataType.BOOL, field_desc.TYPE_BYTES: schema.Field.DataType.BYTES, field_desc.TYPE_MESSAGE: schema.Field.DataType.STRUCT, }[field_type] if field.data_type is schema.Field.DataType.STRUCT: field.struct_type = self.get_obj(field_desc.type_name) if not isinstance(field.struct_type, schema.Struct): raise exception.InvalidType( 'Message {}, referenced by field {}, is not a struct. ' 'Fields may only reference structs.'.format( field.struct_type.full_name, field.full_name)) # set metadata for legacy support field.metadata = field.struct_type elif field.data_type is schema.Field.DataType.ENUM: field.enum_type = self.get_obj(field_desc.type_name) # set metadata for legacy support field.metadata = field.enum_type self.parse_options(field, options)