Example #1
0
    def test_multiple_empty(self):
        """
        Empty list/tuple for validator is the same as None.
        """
        C1 = make_class("C", {"x": attr.ib(validator=[])})
        C2 = make_class("C", {"x": attr.ib(validator=None)})

        assert inspect.getsource(C1.__init__) == inspect.getsource(C2.__init__)
Example #2
0
 def test_no_init_order(self):
     """
     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),
     })
Example #3
0
 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.ib(default=Factory(list)),
         "b": attr.ib(init=False),
     }, slots=slots, frozen=frozen)
Example #4
0
    def test_catches_wrong_attrs_type(self):
        """
        Raise `TypeError` if an invalid type for attrs is passed.
        """
        with pytest.raises(TypeError) as e:
            make_class("C", object())

        assert (
            "attrs argument must be a dict or a list.",
        ) == e.value.args
Example #5
0
    def test_repr_str(self):
        """
        Trying to add a `__str__` without having a `__repr__` raises a
        ValueError.
        """
        with pytest.raises(ValueError) as ei:
            make_class("C", {}, repr=False, str=True)

        assert (
            "__str__ can only be generated if a __repr__ exists.",
        ) == ei.value.args
Example #6
0
    def test_bases(self):
        """
        Parameter bases default to (object,) and subclasses correctly
        """
        class D(object):
            pass

        cls = make_class("C", {})
        assert cls.__mro__[-1] == object

        cls = make_class("C", {}, bases=(D,))
        assert D in cls.__mro__
        assert isinstance(cls(), D)
Example #7
0
    def test_multiple_validators(self):
        """
        If a list is passed as a validator, all of its items are treated as one
        and must pass.
        """
        def v1(_, __, value):
            if value == 23:
                raise TypeError("omg")

        def v2(_, __, value):
            if value == 42:
                raise ValueError("omg")

        C = make_class("C", {"x": attr.ib(validator=[v1, v2])})

        validate(C(1))

        with pytest.raises(TypeError) as e:
            C(23)

        assert "omg" == e.value.args[0]

        with pytest.raises(ValueError) as e:
            C(42)

        assert "omg" == e.value.args[0]
Example #8
0
 def test_success(self):
     """
     If the validator suceeds, nothing gets raised.
     """
     C = make_class("C", {"x": attr(validator=lambda *a: None),
                          "y": attr()})
     validate(C(1, 2))
Example #9
0
    def test_hash(self):
        """
        If `hash` is False, ignore that attribute.
        """
        C = make_class("C", {"a": attr(hash=False), "b": attr()})

        assert hash(C(1, 2)) == hash(C(2, 2))
Example #10
0
def _create_hyp_class(attrs):
    """
    A helper function for Hypothesis to generate attrs classes.
    """
    return make_class(
        "HypClass", dict(zip(gen_attr_names(), attrs))
    )
Example #11
0
    def test_enforces_type(self):
        """
        The `hash` argument to both attrs and attrib must be None, True, or
        False.
        """
        exc_args = ("Invalid value for hash.  Must be True, False, or None.",)

        with pytest.raises(TypeError) as e:
            make_class("C", {}, hash=1),

        assert exc_args == e.value.args

        with pytest.raises(TypeError) as e:
            make_class("C", {"a": attr(hash=1)}),

        assert exc_args == e.value.args
Example #12
0
 def test_empty_metadata_singleton(self, list_of_attrs):
     """
     All empty metadata attributes share the same empty metadata dict.
     """
     C = make_class("C", dict(zip(gen_attr_names(), list_of_attrs)))
     for a in fields(C)[1:]:
         assert a.metadata is fields(C)[0].metadata
Example #13
0
    def test_cmp(self):
        """
        If `cmp` is False, ignore that attribute.
        """
        C = make_class("C", {"a": attr(cmp=False), "b": attr()})

        assert C(1, 2) == C(2, 2)
Example #14
0
    def test_attr_args(self):
        """
        attributes_arguments are passed to attributes
        """
        C = make_class("C", ["x"], repr=False)

        assert repr(C(1)).startswith("<tests.test_make.C object at 0x")
Example #15
0
    def test_repr(self):
        """
        If `repr` is False, ignore that attribute.
        """
        C = make_class("C", {"a": attr(repr=False), "b": attr()})

        assert "C(b=2)" == repr(C(1, 2))
Example #16
0
def simple_class(cmp=False, repr=False, hash=False, slots=False):
    """
    Return a new simple class.
    """
    return make_class(
        "C", ["a", "b"],
        cmp=cmp, repr=repr, hash=hash, init=True, slots=slots
    )
Example #17
0
 def test_frozen(self):
     """
     Converters circumvent immutability.
     """
     C = make_class("C", {
         "x": attr.ib(converter=lambda v: int(v)),
     }, frozen=True)
     C("1")
Example #18
0
    def test_missing_sys_getframe(self, monkeypatch):
        """
        `make_class()` does not fail when `sys._getframe()` is not available.
        """
        monkeypatch.delattr(sys, '_getframe')
        C = make_class("C", ["x"])

        assert 1 == len(C.__attrs_attrs__)
Example #19
0
    def test_hash_attribute(self, slots):
        """
        If `hash` is False on an attribute, ignore that attribute.
        """
        C = make_class("C", {"a": attr(hash=False), "b": attr()},
                       slots=slots, hash=True)

        assert hash(C(1, 2)) == hash(C(2, 2))
Example #20
0
    def test_clean_class(self, slots):
        """
        Attribute definitions do not appear on the class body.
        """
        C = make_class("C", ["x"], slots=slots)

        x = getattr(C, "x", None)

        assert not isinstance(x, _CountingAttr)
Example #21
0
    def test_repr_uninitialized_member(self):
        """
        repr signals unset attributes
        """
        C = make_class("C", {
            "a": attr.ib(init=False),
        })

        assert "C(a=NOTHING)" == repr(C())
Example #22
0
 def test_convert(self):
     """
     Return value of convert is used as the attribute's value.
     """
     C = make_class("C", {"x": attr(convert=lambda v: v + 1),
                          "y": attr()})
     c = C(1, 2)
     assert c.x == 2
     assert c.y == 2
Example #23
0
 def test_validator_others(self):
     """
     Does not interfere when setting non-attrs attributes.
     """
     C = make_class("C", {"a": attr("a", validator=instance_of(int))})
     i = C(1)
     i.b = "foo"
     assert 1 == i.a
     assert "foo" == i.b
Example #24
0
    def test_init(self):
        """
        If `init` is False, ignore that attribute.
        """
        C = make_class("C", {"a": attr(init=False), "b": attr()})
        with pytest.raises(TypeError) as e:
            C(a=1, b=2)

        msg = e.value if PY26 else e.value.args[0]
        assert "__init__() got an unexpected keyword argument 'a'" == msg
Example #25
0
    def test_cmp(self, slots):
        """
        If `cmp` is False, ignore that attribute.
        """
        C = make_class("C", {
            "a": attr.ib(cmp=False),
            "b": attr.ib()
        }, slots=slots)

        assert C(1, 2) == C(2, 2)
Example #26
0
 def test_convert_property(self, val, init):
     """
     Property tests for attributes with convert.
     """
     C = make_class("C", {"y": attr(),
                          "x": attr(init=init, default=val,
                                    convert=lambda v: v + 1),
                          })
     c = C(2)
     assert c.x == val + 1
     assert c.y == 2
Example #27
0
    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
Example #28
0
    def test_not_none_metadata(self, list_of_attrs):
        """
        Non-empty metadata attributes exist as fields after ``@attr.s``.
        """
        C = make_class("C", dict(zip(gen_attr_names(), list_of_attrs)))

        assert len(fields(C)) > 0

        for cls_a, raw_a in zip(fields(C), list_of_attrs):
            assert cls_a.metadata != {}
            assert cls_a.metadata == raw_a.metadata
Example #29
0
    def test_simple(self, ls):
        """
        Passing a list of strings creates attributes with default args.
        """
        C1 = make_class("C1", ls(["a", "b"]))

        @attr.s
        class C2(object):
            a = attr.ib()
            b = attr.ib()

        assert C1.__attrs_attrs__ == C2.__attrs_attrs__
Example #30
0
    def test_dict(self):
        """
        Passing a dict of name: _CountingAttr creates an equivalent class.
        """
        C1 = make_class("C1", {"a": attr(default=42), "b": attr(default=None)})

        @attributes
        class C2(object):
            a = attr(default=42)
            b = attr(default=None)

        assert C1.__attrs_attrs__ == C2.__attrs_attrs__
Example #31
0
    def test_factory_takes_self(self):
        """
        If takes_self on factories is True, self is passed.
        """
        C = make_class(
            "C",
            {
                "x":
                attr.ib(default=Factory((lambda self: self), takes_self=True))
            },
        )

        i = C()

        assert i is i.x
Example #32
0
    def test_hash_attribute(self, slots):
        """
        If `hash` is False on an attribute, ignore that attribute.
        """
        C = make_class(
            "C",
            {
                "a": attr.ib(hash=False),
                "b": attr.ib()
            },
            slots=slots,
            hash=True,
        )

        assert hash(C(1, 2)) == hash(C(2, 2))
Example #33
0
    def test_propagates(self):
        """
        The exception of the validator is handed through.
        """

        def raiser(_, __, value):
            if value == 42:
                raise FloatingPointError

        C = make_class("C", {"x": attr.ib(validator=raiser)})
        i = C(1)
        i.x = 42

        with pytest.raises(FloatingPointError):
            validate(i)
Example #34
0
    def test_init(self, slots, frozen):
        """
        If `init` is False, ignore that attribute.
        """
        C = make_class("C", {
            "a": attr.ib(init=False),
            "b": attr.ib()
        },
                       slots=slots,
                       frozen=frozen)
        with pytest.raises(TypeError) as e:
            C(a=1, b=2)

        assert ("__init__() got an unexpected keyword argument 'a'" ==
                e.value.args[0])
Example #35
0
    def test_dict(self):
        """
        Passing a dict of name: _CountingAttr creates an equivalent class.
        """
        C1 = make_class("C1", {
            "a": attr.ib(default=42),
            "b": attr.ib(default=None),
        })

        @attr.s
        class C2(object):
            a = attr.ib(default=42)
            b = attr.ib(default=None)

        assert C1.__attrs_attrs__ == C2.__attrs_attrs__
Example #36
0
    def test_validator_others(self, slots):
        """
        Does not interfere when setting non-attrs attributes.
        """
        C = make_class("C", {"a": attr.ib("a", validator=instance_of(int))},
                       slots=slots)
        i = C(1)

        assert 1 == i.a

        if not slots:
            i.b = "foo"
            assert "foo" == i.b
        else:
            with pytest.raises(AttributeError):
                i.b = "foo"
Example #37
0
    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
Example #38
0
    def test_convert_before_validate(self):
        """
        Validation happens after conversion.
        """
        def validator(inst, attr, val):
            raise RuntimeError("foo")

        C = make_class(
            "C",
            {
                "x": attr.ib(validator=validator, converter=lambda v: 1 / 0),
                "y": attr.ib(),
            },
        )
        with pytest.raises(ZeroDivisionError):
            C(1, 2)
Example #39
0
    def test_convert_property(self, val, init):
        """
        Property tests for attributes using converter.
        """
        C = make_class(
            "C",
            {
                "y": attr.ib(),
                "x": attr.ib(init=init, default=val,
                             converter=lambda v: v + 1),
            },
        )
        c = C(2)

        assert c.x == val + 1
        assert c.y == 2
Example #40
0
 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 test_validator_slots(self):
        """
        If a validator is passed, call it with the preliminary instance, the
        Attribute, and the argument.
        """
        class VException(Exception):
            pass

        def raiser(*args):
            raise VException(*args)

        C = make_class("C", {"a": attr("a", validator=raiser)}, slots=True)
        with pytest.raises(VException) as e:
            C(42)
        assert (fields(C)[0], 42,) == e.value.args[1:]
        assert isinstance(e.value.args[0], C)
Example #42
0
def simple_classes(draw, slots=None, frozen=None, private_attrs=None):
    """
    A strategy that generates classes with default non-attr attributes.

    For example, this strategy might generate a class such as:

    @attr.s(slots=True, frozen=True)
    class HypClass:
        a = attr.ib(default=1)
        _b = attr.ib(default=None)
        c = attr.ib(default='text')
        _d = attr.ib(default=1.0)
        c = attr.ib(default={'t': 1})

    By default, all combinations of slots and frozen classes will be generated.
    If `slots=True` is passed in, only slots classes will be generated, and
    if `slots=False` is passed in, no slot classes will be generated. The same
    applies to `frozen`.

    By default, some attributes will be private (i.e. prefixed with an
    underscore). If `private_attrs=True` is passed in, all attributes will be
    private, and if `private_attrs=False`, no attributes will be private.
    """
    attrs = draw(list_of_attrs)
    frozen_flag = draw(st.booleans()) if frozen is None else frozen
    slots_flag = draw(st.booleans()) if slots is None else slots

    if private_attrs is None:
        attr_names = maybe_underscore_prefix(gen_attr_names())
    elif private_attrs is True:
        attr_names = ('_' + n for n in gen_attr_names())
    elif private_attrs is False:
        attr_names = gen_attr_names()

    cls_dict = dict(zip(attr_names, attrs))
    post_init_flag = draw(st.booleans())
    if post_init_flag:
        def post_init(self):
            pass
        cls_dict["__attrs_post_init__"] = post_init

    return make_class(
        "HypClass",
        cls_dict,
        slots=slots_flag,
        frozen=frozen_flag,
    )
Example #43
0
    def test_hash_mirrors_eq(self, eq):
        """
        If `hash` is None, the hash generation mirrors `eq`.
        """
        C = make_class("C", {"a": attr.ib()}, eq=eq, frozen=True)

        i = C(1)

        assert i == i
        assert hash(i) == hash(i)

        if eq:
            assert C(1) == C(1)
            assert hash(C(1)) == hash(C(1))
        else:
            assert C(1) != C(1)
            assert hash(C(1)) != hash(C(1))
Example #44
0
    def test_validator(self):
        """
        If a validator is passed, call it with the Attribute and the argument.
        """
        class VException(Exception):
            pass

        def raiser(*args):
            raise VException(args)

        C = make_class("C", {"a": attr("a", validator=raiser)})
        with pytest.raises(VException) as e:
            C(42)
        assert ((
            C.a,
            42,
        ), ) == e.value.args
    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)
Example #46
0
    def test_hash_mirrors_cmp(self, cmp):
        """
        If `hash` is None, the hash generation mirrors `cmp`.
        """
        C = make_class("C", {"a": attr.ib()}, cmp=cmp, frozen=True)

        i = C(1)

        assert i == i
        assert hash(i) == hash(i)

        if cmp:
            assert C(1) == C(1)
            assert hash(C(1)) == hash(C(1))
        else:
            assert C(1) != C(1)
            assert hash(C(1)) != hash(C(1))
Example #47
0
    def test_run_validators(self):
        """
        Setting `_run_validators` to False prevents validators from running.
        """
        _config._run_validators = False
        obj = object()

        def raiser(_, __, ___):
            raise Exception(obj)

        C = make_class("C", {"x": attr(validator=raiser)})
        assert 1 == C(1).x
        _config._run_validators = True

        with pytest.raises(Exception) as e:
            C(1)
        assert (obj,) == e.value.args
Example #48
0
    def test_metadata_present(self, list_of_attrs):
        """
        Assert dictionaries are copied and present.
        """
        C = make_class("C", dict(zip(gen_attr_names(), list_of_attrs)))

        for hyp_attr, class_attr in zip(list_of_attrs, fields(C)):
            if hyp_attr.metadata is None:
                # The default is a singleton empty dict.
                assert class_attr.metadata is not None
                assert len(class_attr.metadata) == 0
            else:
                assert hyp_attr.metadata == class_attr.metadata

                # Once more, just to assert getting items and iteration.
                for k in class_attr.metadata:
                    assert hyp_attr.metadata[k] == class_attr.metadata[k]
                    assert (
                        hyp_attr.metadata.get(k) == class_attr.metadata.get(k))
Example #49
0
def simple_class(cmp=False,
                 repr=False,
                 hash=False,
                 str=False,
                 slots=False,
                 frozen=False):
    """
    Return a new simple class.
    """
    return make_class(
        "C",
        ["a", "b"],
        cmp=cmp,
        repr=repr,
        hash=hash,
        init=True,
        slots=slots,
        str=str,
        frozen=frozen,
    )
Example #50
0
def simple_classes(draw, slots=None, frozen=None):
    """A strategy that generates classes with default non-attr attributes.

    For example, this strategy might generate a class such as:

    @attr.s(slots=True, frozen=True)
    class HypClass:
        a = attr.ib(default=1)
        b = attr.ib(default=None)
        c = attr.ib(default='text')
        d = attr.ib(default=1.0)
        c = attr.ib(default={'t': 1})

    By default, all combinations of slots and frozen classes will be generated.
    If `slots=True` is passed in, only slots classes will be generated, and
    if `slots=False` is passed in, no slot classes will be generated. The same
    applies to `frozen`.
    """
    attrs = draw(list_of_attrs)
    frozen_flag = draw(st.booleans()) if frozen is None else frozen
    slots_flag = draw(st.booleans()) if slots is None else slots

    return make_class('HypClass', dict(zip(_gen_attr_names(), attrs)),
                      slots=slots_flag, frozen=frozen_flag)
Example #51
0
 def test_attr_args(self):
     """
     attributes_arguments are passed to attributes
     """
     C = make_class("C", ["x"], repr=False)
     assert repr(C(1)).startswith("<attr._make.C object at 0x")
Example #52
0
 def test_frozen(self):
     """
     Converters circumvent immutability.
     """
     C = make_class("C", {"x": attr(convert=lambda v: int(v))}, frozen=True)
     C("1")
Example #53
0
 def test_success(self):
     """
     If the validator suceeds, nothing gets raised.
     """
     C = make_class("C", {"x": attr(validator=lambda _, __: None)})
     validate(C(1))
Example #54
0
def _create_hyp_class(attrs):
    """
    A helper function for Hypothesis to generate attrs classes.
    """
    return make_class("HypClass", dict(zip(gen_attr_names(), attrs)))