def _container_attrib_builder(name, container, mapper): """Builder for container attributes.""" factory = Factory(container) def _attrib(type, **kwargs): """Define a container attribute.""" kwargs.setdefault('metadata', {}) kwargs['metadata'][KEY_CLS] = type kwargs['default'] = factory def _converter(value): """Convert value to the given type.""" if isinstance(value, container): return mapper(type, value) elif isinstance(value, dict) and '@type' in value: # Collection might have been compacted away, wrap value return mapper(type, container([value])) elif value is None: return value raise ValueError(value) kwargs.setdefault('converter', _converter) return attrib(**kwargs) return _attrib
def test_no_init_order(self, slots, frozen): """ If an attribute is `init=False`, it's legal to come after a mandatory attribute. """ make_class("C", { "a": attr(default=Factory(list)), "b": attr(init=False), }, slots=slots, frozen=frozen)
def test_factory_sugar(self): """ Passing factory=f is syntactic sugar for passing default=Factory(f). """ @attr.s class C(object): x = attr.ib(factory=list) assert Factory(list) == attr.fields(C).x.default
def test_factory_takes_self(self): """ If takes_self on factories is True, self is passed. """ C = make_class("C", {"x": attr(default=Factory( (lambda self: self), takes_self=True ))}) i = C() assert i is i.x
def test_default_decorator_sets(self): """ Decorator wraps the method in a Factory with pass_self=True and sets the default. """ a = attr.ib() @a.default def f(self): pass assert Factory(f, True) == a._default
def test_convert_factory_property(self, val, init): """ Property tests for attributes with convert, and a factory default. """ C = make_class("C", {"y": attr(), "x": attr(init=init, default=Factory(lambda: val), convert=lambda v: v + 1), }) c = C(2) assert c.x == val + 1 assert c.y == 2
def _attrib(type, **kwargs): """Define a container attribute.""" kwargs.setdefault('metadata', {}) kwargs['metadata'][KEY_CLS] = type kwargs['default'] = Factory(container) def _converter(value): """Convert value to the given type.""" if isinstance(value, container): return mapper(type, value) elif value is None: return value raise ValueError(value) kwargs.setdefault('converter', _converter) return attrib(context=context, **kwargs)
def test_convert_factory_property(self, val, init): """ Property tests for attributes with convert, and a factory default. """ C = make_class("C", ordered_dict([ ("y", attr.ib()), ("x", attr.ib( init=init, default=Factory(lambda: val), converter=lambda v: v + 1 )), ])) c = C(2) assert c.x == val + 1 assert c.y == 2
def test_no_init_default(self, slots, frozen): """ If `init` is False but a Factory is specified, don't allow passing that argument but initialize it anyway. """ C = make_class("C", { "_a": attr(init=False, default=42), "_b": attr(init=False, default=Factory(list)), "c": attr() }, slots=slots, frozen=frozen) with pytest.raises(TypeError): C(a=1, c=2) with pytest.raises(TypeError): C(b=1, c=2) i = C(23) assert (42, [], 23) == (i._a, i._b, i.c)
class C(object): x = attr.ib(factory=Factory(list))
class C(object): x = attr.ib(factory=list, default=Factory(list))
def test_factory_hashable(self): """ Factory is hashable. """ assert hash(Factory(None, False)) == hash(Factory(None, False))
class C(object): __attrs_attrs__ = [ simple_attr(name="a", default=Factory(list)), simple_attr(name="b", default=Factory(D)), ]