Move test helpers into an utils module
__init__.py should never contain any code.
This commit is contained in:
parent
395aa07820
commit
b337f5b9d5
|
@ -1,6 +1,7 @@
|
|||
[run]
|
||||
branch = True
|
||||
source = attr
|
||||
source =
|
||||
attr
|
||||
|
||||
[paths]
|
||||
source =
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import keyword
|
||||
import string
|
||||
|
||||
from hypothesis import strategies as st
|
||||
|
||||
import attr
|
||||
from attr import Attribute
|
||||
from attr._make import NOTHING, make_class
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
def simple_attr(name, default=NOTHING, validator=None, repr=True,
|
||||
cmp=True, hash=True, init=True):
|
||||
"""
|
||||
Return an attribute with a name and no other bells and whistles.
|
||||
"""
|
||||
return Attribute(
|
||||
name=name, default=default, validator=validator, repr=repr,
|
||||
cmp=cmp, hash=hash, init=init
|
||||
)
|
||||
|
||||
|
||||
class TestSimpleClass(object):
|
||||
"""
|
||||
Tests for the testing helper function `make_class`.
|
||||
"""
|
||||
def test_returns_class(self):
|
||||
"""
|
||||
Returns a class object.
|
||||
"""
|
||||
assert type is simple_class().__class__
|
||||
|
||||
def returns_distinct_classes(self):
|
||||
"""
|
||||
Each call returns a completely new class.
|
||||
"""
|
||||
assert simple_class() is not simple_class()
|
||||
|
||||
|
||||
def _gen_attr_names():
|
||||
"""
|
||||
Generate names for attributes, 'a'...'z', then 'aa'...'zz'.
|
||||
|
||||
~702 different attribute names should be enough in practice.
|
||||
|
||||
Some short strings (such as 'as') are keywords, so we skip them.
|
||||
"""
|
||||
lc = string.ascii_lowercase
|
||||
for c in lc:
|
||||
yield c
|
||||
for outer in lc:
|
||||
for inner in lc:
|
||||
res = outer + inner
|
||||
if keyword.iskeyword(res):
|
||||
continue
|
||||
yield outer + inner
|
||||
|
||||
|
||||
def _create_hyp_class(attrs):
|
||||
"""
|
||||
A helper function for Hypothesis to generate attrs classes.
|
||||
"""
|
||||
return make_class('HypClass', dict(zip(_gen_attr_names(), attrs)))
|
||||
|
||||
|
||||
def _create_hyp_nested_strategy(simple_class_strategy):
|
||||
"""
|
||||
Create a recursive attrs class.
|
||||
|
||||
Given a strategy for building (simpler) classes, create and return
|
||||
a strategy for building classes that have the simpler class as an
|
||||
attribute.
|
||||
"""
|
||||
# Use a tuple strategy to combine simple attributes and an attr class.
|
||||
def just_class(tup):
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=attr.Factory(tup[1])))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
def list_of_class(tup):
|
||||
default = attr.Factory(lambda: [tup[1]()])
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=default))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
def dict_of_class(tup):
|
||||
default = attr.Factory(lambda: {"cls": tup[1]()})
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=default))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
return st.one_of(st.tuples(st.lists(simple_attrs), simple_class_strategy)
|
||||
.map(just_class),
|
||||
st.tuples(st.lists(simple_attrs), simple_class_strategy)
|
||||
.map(list_of_class))
|
||||
|
||||
bare_attrs = st.just(attr.ib(default=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))
|
||||
dict_attrs = (st.dictionaries(keys=st.text(), values=st.integers())
|
||||
.map(lambda d: attr.ib(default=d)))
|
||||
|
||||
simple_attrs = st.one_of(bare_attrs, int_attrs, str_attrs, float_attrs,
|
||||
dict_attrs)
|
||||
|
||||
simple_classes = st.lists(simple_attrs).map(_create_hyp_class)
|
||||
|
||||
# Ok, so st.recursive works by taking a base strategy (in this case,
|
||||
# simple_classes) and a special function. This function receives a strategy,
|
||||
# and returns another strategy (building on top of the base strategy).
|
||||
nested_classes = st.recursive(simple_classes, _create_hyp_nested_strategy)
|
|
@ -10,7 +10,7 @@ import pytest
|
|||
from hypothesis import given
|
||||
from hypothesis.strategies import booleans
|
||||
|
||||
from . import simple_attr, simple_class
|
||||
from .utils import simple_attr, simple_class
|
||||
from attr._make import (
|
||||
Factory,
|
||||
NOTHING,
|
||||
|
|
|
@ -10,7 +10,7 @@ import pytest
|
|||
|
||||
from hypothesis import given, strategies as st
|
||||
|
||||
from . import simple_classes, nested_classes
|
||||
from .utils import simple_classes, nested_classes
|
||||
|
||||
from attr._funcs import (
|
||||
asdict,
|
||||
|
|
|
@ -5,10 +5,10 @@ Tests for `attr._make`.
|
|||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import pytest
|
||||
|
||||
from hypothesis import given
|
||||
from hypothesis.strategies import booleans, sampled_from
|
||||
|
||||
from . import simple_attr, simple_attrs
|
||||
from attr import _config
|
||||
from attr._compat import PY3
|
||||
from attr._make import (
|
||||
|
@ -23,6 +23,8 @@ from attr._make import (
|
|||
validate,
|
||||
)
|
||||
|
||||
from .utils import simple_attr, simple_attrs
|
||||
|
||||
attrs = simple_attrs.map(lambda c: Attribute.from_counting_attr('name', c))
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ import zope.interface
|
|||
|
||||
from attr.validators import instance_of, provides, optional
|
||||
from attr._compat import TYPE
|
||||
from . import simple_attr
|
||||
|
||||
from .utils import simple_attr
|
||||
|
||||
|
||||
class TestInstanceOf(object):
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
"""
|
||||
Common helper functions for tests.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import keyword
|
||||
import string
|
||||
|
||||
from hypothesis import strategies as st
|
||||
|
||||
import attr
|
||||
|
||||
from attr import Attribute
|
||||
from attr._make import NOTHING, make_class
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
def simple_attr(name, default=NOTHING, validator=None, repr=True,
|
||||
cmp=True, hash=True, init=True):
|
||||
"""
|
||||
Return an attribute with a name and no other bells and whistles.
|
||||
"""
|
||||
return Attribute(
|
||||
name=name, default=default, validator=validator, repr=repr,
|
||||
cmp=cmp, hash=hash, init=init
|
||||
)
|
||||
|
||||
|
||||
class TestSimpleClass(object):
|
||||
"""
|
||||
Tests for the testing helper function `make_class`.
|
||||
"""
|
||||
def test_returns_class(self):
|
||||
"""
|
||||
Returns a class object.
|
||||
"""
|
||||
assert type is simple_class().__class__
|
||||
|
||||
def returns_distinct_classes(self):
|
||||
"""
|
||||
Each call returns a completely new class.
|
||||
"""
|
||||
assert simple_class() is not simple_class()
|
||||
|
||||
|
||||
def _gen_attr_names():
|
||||
"""
|
||||
Generate names for attributes, 'a'...'z', then 'aa'...'zz'.
|
||||
|
||||
~702 different attribute names should be enough in practice.
|
||||
|
||||
Some short strings (such as 'as') are keywords, so we skip them.
|
||||
"""
|
||||
lc = string.ascii_lowercase
|
||||
for c in lc:
|
||||
yield c
|
||||
for outer in lc:
|
||||
for inner in lc:
|
||||
res = outer + inner
|
||||
if keyword.iskeyword(res):
|
||||
continue
|
||||
yield outer + inner
|
||||
|
||||
|
||||
def _create_hyp_class(attrs):
|
||||
"""
|
||||
A helper function for Hypothesis to generate attrs classes.
|
||||
"""
|
||||
return make_class('HypClass', dict(zip(_gen_attr_names(), attrs)))
|
||||
|
||||
|
||||
def _create_hyp_nested_strategy(simple_class_strategy):
|
||||
"""
|
||||
Create a recursive attrs class.
|
||||
|
||||
Given a strategy for building (simpler) classes, create and return
|
||||
a strategy for building classes that have the simpler class as an
|
||||
attribute.
|
||||
"""
|
||||
# Use a tuple strategy to combine simple attributes and an attr class.
|
||||
def just_class(tup):
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=attr.Factory(tup[1])))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
def list_of_class(tup):
|
||||
default = attr.Factory(lambda: [tup[1]()])
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=default))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
def dict_of_class(tup):
|
||||
default = attr.Factory(lambda: {"cls": tup[1]()})
|
||||
combined_attrs = list(tup[0])
|
||||
combined_attrs.append(attr.ib(default=default))
|
||||
return _create_hyp_class(combined_attrs)
|
||||
|
||||
return st.one_of(st.tuples(st.lists(simple_attrs), simple_class_strategy)
|
||||
.map(just_class),
|
||||
st.tuples(st.lists(simple_attrs), simple_class_strategy)
|
||||
.map(list_of_class))
|
||||
|
||||
bare_attrs = st.just(attr.ib(default=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))
|
||||
dict_attrs = (st.dictionaries(keys=st.text(), values=st.integers())
|
||||
.map(lambda d: attr.ib(default=d)))
|
||||
|
||||
simple_attrs = st.one_of(bare_attrs, int_attrs, str_attrs, float_attrs,
|
||||
dict_attrs)
|
||||
|
||||
simple_classes = st.lists(simple_attrs).map(_create_hyp_class)
|
||||
|
||||
# Ok, so st.recursive works by taking a base strategy (in this case,
|
||||
# simple_classes) and a special function. This function receives a strategy,
|
||||
# and returns another strategy (building on top of the base strategy).
|
||||
nested_classes = st.recursive(simple_classes, _create_hyp_nested_strategy)
|
Loading…
Reference in New Issue