예제 #1
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, _ = 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:
        unstructured = converter.unstructure(inst)
        assert inst == converter.structure(
            converter.unstructure(unstructured), 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)
        unstructured = converter.unstructure(inst)
        assert inst == converter.structure(unstructured, C)
예제 #2
0
def test_type_overrides(cl_and_vals):
    """
    Type overrides on the GenConverter work.
    """
    converter = Converter(type_overrides={int: override(omit_if_default=True)})
    cl, vals = cl_and_vals

    inst = cl(*vals)
    unstructured = converter.unstructure(inst)

    for field, val in zip(fields(cl), vals):
        if field.type is int:
            if field.default is not None:
                if isinstance(field.default, Factory):
                    if not field.default.takes_self and field.default() == val:
                        assert field.name not in unstructured
                elif field.default == val:
                    assert field.name not in unstructured
예제 #3
0
def test_seq_of_simple_classes_unstructure(cls_and_vals,
                                           seq_type_and_annotation):
    """Dumping a sequence of primitives is a simple copy operation."""
    converter = Converter()

    test_val = ("test", 1)

    for cl, _ in cls_and_vals:
        converter.register_unstructure_hook(cl, lambda _: test_val)
        break  # Just register the first class.

    seq_type, annotation = seq_type_and_annotation
    inputs = seq_type(cl(*vals) for cl, vals in cls_and_vals)
    outputs = converter.unstructure(
        inputs,
        unstructure_as=annotation[cl]
        if annotation not in (Tuple, tuple) else annotation[cl, ...],
    )
    assert all(e == test_val for e in outputs)
예제 #4
0
def test_overriding_generated_structure():
    """Test overriding a generated structure hook works."""
    converter = Converter()

    @attr.define
    class Inner:
        a: int

    @attr.define
    class Outer:
        i: Inner

    inst = Outer(Inner(1))
    raw = converter.unstructure(inst)
    converter.structure(raw, Outer)

    converter.register_structure_hook(Inner, lambda p, _: Inner(p["a"] + 1))

    r = converter.structure(raw, Outer)
    assert r.i.a == 2
예제 #5
0
 def _unstructure(self, converter: GenConverter) -> dict[str, Any]:
     # omit glyph name attribute, already used as key
     glyphs: dict[str, dict[str, Any]] = {}
     for glyph_name in self._glyphs:
         g = converter.unstructure(self[glyph_name])
         assert glyph_name == g.pop("name")
         glyphs[glyph_name] = g
     d: dict[str, Any] = {
         # never omit name even if == 'public.default' as that acts as
         # the layer's "key" in the layerSet.
         "name": self._name,
     }
     default: Any
     for key, value, default in [
         ("default", self._default, self._name == DEFAULT_LAYER_NAME),
         ("glyphs", glyphs, {}),
         ("lib", self._lib, {}),
     ]:
         if not converter.omit_if_default or value != default:
             d[key] = value
     if self.color is not None:
         d["color"] = self.color
     return d
예제 #6
0
def test_unstructure_generic_attrs():
    c = GenConverter()

    @attrs(auto_attribs=True)
    class Inner(Generic[T]):
        a: T

    @attrs(auto_attribs=True)
    class Outer:
        inner: Inner[int]

    initial = Outer(Inner(1))
    raw = c.unstructure(initial)

    assert raw == {"inner": {"a": 1}}

    new = c.structure(raw, Outer)
    assert initial == new

    @attrs(auto_attribs=True)
    class OuterStr:
        inner: Inner[str]

    assert c.structure(raw, OuterStr) == OuterStr(Inner("1"))
예제 #7
0
 def _unstructure(self, converter: GenConverter) -> list[dict[str, Any]]:
     return [converter.unstructure(layer) for layer in self]
예제 #8
0
def test_collection_unstructure_override_seq():
    """Test overriding unstructuring seq."""

    # First approach, predicate hook
    c = GenConverter()

    c._unstructure_func.register_func_list([(
        is_sequence,
        partial(c.gen_unstructure_iterable, unstructure_to=tuple),
        True,
    )])

    assert c.unstructure([1, 2, 3], unstructure_as=Sequence[int]) == (1, 2, 3)

    @attr.define
    class MyList:
        args = attr.ib(converter=list)

    # Second approach, using abc.MutableSequence
    c = GenConverter(unstruct_collection_overrides={MutableSequence: MyList})

    assert c.unstructure([1, 2, 3], unstructure_as=Sequence[int]) == [1, 2, 3]
    assert c.unstructure([1, 2, 3],
                         unstructure_as=MutableSequence[int]) == MyList([
                             1,
                             2,
                             3,
                         ])
    assert c.unstructure([1, 2, 3]) == MyList([
        1,
        2,
        3,
    ])
    assert c.unstructure((1, 2, 3)) == [
        1,
        2,
        3,
    ]

    # Second approach, using abc.Sequence
    c = GenConverter(unstruct_collection_overrides={Sequence: MyList})

    assert c.unstructure([1, 2, 3],
                         unstructure_as=Sequence[int]) == MyList([1, 2, 3])
    assert c.unstructure(
        [1, 2, 3], unstructure_as=MutableSequence[int]) == MyList([1, 2, 3])

    assert c.unstructure([1, 2, 3]) == MyList([1, 2, 3])

    assert c.unstructure((1, 2, 3), unstructure_as=tuple[int, ...]) == MyList([
        1,
        2,
        3,
    ])

    # Second approach, using __builtins__.list
    c = GenConverter(unstruct_collection_overrides={list: MyList})

    assert c.unstructure([1, 2, 3], unstructure_as=Sequence[int]) == [1, 2, 3]
    assert c.unstructure([1, 2, 3], unstructure_as=MutableSequence[int]) == [
        1,
        2,
        3,
    ]
    assert c.unstructure([1, 2, 3]) == MyList([
        1,
        2,
        3,
    ])
    assert c.unstructure((1, 2, 3)) == [
        1,
        2,
        3,
    ]

    # Second approach, using __builtins__.tuple
    c = GenConverter(unstruct_collection_overrides={tuple: MyList})

    assert c.unstructure([1, 2, 3], unstructure_as=Sequence[int]) == [1, 2, 3]
    assert c.unstructure([1, 2, 3], unstructure_as=MutableSequence[int]) == [
        1,
        2,
        3,
    ]
    assert c.unstructure([1, 2, 3]) == [
        1,
        2,
        3,
    ]
    assert c.unstructure((1, 2, 3)) == MyList([
        1,
        2,
        3,
    ])
예제 #9
0
def test_collection_unstructure_override_mapping():
    """Test overriding unstructuring mappings."""

    # Using Counter
    c = GenConverter(unstruct_collection_overrides={Counter: Map})
    assert c.unstructure(Counter({1: 2})) == Map({1: 2})
    assert c.unstructure(Counter({1: 2}),
                         unstructure_as=Counter[int]) == Map({1: 2})
    assert c.unstructure({1: 2}) == {1: 2}
    assert c.unstructure({1: 2}, unstructure_as=MutableMapping[int, int]) == {
        1: 2
    }
    assert c.unstructure({1: 2}, unstructure_as=Mapping[int, int]) == {1: 2}

    # Using __builtins__.dict
    c = GenConverter(unstruct_collection_overrides={dict: Map})

    assert c.unstructure(Counter({1: 2})) == Map({1: 2})
    assert c.unstructure(Counter({1: 2}),
                         unstructure_as=Counter[int]) == Map({1: 2})
    assert c.unstructure({1: 2}) == Map({1: 2})
    assert c.unstructure({1: 2}, unstructure_as=MutableMapping[int, int]) == {
        1: 2
    }
    assert c.unstructure({1: 2}, unstructure_as=Mapping[int, int]) == {1: 2}

    # Using MutableMapping
    c = GenConverter(unstruct_collection_overrides={MutableMapping: Map})

    assert c.unstructure(Counter({1: 2})) == Map({1: 2})
    assert c.unstructure(Counter({1: 2}),
                         unstructure_as=Counter[int]) == Map({1: 2})
    assert c.unstructure({1: 2}) == Map({1: 2})
    assert c.unstructure({1: 2},
                         unstructure_as=MutableMapping[int,
                                                       int]) == Map({1: 2})
    assert c.unstructure({1: 2}, unstructure_as=Mapping[int, int]) == {1: 2}

    # Using Mapping
    c = GenConverter(unstruct_collection_overrides={Mapping: Map})

    assert c.unstructure(Counter({1: 2})) == Map({1: 2})
    assert c.unstructure(Counter({1: 2}),
                         unstructure_as=Counter[int]) == Map({1: 2})
    assert c.unstructure({1: 2}) == Map({1: 2})
    assert c.unstructure({1: 2},
                         unstructure_as=MutableMapping[int,
                                                       int]) == Map({1: 2})
    assert c.unstructure({1: 2}, unstructure_as=Mapping[int,
                                                        int]) == Map({1: 2})