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 test_nodefs_generated_unstructuring(cl_and_vals): """Test omitting default values on a per-attribute basis.""" converter = Converter() cl, vals = cl_and_vals attr_is_default = False for attr, val in zip(cl.__attrs_attrs__, vals): if attr.default is not NOTHING: fn = make_dict_unstructure_fn( cl, converter, **{attr.name: override(omit_if_default=True)} ) if attr.default == val: attr_is_default = True break else: assume(False) converter.register_unstructure_hook(cl, fn) inst = cl(*vals) res = converter.unstructure(inst) if attr_is_default: assert attr.name not in res
def test_no_linecache(): """Linecaching should be disableable.""" @define class A: a: int c = GenConverter() before = len(linecache.cache) c.structure(c.unstructure(A(1)), A) after = len(linecache.cache) assert after == before + 2 @define class B: a: int before = len(linecache.cache) c.register_structure_hook( B, make_dict_structure_fn(B, c, _cattrs_use_linecache=False)) c.register_unstructure_hook( B, make_dict_unstructure_fn(B, c, _cattrs_use_linecache=False)) c.structure(c.unstructure(B(1)), B) assert len(linecache.cache) == before
def test_nodefs_generated_unstructuring_cl(converter, cl_and_vals): """Test omitting default values on a per-class basis.""" cl, vals = cl_and_vals for attr, val in zip(cl.__attrs_attrs__, vals): if attr.default is not NOTHING: break else: assume(False) converter.register_unstructure_hook( cl, make_dict_unstructure_fn(cl, converter, omit_if_default=True)) inst = cl(*vals) res = converter.unstructure(inst) for attr, val in zip(cl.__attrs_attrs__, vals): if attr.default is not NOTHING: if not isinstance(attr.default, Factory): if val == attr.default: assert attr.name not in res else: assert attr.name in res else: if val == attr.default.factory(): assert attr.name not in res else: assert attr.name in res
def test_omitting(): converter = Converter() @define class A: a: int b: int = field(init=False) converter.register_unstructure_hook( A, make_dict_unstructure_fn(A, converter, b=override(omit=True))) assert converter.unstructure(A(1)) == {"a": 1}
def test_individual_overrides(cl_and_vals): """ Test omitting default values on a per-class basis, but with individual overrides. """ converter = Converter() cl, vals = cl_and_vals for attr, val in zip(adapted_fields(cl), vals): if attr.default is not NOTHING: break else: assume(False) chosen_name = attr.name converter.register_unstructure_hook( cl, make_dict_unstructure_fn( cl, converter, omit_if_default=True, **{attr.name: override(omit_if_default=False)} ), ) inst = cl(*vals) res = converter.unstructure(inst) assert "Hyp" not in repr(res) assert "Factory" not in repr(res) for attr, val in zip(adapted_fields(cl), vals): if attr.name == chosen_name: assert attr.name in res elif attr.default is not NOTHING: if not isinstance(attr.default, Factory): if val == attr.default: assert attr.name not in res else: assert attr.name in res else: if attr.default.takes_self: if val == attr.default.factory(inst): assert attr.name not in res else: assert attr.name in res else: if val == attr.default.factory(): assert attr.name not in res else: assert attr.name in res
def test_unmodified_generated_unstructuring(converter, cl_and_vals): cl, vals = cl_and_vals fn = make_dict_unstructure_fn(cl, converter) inst = cl(*vals) res_expected = converter.unstructure(inst) converter.register_unstructure_hook(cl, fn) res_actual = converter.unstructure(inst) assert res_expected == res_actual
def test_individual_overrides(cl_and_vals): """ Test omitting default values on a per-class basis, but with individual overrides. """ converter = Converter() cl, vals = cl_and_vals for attr, val in zip(cl.__attrs_attrs__, vals): if attr.default is not NOTHING: break else: assume(False) chosen = attr converter.register_unstructure_hook( cl, make_dict_unstructure_fn( cl, converter, omit_if_default=True, **{attr.name: override(omit_if_default=False)}), ) inst = cl(*vals) res = converter.unstructure(inst) for attr, val in zip(cl.__attrs_attrs__, vals): if attr is chosen: assert attr.name in res elif attr.default is not NOTHING: if not isinstance(attr.default, Factory): if val == attr.default: assert attr.name not in res else: assert attr.name in res else: if val == attr.default.factory(): assert attr.name not in res else: assert attr.name in res
# This requires that the names of the attributes are renamed during (un-)structuring. # Additionally we only want to unstructure attributes which don't have the default value # (e.g. Layer.default_view_configuration has many attributes which are all optionally). for cls in [ DatasetProperties, MagViewProperties, DatasetViewConfiguration, LayerViewConfiguration, ]: dataset_converter.register_unstructure_hook( cls, make_dict_unstructure_fn( cls, dataset_converter, **{ a.name: override(omit_if_default=True, rename=snake_to_camel_case(a.name)) for a in attr.fields(cls) # pylint: disable=not-an-iterable }, ), ) dataset_converter.register_structure_hook( cls, make_dict_structure_fn( cls, dataset_converter, **{ a.name: override(rename=snake_to_camel_case(a.name)) for a in attr.fields(cls) # pylint: disable=not-an-iterable }, ),
def unstructure_adapt_to_camel_case(type): return make_dict_unstructure_fn( type, converter, **{ a.name: override(rename=to_camel_case(a.name)) for a in fields(type) })
def __typed_unstructure(self, obj): cls = type(obj) unstructure_fn = make_dict_unstructure_fn(cls, self) return {"__type__": type(obj).__name__, **unstructure_fn(obj)}