def _create_hyp_class(attrs_and_strategy):
"""
A helper function for Hypothesis to generate attrs classes.
The result is a tuple: an attrs class, and a tuple of values to
instantiate it.
"""
def key(t):
return t[0].default is not NOTHING
attrs_and_strat = sorted(attrs_and_strategy, key=key)
attrs = [a[0] for a in attrs_and_strat]
for i, a in enumerate(attrs):
a.counter = i
vals = tuple((a[1]) for a in attrs_and_strat)
return st.tuples(
st.just(make_class('HypClass',
OrderedDict(zip(gen_attr_names(), attrs)))),
st.tuples(*vals))
python类tuples()的实例源码
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 as an attribute:
* just the simpler class
* a list of simpler classes
* a dict mapping the string "cls" to a simpler class.
"""
# A strategy producing tuples of the form ([list of attributes], <given
# class strategy>).
attrs_and_classes = st.tuples(lists_of_attrs(defaults=True),
simple_class_strategy)
return (attrs_and_classes.flatmap(just_class) |
attrs_and_classes.flatmap(list_of_class) |
attrs_and_classes.flatmap(dict_of_class))
def pattern_to_statements(pattern):
if isinstance(pattern, template):
return lists(just(pattern), min_size=1, max_size=1)
rule, value = pattern
if rule == 'sequence':
return tuples(*map(pattern_to_statements, value)).map(unpack_list).map(list)
elif rule == 'alternates':
return one_of(*map(pattern_to_statements, value))
elif rule == 'zeroOrMore':
return lists(pattern_to_statements(value)).map(unpack_list).map(list)
elif rule == 'oneOrMore':
return lists(pattern_to_statements(value), min_size=1).map(unpack_list).map(list)
elif rule == 'optional':
return lists(pattern_to_statements(value), min_size=0, max_size=1).map(unpack_list).map(list)
else:
raise Exception("impossible!", rule)
# this replicates the current scorm pattern, a realistic example of medium
# complexity. Note it has repeated elements, just not in ambiguous ways.
def random_reference(draw, prefix = random_prefix()):
number = st.integers(min_value = 0)
return draw(st.tuples(prefix, number))
def add_bools(list_of_lists):
"""
Given recursive list that can contain other lists, return tuple of that plus
a booleans strategy for each list.
"""
l = []
def count(recursive):
l.append(1)
for child in recursive:
if isinstance(child, list):
count(child)
count(list_of_lists)
return st.tuples(st.just(list_of_lists), st.tuples(*[st.sampled_from([True, False]) for i in l]))
def remove_strategy(self):
def get_address(service_name):
return st.tuples(st.just(service_name), st.sampled_from(
self.fake.services[service_name]))
return st.tuples(st.just("remove"), (
st.sampled_from(list(self.fake.services.keys())).flatmap(get_address)))
def steps(self):
result = add_strategy | replace_strategy
# Replace or add to a known service cluster:
if self.fake.services:
result |= st.tuples(st.just("replace"),
st.tuples(st.sampled_from(list(self.fake.services.keys())),
st.lists(nice_strings)))
result |= st.tuples(st.just("add"),
st.tuples(st.sampled_from(list(self.fake.services.keys())),
nice_strings))
# Remove a known address from known cluster:
if not self.fake.is_empty():
result |= self.remove_strategy()
return result
def lists_of_primitives(draw):
"""Generate a strategy that yields tuples of list of primitives and types.
For example, a sample value might be ([1,2], List[int]).
"""
prim_strat, t = draw(primitive_strategies)
list_t = draw(list_types.map(lambda list_t: list_t[t]) | list_types)
return draw(st.lists(prim_strat)), list_t
def create_dict_and_type(tuple_of_strats):
"""Map two primitive strategies into a strategy for dict and type."""
(prim_strat_1, type_1), (prim_strat_2, type_2) = tuple_of_strats
return st.tuples(st.dictionaries(prim_strat_1, prim_strat_2),
create_generic_dict_type(type_1, type_2))
def simple_classes(defaults=None):
"""
Return a strategy that yields tuples of simple classes and values to
instantiate them.
"""
return lists_of_attrs(defaults).flatmap(_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).