Ejemplo n.º 1
0
    def instance_of(s):
        """Constructs a new data structure instance conforming
        to given schema. This function proceeds recursively.
        """
        if isinstance(s, Mapping):
            res = (OrderedDict()
                   if isinstance(s, OrderedDict)
                   else dict())
            items = s.iteritems()
        else:
            res = [None] * len(s)
            items = enumerate(s)

        for key, value in items:
            if is_arbitrary(value):
                value = to_arbitrary(value)
                res[key] = next(value)
            elif isinstance(value, Iterable):
                res[key] = instance_of(value)
            else:
                res[key] = value

        if isinstance(s, tuple):
            res = tuple(res)
        return res
Ejemplo n.º 2
0
 def __init__(self, func, data, tests_count=None):
     """Constructor. Callers should specify the function
     which encodes the testing property, and arbitrary values'
     generator for test data (function arguments).
     """
     self.func = self.__coerce_to_generator_func(func)
     self.data = dict((k, to_arbitrary(v) if is_arbitrary(v) else v)
                        for k, v in data.iteritems())
     if tests_count is not None:
         self.tests_count = tests_count
 def __init__(self, func, data, tests_count=None):
     """Constructor. Callers should specify the function
     which encodes the testing property, and arbitrary values'
     generator for test data (function arguments).
     """
     self.func = self.__coerce_to_generator_func(func)
     self.data = dict((k, to_arbitrary(v) if is_arbitrary(v) else v)
                      for k, v in data.iteritems())
     if tests_count is not None:
         self.tests_count = tests_count
Ejemplo n.º 4
0
def apply(func, *args, **kwargs):
    """Generator that applies a specific function to objects returned
    by given generator(s).

    Any number of generators can be passed as arguments, and they can
    be both positional (``args``) or keyword arguments (``kwargs``).
    In either case, the same invocation style (i.e. positional or keyword)
    will be used when calling the ``func`` with actual values
    obtained from given generators.

    As an example, the following call::

        apply(json.dumps, dict_(items=two(str)))

    will create a generator that yields results of ``json.dumps(d)``,
    where ``d`` is an arbitrary dictionary that maps strings to strings.

    Similarly, using :func:`apply` as shown below::

        apply(itertools.product, list_(of=int), repeat=4)

    gets us a generator that produces results of
    ``itertools.product(l, repeat=4)``, where ``l`` is an arbitrary
    list of ``int``\ s.
    """
    if not func:
        raise ValueError("no function provided")
    if not callable(func):
        raise TypeError("expected a callable")

    func_args = [next(to_arbitrary(arg)) for arg in args]
    func_kwargs = dict((k, next(to_arbitrary(v)))
                       for (k, v) in kwargs.iteritems())

    @arbitrary
    def generator():
        return func(*func_args, **func_kwargs)
    return generator
Ejemplo n.º 5
0
def elements(*args, **kwargs):
    """Generator that returns random elements from given set.

    Elements can be passed either directly as arguments::

        elements(1, 2, 3)

    or as a list::

        elements([1, 2, 3])

    Every element has equal probability of being chosen.

    :param count: Optional number of elements in every returned subset.
                  If omitted, a single element will be yield every time.
                  If provided, it should always be passed as keyword argument,
                  e.g. ``elements(range(10), count=3)``.

                  This can be also a generator - such as :func:`int_` -
                  if there's a need to randomize the subset size, too.

    .. note::

        There is difference between ``elements(foo)``
        and ``elements(foo, count=1)``. The first form returns
        random element from the set ``foo``, while the second returns random
        *1-element subset* of ``foo`` - ``x`` vs ``[x]``, essentially.
    """
    if not args:
        raise ValueError("cannot pick random elements from empty sequence")

    count = kwargs.get('count', None)
    if count is None:
        return random.choice(args)
    if is_arbitrary(count):
        count = next(to_arbitrary(count))

    count = min(count, len(args))
    return random.sample(args, count)
Ejemplo n.º 6
0
def combinator(func):
    """Decorator for arbitrary combinator functions which take
    a collection of arguments as either an actual list/sequence,
    or as positional arguments.

    In other words, it makes it possible to use
    the following two forms of invocation::

        func([1, 2, 3])
        func(1, 2, 3)

    In both cases ``func`` receives 1, 2 and 3 as
    positional arguments (``*args``).
    """
    _2arbitrary = recursive(
        lambda obj: to_arbitrary(obj) if is_arbitrary(obj) else obj)

    @arbitrary
    @functools.wraps(func)
    def wrapped(*args, **kwargs):
        if not args:
            return func(**kwargs)

        new_args = []
        for arg in args:
            arg_collection = (isinstance(arg, Iterable)
                              and not is_arbitrary(arg))
            if arg_collection:
                arg = map(_2arbitrary, arg)
                new_args.extend(arg)
            else:
                arg = _2arbitrary(arg)
                new_args.append(arg)
        return func(*new_args, **kwargs)

    return wrapped