Review feedback.

This commit is contained in:
Tin Tvrtkovic 2016-05-15 02:00:36 +02:00
parent 17a48c3bc3
commit 88f33a9375
3 changed files with 42 additions and 28 deletions

View File

@ -13,21 +13,21 @@ def asdict(inst, recurse=True, filter=None, dict_factory=dict):
:param inst: Instance of a ``attrs``-decorated class. :param inst: Instance of a ``attrs``-decorated class.
:param recurse: Recurse into classes that are also ``attrs``-decorated. :param bool recurse: Recurse into classes that are also ``attrs``-decorated.
:type recurse: bool
:param filter: A callable whose return code deteremines whether an :param callable filter: A callable whose return code deteremines whether an
attribute or element is included (``True``) or dropped (``False``). Is attribute or element is included (``True``) or dropped (``False``). Is
called with the :class:`attr.Attribute` as the first argument and the called with the :class:`attr.Attribute` as the first argument and the
value as the second argument. value as the second argument.
:type filer: callable
:param dict_factory: A callable to produce dictionaries from. For example, :param callable dict_factory: A callable to produce dictionaries from. For
to produce ordered dictionaries instead of normal Python dictionaries, example, to produce ordered dictionaries instead of normal Python
pass in ``collections.OrderedDict``. dictionaries, pass in ``collections.OrderedDict``.
:type dict_factory: callable
:rtype: :class:`dict` :rtype: :class:`dict`
.. versionadded:: 16.0.0
*dict_factory*
""" """
attrs = fields(inst.__class__) attrs = fields(inst.__class__)
rv = dict_factory() rv = dict_factory()

View File

@ -4,7 +4,8 @@ import string
from hypothesis import strategies as st from hypothesis import strategies as st
from attr import Attribute, ib import attr
from attr import Attribute
from attr._make import NOTHING, make_class from attr._make import NOTHING, make_class
@ -46,18 +47,30 @@ class TestSimpleClass(object):
assert simple_class() is not simple_class() assert simple_class() is not simple_class()
def create_class(attrs): def _gen_attr_names():
"""
Generate names for attributes, 'a'...'z', then 'aa'...'zz'.
702 different attribute names should be enough in practice.
"""
lc = string.ascii_lowercase
for c in lc:
yield c
for outer in lc:
for inner in lc:
yield outer + inner
def _create_hyp_class(attrs):
""" """
A helper function for Hypothesis to generate attrs classes. A helper function for Hypothesis to generate attrs classes.
""" """
# What if we get more than len(string.ascii_lowercase) attributes? return make_class('HypClass', dict(zip(_gen_attr_names(), attrs)))
return make_class('HypClass', dict(zip(string.ascii_lowercase, attrs)))
bare_attrs = st.just(ib(default=None)) bare_attrs = st.just(attr.ib(default=None))
int_attrs = st.integers().map(lambda i: ib(default=i)) int_attrs = st.integers().map(lambda i: attr.ib(default=i))
str_attrs = st.text().map(lambda s: ib(default=s)) str_attrs = st.text().map(lambda s: attr.ib(default=s))
float_attrs = st.floats().map(lambda f: ib(default=f)) float_attrs = st.floats().map(lambda f: attr.ib(default=f))
simple_attrs = st.one_of(bare_attrs, int_attrs, str_attrs, float_attrs) simple_attrs = st.one_of(bare_attrs, int_attrs, str_attrs, float_attrs)
simple_classes = st.lists(simple_attrs).map(create_class) simple_classes = st.lists(simple_attrs).map(_create_hyp_class)

View File

@ -3,6 +3,7 @@ Tests for `attr._funcs`.
""" """
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
from collections import OrderedDict from collections import OrderedDict
import pytest import pytest
@ -14,20 +15,23 @@ from . import simple_classes
from attr._funcs import ( from attr._funcs import (
asdict, asdict,
assoc, assoc,
has,
fields, fields,
has,
) )
from attr._make import ( from attr._make import (
attr, attr,
attributes, attributes,
) )
MAPPING_TYPES = (dict, OrderedDict)
SEQUENCE_TYPES = (list, tuple)
class TestAsDict(object): class TestAsDict(object):
""" """
Tests for `asdict`. Tests for `asdict`.
""" """
@given(st.sampled_from([dict, OrderedDict])) @given(st.sampled_from(MAPPING_TYPES))
def test_shallow(self, C, dict_factory): def test_shallow(self, C, dict_factory):
""" """
Shallow asdict returns correct dict. Shallow asdict returns correct dict.
@ -37,7 +41,7 @@ class TestAsDict(object):
"y": 2, "y": 2,
} == asdict(C(x=1, y=2), False, dict_factory=dict_factory) } == asdict(C(x=1, y=2), False, dict_factory=dict_factory)
@given(st.sampled_from([dict, OrderedDict])) @given(st.sampled_from(MAPPING_TYPES))
def test_recurse(self, C, dict_factory): def test_recurse(self, C, dict_factory):
""" """
Deep asdict returns correct dict. Deep asdict returns correct dict.
@ -50,7 +54,7 @@ class TestAsDict(object):
C(3, 4), C(3, 4),
), dict_factory=dict_factory) ), dict_factory=dict_factory)
@given(st.sampled_from([dict, OrderedDict])) @given(st.sampled_from(MAPPING_TYPES))
def test_filter(self, C, dict_factory): def test_filter(self, C, dict_factory):
""" """
Attributes that are supposed to be skipped are skipped. Attributes that are supposed to be skipped are skipped.
@ -62,10 +66,7 @@ class TestAsDict(object):
C(3, 4), C(3, 4),
), filter=lambda a, v: a.name != "y", dict_factory=dict_factory) ), filter=lambda a, v: a.name != "y", dict_factory=dict_factory)
@pytest.mark.parametrize("container", [ @given(container=st.sampled_from(SEQUENCE_TYPES))
list,
tuple,
])
def test_lists_tuples(self, container, C): def test_lists_tuples(self, container, C):
""" """
If recurse is True, also recurse into lists. If recurse is True, also recurse into lists.
@ -75,7 +76,7 @@ class TestAsDict(object):
"y": [{"x": 2, "y": 3}, {"x": 4, "y": 5}, "a"], "y": [{"x": 2, "y": 3}, {"x": 4, "y": 5}, "a"],
} == asdict(C(1, container([C(2, 3), C(4, 5), "a"]))) } == asdict(C(1, container([C(2, 3), C(4, 5), "a"])))
@given(st.sampled_from([dict, OrderedDict])) @given(st.sampled_from(MAPPING_TYPES))
def test_dicts(self, C, dict_factory): def test_dicts(self, C, dict_factory):
""" """
If recurse is True, also recurse into dicts. If recurse is True, also recurse into dicts.
@ -87,10 +88,10 @@ class TestAsDict(object):
} == res } == res
assert isinstance(res, dict_factory) assert isinstance(res, dict_factory)
@given(simple_classes, st.sampled_from([dict, OrderedDict])) @given(simple_classes, st.sampled_from(MAPPING_TYPES))
def test_roundtrip(self, cls, dict_factory): def test_roundtrip(self, cls, dict_factory):
""" """
Test roundtripping for Hypothesis-generated classes. Test dumping to dicts and back for Hypothesis-generated classes.
""" """
instance = cls() instance = cls()
dict_instance = asdict(instance, dict_factory=dict_factory) dict_instance = asdict(instance, dict_factory=dict_factory)