def _get_field_option(field: FieldDescriptor, option, default_value): options: MessageOptions = field.GetOptions() if options.HasExtension(option): return options.Extensions[option] else: return default_value
def field_gen(buf: Buffer, field: FieldDescriptor, code_path: List[str], proto_path: List[str]) -> None: for opt, opt_value in field.GetOptions().ListFields(): if opt.full_name == "validate.rules": dispatch_field(buf, field, code_path, proto_path, opt_value) if opt_value.HasField("message"): assert field.message_type if opt_value.message.skip: return if field.message_type: for opt, opt_value in field.message_type.GetOptions().ListFields(): if (opt.full_name == "google.protobuf.MessageOptions.map_entry" and opt_value is True): return field_value = ".".join(code_path) if field.label == FieldDescriptor.LABEL_REPEATED: buf.add(f"for item in {field_value}:") with buf.indent(): buf.add("validate(item)") else: outer = ".".join(code_path[:-1]) inner = code_path[-1] buf.add(f'if {outer}.HasField("{inner}"):') with buf.indent(): buf.add(f"validate({field_value})")
def _validate_reference_field(parent: message.Message, field: descriptor.FieldDescriptor): """Ensure that the provided reference field is valid. Args: parent: The containing Message. field: The reference field descriptor. Raises: fhir_errors.InvalidFhirError: In the event of an empty reference (no extensions, no identifier, no display). """ oneof = field.message_type.oneofs[0] # Singular fields have a length of 1 for i in range(proto_utils.field_content_length(parent, field)): reference = proto_utils.get_value_at_field_index(parent, field, i) reference_field_name = reference.WhichOneof(oneof.name) if reference_field_name is None: if not (reference.extension or reference.HasField('identifier') or reference.HasField('display')): raise fhir_errors.InvalidFhirError( f'`{reference.DESCRIPTOR.name}` is an empty reference.') # There's no reference field, but there is other data. This is valid. return field_options = field.GetOptions() if not field_options.Extensions[annotations_pb2.valid_reference_type]: # The reference field does not have restrictions, so any value is fine. return if reference.HasField('uri') or reference.HasField('fragment'): # Uri and Fragment references are untyped. return # There are no reference annotations for DSTU2; skip validation if annotation_utils.get_fhir_version( reference) == annotations_pb2.FhirVersion.DSTU2: return reference_field = reference.DESCRIPTOR.fields_by_name[ reference_field_name] if annotation_utils.is_typed_reference_field(reference_field): # Ensure that the reference type is listed as "valid" reference_type = reference_field.GetOptions().Extensions[ annotations_pb2.referenced_fhir_type] is_allowed = False for valid_type in field_options.Extensions[ annotations_pb2.valid_reference_type]: if valid_type == reference_type or valid_type == 'Resource': is_allowed = True break if not is_allowed: raise fhir_errors.InvalidFhirError( f'Message `{parent.DESCRIPTOR.full_name}` contains an invalid ' f'reference type: `{reference_type}` set at: ' f'`{reference_field_name}`.')
def make_lback_protobuf_field(name, type, type1, idx=0, tag=0, default_value=""): return FieldDescriptor(name, name, idx, tag, type, type1, default_value, name, None, None, None, False, None)
def _get_pretty_value(value: Any, desc: descriptor.FieldDescriptor, components: List[Text]) -> Dict[Text, List[Any]]: """Converts value to the object easier to work with or more representative. Args: value: Object to transform. desc: Field descriptor of a value. components: Prefixes for column names. Returns: Data dictionary representing the given value. """ data = {} column_name = '.'.join(components + [desc.name]) sem_type = semantic_pb2.sem_type if desc.label == desc.LABEL_REPEATED: data[column_name] = [from_sequence(value)] elif desc.type == desc.TYPE_ENUM: char_name = next(_.name for _ in desc.enum_type.values if _.number == value) data[column_name] = [char_name] elif desc.type == desc.TYPE_BYTES: data[column_name] = [value] data[column_name + '.pretty'] = [repr(value)] elif desc.GetOptions().Extensions[sem_type].type == 'RDFDatetime': data[column_name] = [value] pretty_value = datetime.datetime.utcfromtimestamp(value / (10**6)) data[column_name + '.pretty'] = [pretty_value] elif desc.GetOptions().Extensions[sem_type].type == 'StatMode': data[column_name] = [value] data[column_name + '.pretty'] = [stat.mode_from_bitmask(value)] else: data[column_name] = [value] return data
def convert_proto_type_to_click_house_type( field_descriptor: FieldDescriptor) -> str: if field_descriptor.message_type: message_name = field_descriptor.message_type.name raise UnknownMessageError( f"Can't convert field with type message of {message_name} to Clickhouse type" ) field_meta = field_descriptor.GetOptions().Extensions[ options_pb2.field_meta] if field_meta.clickhouse_data_type: ch_type = field_meta.clickhouse_data_type else: try: ch_type = TYPES_MAPPING[field_descriptor.type] except KeyError: raise UnknownFieldError( f"Can't convert field with type {field_descriptor.type} to Clickhouse type" ) if field_descriptor.label == FieldDescriptor.LABEL_REPEATED: return f'Array({ch_type})' return ch_type
def _field_options(self, field: FieldDescriptor, provider: FieldDescriptor = None): provider = provider or self._BREWBLOX_PROVIDER return field.GetOptions().Extensions[provider]
def MakeClassDescriptor(descriptor_pool, desc_proto, package='', build_file_if_cpp=True, syntax=None): if api_implementation.Type() == 'cpp' and build_file_if_cpp: # The C++ implementation requires all descriptors to be backed by the same # definition in the C++ descriptor pool. To do this, we build a # FileDescriptorProto with the same definition as this descriptor and build # it into the pool. from google.protobuf import descriptor_pb2 file_descriptor_proto = descriptor_pb2.FileDescriptorProto() file_descriptor_proto.message_type.add().MergeFrom(desc_proto) # Generate a random name for this proto file to prevent conflicts with any # imported ones. We need to specify a file name so the descriptor pool # accepts our FileDescriptorProto, but it is not important what that file # name is actually set to. proto_name = binascii.hexlify(os.urandom(16)).decode('ascii') if package: file_descriptor_proto.name = os.path.join( package.replace('.', '/'), proto_name + '.proto') file_descriptor_proto.package = package else: file_descriptor_proto.name = proto_name + '.proto' descriptor_pool.Add(file_descriptor_proto) result = descriptor_pool.FindFileByName(file_descriptor_proto.name) if _USE_C_DESCRIPTORS: return result.message_types_by_name[desc_proto.name] full_message_name = [desc_proto.name] if package: full_message_name.insert(0, package) # Create Descriptors for enum types enum_types = {} for enum_proto in desc_proto.enum_type: full_name = '.'.join(full_message_name + [enum_proto.name]) enum_desc = EnumDescriptor(enum_proto.name, full_name, None, [ EnumValueDescriptor(enum_val.name, ii, enum_val.number) for ii, enum_val in enumerate(enum_proto.value) ]) enum_types[full_name] = enum_desc # Create Descriptors for nested types nested_types = {} for nested_proto in desc_proto.nested_type: full_name = '.'.join(full_message_name + [nested_proto.name]) # Nested types are just those defined inside of the message, not all types # used by fields in the message, so no loops are possible here. nested_desc = MakeClassDescriptor(descriptor_pool, nested_proto, package='.'.join(full_message_name), build_file_if_cpp=False, syntax=syntax) nested_types[full_name] = nested_desc fields = [] for field_proto in desc_proto.field: full_name = '.'.join(full_message_name + [field_proto.name]) enum_desc = None nested_desc = None if field_proto.json_name: json_name = field_proto.json_name else: json_name = None if field_proto.HasField('type_name'): type_name = field_proto.type_name full_type_name = '.'.join(full_message_name + [type_name[type_name.rfind('.') + 1:]]) if full_type_name in nested_types: nested_desc = nested_types[full_type_name] elif full_type_name in enum_types: enum_desc = enum_types[full_type_name] # Else type_name references a non-local type, which isn't implemented field = FieldDescriptor(field_proto.name, full_name, field_proto.number - 1, field_proto.number, field_proto.type, FieldDescriptor.ProtoTypeToCppProtoType( field_proto.type), field_proto.label, None, nested_desc, enum_desc, None, False, None, options=_OptionsOrNone(field_proto), has_default_value=False, json_name=json_name) fields.append(field) desc_name = '.'.join(full_message_name) return Descriptor(desc_proto.name, desc_name, None, None, fields, list(nested_types.values()), list(enum_types.values()), [], options=_OptionsOrNone(desc_proto))