def test_union_field_roundtrip(cl_and_vals_a, cl_and_vals_b, strat): """ Classes with union fields can be unstructured and structured. """ converter = Converter(unstruct_strat=strat) cl_a, vals_a = cl_and_vals_a cl_b, vals_b = cl_and_vals_b a_field_names = {a.name for a in fields(cl_a)} b_field_names = {a.name for a in fields(cl_b)} assume(a_field_names) assume(b_field_names) common_names = a_field_names & b_field_names assume(len(a_field_names) > len(common_names)) @attr.s class C(object): a = attr.ib(type=Union[cl_a, cl_b]) inst = C(a=cl_a(*vals_a)) if strat is UnstructureStrategy.AS_DICT: assert inst == converter.structure(converter.unstructure(inst), C) else: # Our disambiguation functions only support dictionaries for now. with pytest.raises(ValueError): converter.structure(converter.unstructure(inst), C) def handler(obj, _): return converter.structure(obj, cl_a) converter.register_structure_hook(Union[cl_a, cl_b], handler) assert inst == converter.structure(converter.unstructure(inst), C)
def test_renaming(cl_and_vals, data): converter = Converter() cl, vals = cl_and_vals attrs = fields(cl) to_replace = data.draw(sampled_from(attrs)) u_fn = make_dict_unstructure_fn( cl, converter, **{to_replace.name: override(rename="class")} ) s_fn = make_dict_structure_fn( cl, converter, **{to_replace.name: override(rename="class")} ) converter.register_structure_hook(cl, s_fn) converter.register_unstructure_hook(cl, u_fn) inst = cl(*vals) raw = converter.unstructure(inst) assert "class" in raw new_inst = converter.structure(raw, cl) assert inst == new_inst
def init_converter(): converter = Converter() # converter.register_unstructure_hook(pendulum.DateTime, lambda dt: dt.to_iso8601_string()) # converter.register_structure_hook(pendulum.DateTime, lambda ts, _: pendulum.parse(ts)) converter.register_unstructure_hook(datetime, lambda dt: dt.isoformat() + 'Z') converter.register_structure_hook(datetime, lambda ts, _: parser.parse(ts)) return converter
def with_datetime_hooks(converter: cattr.Converter) -> cattr.Converter: converter.register_unstructure_hook(datetime.datetime, datetime_to_serializable) converter.register_structure_hook( datetime.datetime, lambda date_str, _: serializable_to_datetime(date_str) ) converter.register_unstructure_hook(datetime.date, date_to_serializable) converter.register_structure_hook( datetime.date, lambda date_str, _: serializable_to_date(date_str) ) return converter
def test_unmodified_generated_structuring(cl_and_vals): converter = Converter() cl, vals = cl_and_vals fn = make_dict_structure_fn(cl, converter) inst = cl(*vals) unstructured = converter.unstructure(inst) converter.register_structure_hook(cl, fn) res = converter.structure(unstructured, cl) assert inst == res
def setup_cattrs(converter: cattr.Converter) -> None: lookup: typing.Dict[int, typing.Callable[ [typing.Mapping[str, typing.Any], typing.Any], Component]] = { 1: cattr.gen.make_dict_structure_fn(ActionRow, converter), 2: cattr.gen.make_dict_structure_fn(Button, converter), 3: cattr.gen.make_dict_structure_fn(SelectMenu, converter), 4: cattr.gen.make_dict_structure_fn(TextInput, converter), } # mypy can't infer types here def structure_snowflake(raw: typing.Any, ty: typing.Type[Component]) -> Component: return lookup[raw["type"]](raw, ty) converter.register_structure_hook(Component, structure_snowflake)
def test_structuring_primitive_union_hook(ints): """Registering a union loading hook works.""" converter = Converter() def structure_hook(val, cl): """Even ints are passed through, odd are stringified.""" return val if val % 2 == 0 else str(val) converter.register_structure_hook(Union[str, int], structure_hook) converted = converter.structure(ints, List[Union[str, int]]) for x, y in zip(ints, converted): if x % 2 == 0: assert x == y else: assert str(x) == y
def create_cattrs_converter(): converter = Converter() converter.register_structure_hook(bool, _structure_bool) converter.register_structure_hook(string_type, _structure_string) converter.register_structure_hook(Model, _structure_schematics) converter.register_structure_hook(BaseType, _structure_basetype) converter.register_structure_hook(datetime, _structure_datetime) converter.register_unstructure_hook(Model, _unstructure_schematics) converter.register_unstructure_hook(datetime, _unstructure_datetime) converter.register_unstructure_hook(BaseType, _unstructure_basetype) return converter
def test_subclass_registration_is_honored(): """If a subclass is registered after a superclass, that subclass handler should be dispatched for structure """ converter = Converter() class Foo(object): def __init__(self, value): self.value = value class Bar(Foo): pass converter.register_structure_hook(Foo, lambda obj, cls: cls("foo")) assert converter.structure(None, Foo).value == "foo" assert converter.structure(None, Bar).value == "foo" converter.register_structure_hook(Bar, lambda obj, cls: cls("bar")) assert converter.structure(None, Foo).value == "foo" assert converter.structure(None, Bar).value == "bar"
def _register_converter(converter: Converter) -> Converter: converter.register_structure_hook( base_models.Snowflake, lambda d, _: base_models.Snowflake(int(d))) converter.register_structure_hook( permission_models.BitwisePermissionFlags, lambda d, _: permission_models.BitwisePermissionFlags(int(d)), ) def unstruct_permissions( d: permission_models.BitwisePermissionFlags) -> str: return str(d.value) converter.register_unstructure_hook( permission_models.BitwisePermissionFlags, unstruct_permissions) def struct_int_or_str(d: typing.Any, _: object) -> typing.Union[int, str]: try: return int(d) except ValueError: return str(d) converter.register_structure_hook(typing.Union[int, str], struct_int_or_str) UNKNOWN_TYPE = base_models.UNKNOWN_TYPE # TODO: use the new methods in `typing` def is_unknown(cls: type) -> bool: if getattr(cls, '__origin__') is typing.Union and UNKNOWN_TYPE in getattr( cls, '__args__'): return True return False def unknown_function(data: object, cls: typing.Type[typing.Any]) -> object: default: typing.Tuple[typing.Any] = ( ) # type: ignore[assignment] # mypy 0.930 regression args: typing.Tuple[typing.Type[typing.Any]] = getattr( cls, '__args__', default) if len(args) == 2: return converter.structure(data, [n for n in args if n != UNKNOWN_TYPE][0]) else: type: typing.Any = typing.Union[tuple(n for n in args if n != UNKNOWN_TYPE)] return converter.structure(data, type) converter.register_structure_hook_func(is_unknown, unknown_function) models.setup_cattrs(converter) return converter
import attr from aiohttp import ClientSession from cattr import Converter from pendulum import DateTime, from_timestamp from ujson import dumps, loads from pyrseia import create_client, rpc from pyrseia.aiohttp import aiohttp_client_adapter from pyrseia.wire import Call PRODUCTION_URL = "https://buy.itunes.apple.com/verifyReceipt" SANDBOX_URL = "https://sandbox.itunes.apple.com/verifyReceipt" APP_STORE_CONVERTER = Converter() APP_STORE_CONVERTER.register_structure_hook( DateTime, lambda m, _: from_timestamp(float(m) / 1000) ) @attr.s(slots=True, frozen=True) class ResponseBody: """This structure is called 'responseBody' by Apple.""" @unique class Environment(str, Enum): SANDBOX = "Sandbox" PRODUCTION = "Production" @unique class Status(IntEnum): SUCCESS = 0
pickle_dump = f.partial(pickle.dump, protocol=2) def u2c(value): """Convert underscore string to capitalized string.""" # Make a list of capitalized words and underscores to be preserved capitalized_words = [w.capitalize() if w else '_' for w in value.split('_')] return "".join(capitalized_words) CUSTOM_CVT = Converter() CUSTOM_CVT.register_unstructure_hook( np.ndarray, lambda a: dict(dtype=a.dtype.name, data=a.tobytes(), shape=list(a.shape))) CUSTOM_CVT.register_structure_hook( np.ndarray, lambda a, _: np.frombuffer(a['data'], dtype=a['dtype']).reshape(tuple(a['shape']))) def to_dict(obj): """Convert object to dict""" global CUSTOM_CVT return CUSTOM_CVT.unstructure(obj) def from_dict(d, cls, compatible=True): """Convert dict to obj of class.""" global CUSTOM_CVT if compatible and hasattr(cls, '__attrs_attrs__'): nd = {} for a in cls.__attrs_attrs__: if a.name not in d:
datetime_type = DateTimeType() def _structure_datetime(data, cls): if not data: raise ValueError("datetime is empty") return datetime_type.to_native(data) def _unstructure_datetime(data): return data.isoformat() converter = Converter() converter.register_structure_hook(datetime, _structure_datetime) converter.register_unstructure_hook(datetime, _unstructure_datetime) def validate_len(instance, attribute, value): if len(value) > 100: raise ValueError("val should <= 100") @attr.s class Artist2: name = attr.ib(type=str, validator=validate_len) @attr.s class Album2: