"""
Extra hypothesis strategies built from those in `hypothesis.strategies`, and
helper functions for merging dictionary type strategies and dictionaries of
strategies.
"""
import logging
import datetime
import io
import hypothesis.strategies as hy_st
__all__ = ["json", "dates", "times", "datetimes", "file_objects", "files",
"merge_dicts_strategy", "merge_dicts_max_size_strategy",
"merge_optional_dict_strategy"]
log = logging.getLogger(__name__)
[docs]def json(value_limit=5):
"""Hypothesis strategy for generating values that can be passed to
`json.dumps` to produce valid JSON data.
:param value_limit: A limit on the number of values in the JSON data -
setting this too high can cause value generation to
time out.
:type value_limit: int
"""
return hy_st.recursive(
hy_st.floats() | hy_st.booleans() | hy_st.text() | hy_st.none(),
lambda children: hy_st.dictionaries(hy_st.text(), children),
max_leaves=value_limit)
[docs]def dates():
"""Hypothesis strategy for generating `datetime.date` values."""
return hy_st.builds(
datetime.date.fromordinal,
hy_st.integers(min_value=1, max_value=datetime.date.max.toordinal()))
[docs]def times():
"""Hypothesis strategy for generating `datetime.time` values."""
return hy_st.builds(
datetime.time,
hour=hy_st.integers(min_value=0, max_value=23),
minute=hy_st.integers(min_value=0, max_value=59),
second=hy_st.integers(min_value=0, max_value=59),
microsecond=hy_st.integers(min_value=0, max_value=999999))
[docs]def datetimes():
"""Hypothesis strategy for generating `datetime.datetime` values."""
return hy_st.builds(datetime.datetime.combine, dates(), times())
[docs]def file_objects():
"""Hypothesis strategy for generating pre-populated `file objects`."""
return hy_st.builds(io.BytesIO, hy_st.binary())
[docs]def files():
"""Hypothesis strategy for generating objects pyswagger can use as file
handles to populate `file` format parameters.
Generated values take the format: `dict('data': <file object>)`"""
return file_objects().map(lambda x: {'data': x})
[docs]def merge_dicts_strategy(dict_strat_1, dict_strat_2):
"""Strategy merging two strategies producting dicts into one."""
return hy_st.builds(lambda x, y: dict((list(x.items()) + list(y.items()))),
dict_strat_1,
dict_strat_2)
[docs]def merge_optional_dict_strategy(required_fields, optional_fields):
"""Combine dicts of strings mapping to required and optional strategies.
:param required_fields: Mapping containing required fields.
:type required_fields: dict(str)
:param optional_fields: Mapping containing optional fields.
:type optional_fields: dict(str)
"""
# Create a strategy for a set of keys from the optional dict strategy, then
# a strategy to build those back into a dictionary.
# Finally, merge the strategy of selected optionals with the required one.
opt_keys = hy_st.sets(hy_st.sampled_from(list(optional_fields.keys())))
selected_optionals = hy_st.builds(
lambda dictionary, keys: {key: dictionary[key] for key in keys},
hy_st.fixed_dictionaries(optional_fields),
opt_keys)
result = merge_dicts_strategy(hy_st.fixed_dictionaries(required_fields),
selected_optionals)
return result
[docs]def merge_dicts_max_size_strategy(dict1, dict2, max_size):
"""Combine dict strategies into one to produce a dict up to a max size.
Assumes both dicts have distinct keys.
:param max_size: Maximum number of keys in dicts generated by the strategy.
:type max_size: int
"""
# This is grim, but combine both dictionaries after creating a copy of the
# second containing a reduced number of keys if that would take us over the
# max size.
result = hy_st.builds(
lambda x, y: dict((list(x.items()) + list(y.items()))[:max_size]),
dict1,
dict2)
return result