Skip to content

Commit

Permalink
Merge branch 'master' into resolve_type
Browse files Browse the repository at this point in the history
  • Loading branch information
hynek committed Dec 19, 2017
2 parents 7e56d96 + 051da68 commit 10bea3a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 4 deletions.
2 changes: 2 additions & 0 deletions changelog.d/280.change.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
``attr.ib``\ ’s ``metadata`` argument now defaults to a unique empty ``dict`` instance instead of sharing a common empty ``dict`` for all.
The singleton empty ``dict`` is still enforced.
4 changes: 3 additions & 1 deletion src/attr/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def __hash__(self):

def attrib(default=NOTHING, validator=None,
repr=True, cmp=True, hash=None, init=True,
convert=None, metadata={}, type=None):
convert=None, metadata=None, type=None):
"""
Create a new attribute on a class.
Expand Down Expand Up @@ -134,6 +134,8 @@ def attrib(default=NOTHING, validator=None,
raise TypeError(
"Invalid value for hash. Must be True, False, or None."
)
if metadata is None:
metadata = {}
return _CountingAttr(
default=default,
validator=validator,
Expand Down
31 changes: 30 additions & 1 deletion tests/test_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from __future__ import absolute_import, division, print_function

import inspect
import itertools
import sys

from operator import attrgetter
Expand All @@ -26,7 +27,7 @@

from .utils import (
gen_attr_names, list_of_attrs, simple_attr, simple_attrs,
simple_attrs_without_metadata, simple_classes
simple_attrs_with_metadata, simple_attrs_without_metadata, simple_classes
)


Expand Down Expand Up @@ -823,6 +824,34 @@ def test_empty_metadata_singleton(self, list_of_attrs):
for a in fields(C)[1:]:
assert a.metadata is fields(C)[0].metadata

@given(lists(simple_attrs_without_metadata, min_size=2, max_size=5))
def test_empty_countingattr_metadata_independent(self, list_of_attrs):
"""
All empty metadata attributes are independent before ``@attr.s``.
"""
for x, y in itertools.combinations(list_of_attrs, 2):
assert x.metadata is not y.metadata

@given(lists(simple_attrs_with_metadata(), min_size=2, max_size=5))
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

def test_not_none_metadata_force_coverage(self):
"""
Force coverage of metadata is not None case even though other tests
should do so anyways.
"""
attr.ib(metadata={})


class TestClassBuilder(object):
"""
Expand Down
5 changes: 3 additions & 2 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def ordereddict_of_class(tup):
attrs_and_classes.map(ordereddict_of_class))


bare_attrs = st.just(attr.ib(default=None))
bare_attrs = st.builds(attr.ib, default=st.none())
int_attrs = st.integers().map(lambda i: attr.ib(default=i))
str_attrs = st.text().map(lambda s: attr.ib(default=s))
float_attrs = st.floats().map(lambda f: attr.ib(default=f))
Expand All @@ -164,7 +164,8 @@ def simple_attrs_with_metadata(draw):
c_attr = draw(simple_attrs)
keys = st.booleans() | st.binary() | st.integers() | st.text()
vals = st.booleans() | st.binary() | st.integers() | st.text()
metadata = draw(st.dictionaries(keys=keys, values=vals))
metadata = draw(st.dictionaries(
keys=keys, values=vals, min_size=1, max_size=5))

return attr.ib(c_attr._default, c_attr._validator, c_attr.repr,
c_attr.cmp, c_attr.hash, c_attr.init, c_attr.convert,
Expand Down

0 comments on commit 10bea3a

Please sign in to comment.