def test_to_python_unknown_value(): class Foo(proto.Enum): FOO_UNSPECIFIED = 0 BAR = 1 BAZ = 2 enum_rule = EnumRule(Foo) with mock.patch.object(warnings, 'warn') as warn: assert enum_rule.to_python(4) == 4 warn.assert_called_once_with('Unrecognized Foo enum value: 4')
def test_to_python(): class Foo(proto.Enum): FOO_UNSPECIFIED = 0 BAR = 1 BAZ = 2 enum_rule = EnumRule(Foo) foo_a = enum_rule.to_python(1) foo_b = enum_rule.to_python(Foo.BAR) assert foo_a is foo_b is Foo.BAR
def test_to_proto(): class Foo(proto.Enum): FOO_UNSPECIFIED = 0 BAR = 1 BAZ = 2 enum_rule = EnumRule(Foo) foo_a = enum_rule.to_proto(Foo.BAR) foo_b = enum_rule.to_proto(1) foo_c = enum_rule.to_proto('BAR') # We want to distinguish literal `1` from `Foo.BAR` here # (they are equivalent but not identical). assert foo_a is foo_b is foo_c is 1 # noqa: F632
def __new__(mcls, name, bases, attrs): # Do not do any special behavior for `proto.Enum` itself. if bases[0] == enum.IntEnum: return super().__new__(mcls, name, bases, attrs) # Get the essential information about the proto package, and where # this component belongs within the file. package, marshal = _package_info.compile(name, attrs) # Run the superclass constructor. cls = super().__new__(mcls, name, bases, attrs) # Register the enum with the marshal. marshal.register(cls, EnumRule(cls)) # Done; return the class. return cls
def __new__(mcls, name, bases, attrs): # Do not do any special behavior for `proto.Enum` itself. if bases[0] == enum.IntEnum: return super().__new__(mcls, name, bases, attrs) # Get the essential information about the proto package, and where # this component belongs within the file. package, marshal = _package_info.compile(name, attrs) # Determine the local path of this proto component within the file. local_path = tuple(attrs.get("__qualname__", name).split(".")) # Sanity check: We get the wrong full name if a class is declared # inside a function local scope; correct this. if "<locals>" in local_path: ix = local_path.index("<locals>") local_path = local_path[: ix - 1] + local_path[ix + 1 :] # Determine the full name in protocol buffers. full_name = ".".join((package,) + local_path).lstrip(".") filename = _file_info._FileInfo.proto_file_name( attrs.get("__module__", name.lower()) ) # Retrieve any enum options. # We expect something that looks like an EnumOptions message, # either an actual instance or a dict-like representation. pb_options = "_pb_options" opts = attrs.pop(pb_options, {}) # This is the only portable way to remove the _pb_options name # from the enum attrs. # In 3.7 onwards, we can define an _ignore_ attribute and do some # mucking around with that. if pb_options in attrs._member_names: idx = attrs._member_names.index(pb_options) attrs._member_names.pop(idx) # Make the descriptor. enum_desc = descriptor_pb2.EnumDescriptorProto( name=name, # Note: the superclass ctor removes the variants, so get them now. # Note: proto3 requires that the first variant value be zero. value=sorted( ( descriptor_pb2.EnumValueDescriptorProto(name=name, number=number) # Minor hack to get all the enum variants out. for name, number in attrs.items() if isinstance(number, int) ), key=lambda v: v.number, ), options=opts, ) file_info = _file_info._FileInfo.maybe_add_descriptor(filename, package) if len(local_path) == 1: file_info.descriptor.enum_type.add().MergeFrom(enum_desc) else: file_info.nested_enum[local_path] = enum_desc # Run the superclass constructor. cls = super().__new__(mcls, name, bases, attrs) # We can't just add a "_meta" element to attrs because the Enum # machinery doesn't know what to do with a non-int value. # The pb is set later, in generate_file_pb cls._meta = _EnumInfo(full_name=full_name, pb=None) file_info.enums[full_name] = cls # Register the enum with the marshal. marshal.register(cls, EnumRule(cls)) # Generate the descriptor for the file if it is ready. if file_info.ready(new_class=cls): file_info.generate_file_pb(new_class=cls, fallback_salt=full_name) # Done; return the class. return cls