123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- # coding=utf-8
- #
- # This file is part of Hypothesis, which may be found at
- # https://github.com/HypothesisWorks/hypothesis-python
- #
- # Most of this work is copyright (C) 2013-2018 David R. MacIver
- # (david@drmaciver.com), but it contains contributions by others. See
- # CONTRIBUTING.rst for a full list of people who may hold copyright, and
- # consult the git log if you need to determine who owns an individual
- # contribution.
- #
- # This Source Code Form is subject to the terms of the Mozilla Public License,
- # v. 2.0. If a copy of the MPL was not distributed with this file, You can
- # obtain one at http://mozilla.org/MPL/2.0/.
- #
- # END HEADER
- from __future__ import division, print_function, absolute_import
- import hypothesis.internal.conjecture.utils as cu
- from hypothesis.errors import InvalidArgument
- from hypothesis.internal.compat import OrderedDict, hbytes
- from hypothesis.searchstrategy.strategies import SearchStrategy, \
- MappedSearchStrategy, one_of_strategies
- class TupleStrategy(SearchStrategy):
- """A strategy responsible for fixed length tuples based on heterogenous
- strategies for each of their elements."""
- def __init__(self,
- strategies, tuple_type):
- SearchStrategy.__init__(self)
- strategies = tuple(strategies)
- self.element_strategies = strategies
- def do_validate(self):
- for s in self.element_strategies:
- s.validate()
- def __repr__(self):
- if len(self.element_strategies) == 1:
- tuple_string = '%s,' % (repr(self.element_strategies[0]),)
- else:
- tuple_string = ', '.join(map(repr, self.element_strategies))
- return 'TupleStrategy((%s))' % (
- tuple_string,
- )
- def calc_has_reusable_values(self, recur):
- return all(recur(e) for e in self.element_strategies)
- def newtuple(self, xs):
- """Produce a new tuple of the correct type."""
- return tuple(xs)
- def do_draw(self, data):
- return self.newtuple(
- data.draw(e) for e in self.element_strategies
- )
- def calc_is_empty(self, recur):
- return any(recur(e) for e in self.element_strategies)
- TERMINATOR = hbytes(b'\0')
- class ListStrategy(SearchStrategy):
- """A strategy for lists which takes an intended average length and a
- strategy for each of its element types and generates lists containing any
- of those element types.
- The conditional distribution of the length is geometric, and the
- conditional distribution of each parameter is whatever their
- strategies define.
- """
- def __init__(
- self,
- strategies, average_length=50.0, min_size=0, max_size=float('inf')
- ):
- SearchStrategy.__init__(self)
- assert average_length > 0
- self.average_length = average_length
- strategies = tuple(strategies)
- self.min_size = min_size or 0
- self.max_size = max_size or float('inf')
- self.element_strategy = one_of_strategies(strategies)
- def do_validate(self):
- self.element_strategy.validate()
- if self.is_empty:
- raise InvalidArgument((
- 'Cannot create non-empty lists with elements drawn from '
- 'strategy %r because it has no values.') % (
- self.element_strategy,))
- def calc_is_empty(self, recur):
- if self.min_size == 0:
- return False
- else:
- return recur(self.element_strategy)
- def do_draw(self, data):
- if self.element_strategy.is_empty:
- assert self.min_size == 0
- return []
- elements = cu.many(
- data,
- min_size=self.min_size, max_size=self.max_size,
- average_size=self.average_length
- )
- result = []
- while elements.more():
- result.append(data.draw(self.element_strategy))
- return result
- def __repr__(self):
- return (
- 'ListStrategy(%r, min_size=%r, average_size=%r, max_size=%r)'
- ) % (
- self.element_strategy, self.min_size, self.average_length,
- self.max_size
- )
- class UniqueListStrategy(SearchStrategy):
- def __init__(
- self,
- elements, min_size, max_size, average_size,
- key
- ):
- super(UniqueListStrategy, self).__init__()
- assert min_size <= average_size <= max_size
- self.min_size = min_size
- self.max_size = max_size
- self.average_size = average_size
- self.element_strategy = elements
- self.key = key
- def do_validate(self):
- self.element_strategy.validate()
- if self.is_empty:
- raise InvalidArgument((
- 'Cannot create non-empty lists with elements drawn from '
- 'strategy %r because it has no values.') % (
- self.element_strategy,))
- def calc_is_empty(self, recur):
- if self.min_size == 0:
- return False
- else:
- return recur(self.element_strategy)
- def do_draw(self, data):
- if self.element_strategy.is_empty:
- assert self.min_size == 0
- return []
- elements = cu.many(
- data,
- min_size=self.min_size, max_size=self.max_size,
- average_size=self.average_size
- )
- seen = set()
- result = []
- while elements.more():
- value = data.draw(self.element_strategy)
- k = self.key(value)
- if k in seen:
- elements.reject()
- else:
- seen.add(k)
- result.append(value)
- assert self.max_size >= len(result) >= self.min_size
- return result
- class FixedKeysDictStrategy(MappedSearchStrategy):
- """A strategy which produces dicts with a fixed set of keys, given a
- strategy for each of their equivalent values.
- e.g. {'foo' : some_int_strategy} would
- generate dicts with the single key 'foo' mapping to some integer.
- """
- def __init__(self, strategy_dict):
- self.dict_type = type(strategy_dict)
- if isinstance(strategy_dict, OrderedDict):
- self.keys = tuple(strategy_dict.keys())
- else:
- try:
- self.keys = tuple(sorted(
- strategy_dict.keys(),
- ))
- except TypeError:
- self.keys = tuple(sorted(
- strategy_dict.keys(), key=repr,
- ))
- super(FixedKeysDictStrategy, self).__init__(
- strategy=TupleStrategy(
- (strategy_dict[k] for k in self.keys), tuple
- )
- )
- def calc_is_empty(self, recur):
- return recur(self.mapped_strategy)
- def __repr__(self):
- return 'FixedKeysDictStrategy(%r, %r)' % (
- self.keys, self.mapped_strategy)
- def pack(self, value):
- return self.dict_type(zip(self.keys, value))
|