def value_from_storage_dict( cls, storage_dict: Dict[str, Any], klass: Type, args_for_class: Mapping[str, Parameter], whitelist_map: WhitelistMap, descent_path: str, ) -> NamedTuple: klass_kwargs = {} for key, value in storage_dict.items(): unpacked = unpack_inner_value(value, whitelist_map, f"{descent_path}.{key}") if key in args_for_class: klass_kwargs[key] = unpacked elif key == "job_origin_id": # For backcompat, we store instigator_origin_id as job_origin_id klass_kwargs["instigator_origin_id"] = unpacked elif key == "job_name": # For backcompat, we store instigator_name as job_name klass_kwargs["instigator_name"] = unpacked elif key == "job_type": # For backcompat, we store instigator_type as job_type klass_kwargs["instigator_type"] = unpacked return klass(**klass_kwargs)
def test_forward_compat_serdes_new_enum_field(): test_map = WhitelistMap.create() @_whitelist_for_serdes(whitelist_map=test_map) class Corge(Enum): FOO = 1 BAR = 2 assert test_map.has_enum_entry("Corge") corge = Corge.FOO packed = pack_inner_value(corge, whitelist_map=test_map, descent_path="") # pylint: disable=function-redefined @_whitelist_for_serdes(whitelist_map=test_map) class Corge(Enum): FOO = 1 BAR = 2 BAZ = 3 unpacked = unpack_inner_value(packed, whitelist_map=test_map, descent_path="") assert unpacked != corge assert unpacked.name == corge.name assert unpacked.value == corge.value
def test_serdes_enum_backcompat(): test_map = WhitelistMap.create() @_whitelist_for_serdes(whitelist_map=test_map) class Corge(Enum): FOO = 1 BAR = 2 assert test_map.has_enum_entry("Corge") corge = Corge.FOO packed = pack_inner_value(corge, whitelist_map=test_map, descent_path="") class CorgeBackCompatSerializer(DefaultEnumSerializer): @classmethod def value_from_storage_str(cls, storage_str, klass): if storage_str == "FOO": value = "FOO_FOO" else: value = storage_str return super().value_from_storage_str(value, klass) # pylint: disable=function-redefined @_whitelist_for_serdes(whitelist_map=test_map, serializer=CorgeBackCompatSerializer) class Corge(Enum): BAR = 2 BAZ = 3 FOO_FOO = 4 unpacked = unpack_inner_value(packed, whitelist_map=test_map, descent_path="") assert unpacked != corge assert unpacked == Corge.FOO_FOO
def value_from_storage_dict(cls, storage_dict, klass, args_for_class, whitelist_map, descent_path): raw_dict = { key: unpack_inner_value(value, whitelist_map, f"{descent_path}.{key}") for key, value in storage_dict.items() } # typical pattern is to use the same serialization format from an old field and passing # it in as a new field return klass( **{ key: value for key, value in raw_dict.items() if key in args_for_class }, new_name=raw_dict.get("old_name"), )
def value_from_storage_dict( cls, storage_dict: Dict[str, Any], klass: Type, args_for_class: Mapping[str, Parameter], whitelist_map: WhitelistMap, descent_path: str, ) -> NamedTuple: raw_dict = { key: unpack_inner_value(value, whitelist_map, f"{descent_path}.{key}") for key, value in storage_dict.items() } # the stored key for the instigator name should always be `job_name`, for backcompat # and origin id stability (hash of the serialized tuple). Make sure we fetch it from the # raw storage dict and pass it in as instigator_name to ExternalInstigatorOrigin instigator_name = raw_dict.get("job_name") return klass( **{key: value for key, value in raw_dict.items() if key in args_for_class}, instigator_name=instigator_name, )