Example #1
0
def test_structuring_unsupported():
    """Loading unsupported classes should throw."""
    converter = Converter()
    with raises(ValueError):
        converter.structure(1, Converter)
    with raises(ValueError):
        converter.structure(1, Union[int, str])
Example #2
0
def test_structuring_optional_primitives(primitive_and_type):
    """Test structuring Optional primitive types."""
    converter = Converter()
    val, type = primitive_and_type

    assert converter.structure(val, Optional[type]) == val
    assert converter.structure(None, Optional[type]) is None
Example #3
0
def test_structuring_lists_of_opt(list_and_type):
    """Test structuring lists of Optional primitive types."""
    converter = Converter()
    l, t = list_and_type

    l.append(None)
    args = t.__args__

    is_optional = args[0] is Optional or (is_union_type(args[0])
                                          and len(args[0].__args__) == 2
                                          and args[0].__args__[1] is NoneType)

    if not is_bare(t) and (args[0] not in (Any, str) and not is_optional):
        with raises((TypeError, ValueError)):
            converter.structure(l, t)

    optional_t = Optional[args[0]]
    # We want to create a generic type annotation with an optional
    # type parameter.
    t = change_type_param(t, optional_t)

    converted = converter.structure(l, t)

    for x, y in zip(l, converted):
        assert x == y

    t.__args__ = args
Example #4
0
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)
Example #5
0
def test_simple_roundtrip_defaults(cls_and_vals, strat):
    """
    Simple classes with metadata can be unstructured and restructured.
    """
    a, _ = cls_and_vals
    cl = make_class("HypClass", {"a": a})
    converter = Converter(unstruct_strat=strat)
    inst = cl()
    assert converter.unstructure(converter.structure(
        {}, cl)) == converter.unstructure(inst)
    assert inst == converter.structure(converter.unstructure(inst), cl)
Example #6
0
def test_structuring_unsupported():
    """Loading unsupported classes should throw."""
    converter = Converter()
    with raises(StructureHandlerNotFoundError) as exc:
        converter.structure(1, Converter)

    assert exc.value.type_ is Converter

    with raises(StructureHandlerNotFoundError) as exc:
        converter.structure(1, Union[int, str])

    assert exc.value.type_ is Union[int, str]
Example #7
0
def test_structuring_seqs(seq_and_type):
    """Test structuring sequence generic types."""
    converter = Converter()
    iterable, t = seq_and_type
    converted = converter.structure(iterable, t)
    for x, y in zip(iterable, converted):
        assert x == y
Example #8
0
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
Example #9
0
def test_simple_roundtrip(cls_and_vals, strat):
    """
    Simple classes with metadata can be unstructured and restructured.
    """
    converter = Converter(unstruct_strat=strat)
    cl, vals = cls_and_vals
    inst = cl(*vals)
    assert inst == converter.structure(converter.unstructure(inst), cl)
Example #10
0
def test_stringifying_dicts(dict_and_type):
    converter = Converter()
    d, t = dict_and_type

    converted = converter.structure(d, Dict[str, str])

    for k, v in d.items():
        assert converted[str(k)] == str(v)
Example #11
0
def test_structuring_dicts(dict_and_type):
    converter = Converter()
    d, t = dict_and_type

    converted = converter.structure(d, t)

    assert converted == d
    assert converted is not d
Example #12
0
def test_nested_roundtrip(cls_and_vals, strat):
    """
    Nested classes with metadata can be unstructured and restructured.
    """
    converter = Converter(unstruct_strat=strat)
    cl, vals = cls_and_vals
    # Vals are a tuple, convert into a dictionary.
    inst = cl(*vals)
    assert inst == converter.structure(converter.unstructure(inst), cl)
Example #13
0
def test_optional_field_roundtrip(cl_and_vals):
    """
    Classes with optional fields can be unstructured and structured.
    """
    converter = Converter()
    cl, vals = cl_and_vals

    @attr.s
    class C(object):
        a = attr.ib(type=Optional[cl])

    inst = C(a=cl(*vals))
    assert inst == converter.structure(converter.unstructure(inst), C)

    inst = C(a=None)
    unstructured = converter.unstructure(inst)

    assert inst == converter.structure(unstructured, C)
Example #14
0
def test_310_optional_field_roundtrip(cl_and_vals):
    """
    Classes with optional fields can be unstructured and structured.
    """
    converter = Converter()
    cl, vals = cl_and_vals

    @define
    class C:
        a: cl | None

    inst = C(a=cl(*vals))
    assert inst == converter.structure(converter.unstructure(inst), C)

    inst = C(a=None)
    unstructured = converter.unstructure(inst)

    assert inst == converter.structure(unstructured, C)
Example #15
0
def test_structuring_sets(set_and_type, set_type):
    """Test structuring generic sets."""
    converter = Converter()
    set_, input_set_type = set_and_type

    if input_set_type not in (Set, FrozenSet, MutableSet):
        set_type = set_type[input_set_type.__args__[0]]

    converted = converter.structure(set_, set_type)
    assert converted == set_

    # Set[int] can't be used with isinstance any more.
    non_generic = (set_type.__origin__
                   if set_type.__origin__ is not None else set_type)
    assert isinstance(converted, non_generic)

    converted = converter.structure(set_, Any)
    assert converted == set_
    assert isinstance(converted, type(set_))
Example #16
0
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"
Example #17
0
def test_structuring_dicts_opts(dict_and_type, data):
    """Structure dicts, but with optional primitives."""
    converter = Converter()
    d, t = dict_and_type
    assume(not is_bare(t))
    t.__args__ = (t.__args__[0], Optional[t.__args__[1]])
    d = {k: v if data.draw(booleans()) else None for k, v in d.items()}

    converted = converter.structure(d, t)

    assert converted == d
    assert converted is not d
Example #18
0
def test_structure_hook_func():
    """ testing the hook_func method """
    converter = Converter()

    def can_handle(cls):
        return cls.__name__.startswith("F")

    def handle(obj, cls):
        return "hi"

    class Foo(object):
        pass

    class Bar(object):
        pass

    converter.register_structure_hook_func(can_handle, handle)

    assert converter.structure(10, Foo) == "hi"
    with raises(ValueError):
        converter.structure(10, Bar)
Example #19
0
def deserialize(*, data: str, structure: TStructure,
                converter: cattr.Converter) -> TDeserializeReturn:
    """Translate API data into models."""
    try:
        data = json.loads(data)
    except json.JSONDecodeError as ex:
        raise DeserializeError(f"Bad json {ex}")
    try:
        response: TDeserializeReturn = converter.structure(  # type: ignore
            data, structure)
    except (TypeError, AttributeError) as ex:
        raise DeserializeError(f"Bad data {ex}")
    return response
Example #20
0
def test_stringifying_sets(set_and_type):
    """Test structuring generic sets and converting the contents to str."""
    converter = Converter()
    set_, input_set_type = set_and_type

    if is_bare(input_set_type):
        input_set_type = input_set_type[str]
    else:
        input_set_type.__args__ = (str, )
    converted = converter.structure(set_, input_set_type)
    assert len(converted) == len(set_)
    for e in set_:
        assert str(e) in converted
Example #21
0
def test_stringifying_lists_of_opt(list_and_type):
    """Test structuring Optional primitive types into strings."""
    converter = Converter()
    l, t = list_and_type

    l.append(None)

    converted = converter.structure(l, List[Optional[str]])

    for x, y in zip(l, converted):
        if x is None:
            assert x is y
        else:
            assert str(x) == y
Example #22
0
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
Example #23
0
def test_structuring_hetero_tuples(list_of_vals_and_types):
    """Test structuring heterogenous tuples."""
    converter = Converter()
    types = tuple(e[1] for e in list_of_vals_and_types)
    vals = [e[0] for e in list_of_vals_and_types]
    t = Tuple[types]

    converted = converter.structure(vals, t)

    assert isinstance(converted, tuple)

    for x, y in zip(vals, converted):
        assert x == y

    for x, y in zip(types, converted):
        assert isinstance(y, x)
Example #24
0
def test_stringifying_tuples(list_of_vals_and_types):
    """Stringify all elements of a heterogeneous tuple."""
    converter = Converter()
    vals = [e[0] for e in list_of_vals_and_types]
    t = Tuple[(str, ) * len(list_of_vals_and_types)]

    converted = converter.structure(vals, t)

    assert isinstance(converted, tuple)

    for x, y in zip(vals, converted):
        assert str(x) == y

    for x in converted:
        # this should just be unicode, but in python2, '' is not unicode
        assert isinstance(x, str)
Example #25
0
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
Example #26
0
def test_structure_union_edge_case():
    converter = Converter()

    @attr.s(auto_attribs=True)
    class A:
        a1: Any
        a2: Optional[Any] = None

    @attr.s(auto_attribs=True)
    class B:
        b1: Any
        b2: Optional[Any] = None

    assert converter.structure([{
        "a1": "foo"
    }, {
        "b1": "bar"
    }], List[Union[A, B]]) == [A("foo"), B("bar")]
Example #27
0
def test_able_to_structure_generics(converter: Converter, t, t2, result):
    res = converter.structure(asdict(result), TClass[t, t2])

    assert res == result
Example #28
0
def test_structuring_enums(data, enum):
    """Test structuring enums by their values."""
    converter = Converter()
    val = data.draw(sampled_from(list(enum)))

    assert converter.structure(val.value, enum) == val
Example #29
0
def test_structuring_primitives(primitive_and_type):
    """Test just structuring a primitive value."""
    converter = Converter()
    val, t = primitive_and_type
    assert converter.structure(val, t) == val
    assert converter.structure(val, Any) == val