import six
from itertools import islice, count
from functools import wraps
registry = {}
registry[None] = []
[docs]class combomethod(object):
def __init__(self, method):
self.method = method
def __get__(self, obj=None, objtype=None):
@wraps(self.method)
def _wrapper(*args, **kwargs):
if obj is not None:
return self.method(obj, *args, **kwargs)
else:
return self.method(objtype.inst, *args, **kwargs)
return _wrapper
[docs]class Arbitrary(six.with_metaclass(ArbitraryMeta)):
[docs] def next_random(self):
"""Get next random value.
You should override this method."""
raise StopIteration
[docs] def gen_serial(self, amount):
"""Generate or return a sequence of serial values (finite or infinite amount).
You should override this method."""
return []
[docs] def could_generate(self, x):
"""Check if x could've been generated by self.
You can override this method, but it's not used now in any way."""
raise NotImplementedError
[docs] def shrink(self, x):
"""Get possible shrinkings of x.
You can assume here that self.could_generate(x) == True.
You have to override this method if you want shrinking to be available."""
return []
@classmethod
[docs] def sample(cls):
try:
args = cls.__init__.args_for_sample['args']
kwargs = cls.__init__.args_for_sample['kwargs']
except AttributeError:
args = []
kwargs = {}
inst = cls(*args, **kwargs)
dct = {
'args': {
'args': args,
'kwargs': kwargs,
},
'random': (inst.next_random() for _ in count()),
'serial': (
(2 ** p2, inst.gen_serial(2 ** p2))
for p2 in count()
)
}
return dct
@staticmethod
[docs] def args_for_sample(*args, **kwargs):
def wrapper(method):
method.args_for_sample = {'args': args, 'kwargs': kwargs}
return method
return wrapper
@staticmethod
[docs] def set_for(type):
def wrapper(arb):
if type in registry:
raise LookupError('Arbitrary class already set for %s' % type)
registry[type] = arb
return arb
return wrapper
@staticmethod
[docs] def get_for(type):
"""Get default Arbitrary for the specified type."""
try:
return registry[type]
except KeyError:
raise LookupError('No Arbitrary class is set for %s' % type)
@staticmethod
[docs] def get_all():
return registry[None]