Feature/better simple classes (#119)
This commit is contained in:
parent
6771640853
commit
0c8211d922
|
@ -132,10 +132,13 @@ class TestAsDict(object):
|
|||
} == res
|
||||
assert isinstance(res, dict_factory)
|
||||
|
||||
@given(simple_classes(), st.sampled_from(MAPPING_TYPES))
|
||||
@given(simple_classes(private_attrs=False), st.sampled_from(MAPPING_TYPES))
|
||||
def test_roundtrip(self, cls, dict_class):
|
||||
"""
|
||||
Test dumping to dicts and back for Hypothesis-generated classes.
|
||||
|
||||
Private attributes don't round-trip (the attribute name is different
|
||||
than the initializer argument).
|
||||
"""
|
||||
instance = cls()
|
||||
dict_instance = asdict(instance, dict_factory=dict_class)
|
||||
|
@ -359,22 +362,27 @@ class TestAssoc(object):
|
|||
assert i1 is not i2
|
||||
assert i1 == i2
|
||||
|
||||
@given(simple_classes(), st.integers())
|
||||
def test_change(self, C, val):
|
||||
@given(simple_classes(), st.data())
|
||||
def test_change(self, C, data):
|
||||
"""
|
||||
Changes work.
|
||||
"""
|
||||
# Take the first attribute, and change it.
|
||||
assume(fields(C)) # Skip classes with no attributes.
|
||||
field_names = [a.name for a in fields(C)]
|
||||
original = C()
|
||||
attribute = fields(C)[0]
|
||||
changed = assoc(original, **{attribute.name: val})
|
||||
assert getattr(changed, attribute.name) == val
|
||||
chosen_names = data.draw(st.sets(st.sampled_from(field_names)))
|
||||
change_dict = {name: data.draw(st.integers())
|
||||
for name in chosen_names}
|
||||
changed = assoc(original, **change_dict)
|
||||
for k, v in change_dict.items():
|
||||
assert getattr(changed, k) == v
|
||||
|
||||
@given(simple_classes())
|
||||
def test_unknown(self, C):
|
||||
"""
|
||||
Wanting to change an unknown attribute raises a ValueError.
|
||||
Wanting to change an unknown attribute raises an
|
||||
AttrsAttributeNotFoundError.
|
||||
"""
|
||||
# No generated class will have a four letter attribute.
|
||||
with pytest.raises(AttrsAttributeNotFoundError) as e:
|
||||
|
|
|
@ -74,6 +74,16 @@ def gen_attr_names():
|
|||
yield outer + inner
|
||||
|
||||
|
||||
def maybe_underscore_prefix(source):
|
||||
"""
|
||||
A generator to sometimes prepend an underscore.
|
||||
"""
|
||||
to_underscore = False
|
||||
for val in source:
|
||||
yield val if not to_underscore else '_' + val
|
||||
to_underscore = not to_underscore
|
||||
|
||||
|
||||
def _create_hyp_class(attrs):
|
||||
"""
|
||||
A helper function for Hypothesis to generate attrs classes.
|
||||
|
@ -164,7 +174,7 @@ list_of_attrs = st.lists(simple_attrs, average_size=3, max_size=9)
|
|||
|
||||
|
||||
@st.composite
|
||||
def simple_classes(draw, slots=None, frozen=None):
|
||||
def simple_classes(draw, slots=None, frozen=None, private_attrs=None):
|
||||
"""
|
||||
A strategy that generates classes with default non-attr attributes.
|
||||
|
||||
|
@ -173,21 +183,32 @@ def simple_classes(draw, slots=None, frozen=None):
|
|||
@attr.s(slots=True, frozen=True)
|
||||
class HypClass:
|
||||
a = attr.ib(default=1)
|
||||
b = attr.ib(default=None)
|
||||
_b = attr.ib(default=None)
|
||||
c = attr.ib(default='text')
|
||||
d = attr.ib(default=1.0)
|
||||
_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
|
||||
|
||||
cls_dict = dict(zip(gen_attr_names(), attrs))
|
||||
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):
|
||||
|
|
Loading…
Reference in New Issue