├── tests ├── __main__.py ├── test_sample.py ├── __init__.py ├── test_usage.py ├── test_strings.py ├── test_basics.py ├── test_values.py ├── test_generator.py └── test_types.py ├── .gitignore ├── paycheck ├── __init__.py ├── checker.py └── generator.py ├── setup.py └── README.textile /tests/__main__.py: -------------------------------------------------------------------------------- 1 | import tests 2 | tests.run_tests() 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .pydevproject 3 | *.pyc 4 | MANIFEST 5 | build 6 | dist 7 | target 8 | -------------------------------------------------------------------------------- /paycheck/__init__.py: -------------------------------------------------------------------------------- 1 | from paycheck.checker import with_checker 2 | from paycheck.generator import irange, frange, positive_float, non_negative_float, unit_interval_float 3 | -------------------------------------------------------------------------------- /tests/test_sample.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import with_checker 3 | from paycheck.generator import irange 4 | 5 | class TestSample(unittest.TestCase): 6 | 7 | @with_checker(str, str) 8 | def test_string_concatination(self, a, b): 9 | self.assertTrue((a+b).endswith(b)) 10 | 11 | tests = [TestSample] 12 | 13 | if __name__ == '__main__': 14 | unittest.main() 15 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from tests import test_basics, test_generator, test_sample, test_strings, test_types, test_usage, test_values 4 | modules = [ 5 | test_basics, 6 | test_generator, 7 | test_sample, 8 | test_strings, 9 | test_types, 10 | test_usage, 11 | test_values 12 | ] 13 | 14 | def run_tests(): 15 | tests = [] 16 | for module in modules: 17 | for test_case in module.tests: 18 | tests.append(unittest.defaultTestLoader.loadTestsFromTestCase(test_case)) 19 | unittest.TextTestRunner(verbosity=2).run(unittest.TestSuite(tests)) 20 | 21 | if __name__ == "__main__": 22 | run_tests() 23 | -------------------------------------------------------------------------------- /tests/test_usage.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import with_checker 3 | 4 | class TestUsage(unittest.TestCase): 5 | 6 | @with_checker() 7 | def test_defaults(self, i=int, f=float): 8 | self.assertTrue(isinstance(i, int)) 9 | self.assertTrue(isinstance(f, float)) 10 | 11 | @with_checker(int) 12 | def test_mixed(self, i, f=float): 13 | self.assertTrue(isinstance(i, int)) 14 | self.assertTrue(isinstance(f, float)) 15 | 16 | @with_checker 17 | def test_without_parentheses(self, i=int, f=float): 18 | self.assertTrue(isinstance(i, int)) 19 | self.assertTrue(isinstance(f, float)) 20 | 21 | tests = [TestUsage] 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.cmd import Command 2 | from distutils.core import setup 3 | 4 | import sys 5 | if sys.version_info >= (3, 0): 6 | try: 7 | from distutils.command.build_py import build_py_2to3 as build_py 8 | except ImportError: 9 | raise ImportError("build_py_2to3 not found in distutils - it is required for Python 3.x") 10 | else: 11 | from distutils.command.build_py import build_py 12 | 13 | class test(Command): 14 | user_options = [] 15 | def initialize_options(self): 16 | pass 17 | def finalize_options(self): 18 | pass 19 | def run(self): 20 | import tests 21 | tests.run_tests() 22 | 23 | setup( 24 | name = 'paycheck', 25 | version ='0.4.6', 26 | description ='A Python QuickCheck implementation', 27 | author ='Mark Chadwick', 28 | author_email ='mark.chadwick@gmail.com', 29 | url='http://github.com/markchadwick/paycheck/tree/master', 30 | packages = ['paycheck'], 31 | cmdclass = {"build_py": build_py, "test" : test} 32 | ) 33 | -------------------------------------------------------------------------------- /tests/test_strings.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import with_checker 3 | 4 | class TestStrings(unittest.TestCase): 5 | """ 6 | More-or-less a direct port of the string testing example from the ScalaCheck 7 | doc at: http://code.google.com/p/scalacheck/ 8 | """ 9 | 10 | @with_checker(str, str) 11 | def test_starts_with(self, a, b): 12 | self.assertTrue((a+b).startswith(a)) 13 | 14 | @with_checker(str, str) 15 | def test_ends_with(self, a, b): 16 | self.assertTrue((a+b).endswith(b)) 17 | 18 | @with_checker(str, str) 19 | def test_concat(self, a, b): 20 | self.assertTrue(len(a+b) >= len(a)) 21 | self.assertTrue(len(a+b) >= len(b)) 22 | 23 | @with_checker(str, str) 24 | def test_substring2(self, a, b): 25 | self.assertEquals( (a+b)[len(a):], b ) 26 | 27 | @with_checker(str, str, str) 28 | def test_substring3(self, a, b, c): 29 | self.assertEquals((a+b+c)[len(a):len(a)+len(b)], b) 30 | 31 | tests = [TestStrings] 32 | 33 | if __name__ == '__main__': 34 | unittest.main() 35 | -------------------------------------------------------------------------------- /tests/test_basics.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import with_checker 3 | import sys 4 | 5 | class Dummy: 6 | pass 7 | 8 | class TestBasics(unittest.TestCase): 9 | def test_calls_method(self): 10 | o = Dummy() 11 | @with_checker(number_of_calls=10) 12 | def call_me(): 13 | o.times_called += 1 14 | o.times_called = 0 15 | call_me() 16 | self.assertEqual(10,o.times_called) 17 | 18 | def test_calls_method_without_parentheses(self): 19 | o = Dummy() 20 | @with_checker 21 | def call_me(): 22 | o.times_called += 1 23 | o.times_called = 0 24 | call_me() 25 | self.assert_(o.times_called > 0) 26 | 27 | def test_throws_correct_exception_upon_failure(self): 28 | class MyException(Exception): 29 | pass 30 | e = MyException("FAIL") 31 | @with_checker(number_of_calls=1) 32 | def call_me(): 33 | raise e 34 | try: 35 | call_me() 36 | self.fail("Exception was not thrown!") 37 | except MyException: 38 | pass 39 | 40 | tests = [TestBasics] 41 | 42 | if __name__ == '__main__': 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /tests/test_values.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import * 3 | from paycheck import generator 4 | 5 | class TestValues(unittest.TestCase): 6 | 7 | @with_checker(irange(0,10)) 8 | def test_irange_range(self,i): 9 | self.assertTrue(i >= 0) 10 | self.assertTrue(i <= 10) 11 | 12 | @with_checker(irange(0,10,3)) 13 | def test_irange_step(self,i): 14 | self.assertEqual(0,i%3) 15 | 16 | @with_checker(irange(-17,86,9)) 17 | def test_irange_exotic(self,i): 18 | self.assertTrue(i >= -17) 19 | self.assertTrue(i <= 86) 20 | self.assertEqual(0,(i+17)%9) 21 | 22 | @with_checker(irange(0,0)) 23 | def test_irange_tiny(self,i): 24 | self.assertEqual(0,i) 25 | 26 | @with_checker(frange(0,10)) 27 | def test_frange(self,f): 28 | self.assertTrue(f >= 0) 29 | self.assertTrue(f < 10) 30 | 31 | @with_checker(unit_interval_float) 32 | def test_unit_interval_float(self,f): 33 | self.assertTrue(f >= 0) 34 | self.assertTrue(f <= 1) 35 | 36 | @with_checker(non_negative_float) 37 | def test_non_negative_floats(self,f): 38 | self.assertTrue(f >= 0) 39 | 40 | @with_checker(non_negative_float(1e3,1e5)) 41 | def test_frange(self,f): 42 | self.assertTrue(f >= 1e3) 43 | self.assertTrue(f < 1e5) 44 | 45 | @with_checker(positive_float) 46 | def test_positive_floats(self,f): 47 | self.assertTrue(f >= 0) 48 | 49 | tests = [TestValues] 50 | 51 | if __name__ == '__main__': 52 | unittest.main() 53 | -------------------------------------------------------------------------------- /paycheck/checker.py: -------------------------------------------------------------------------------- 1 | import paycheck 2 | from paycheck.generator import PayCheckGenerator 3 | 4 | from functools import partial 5 | from itertools import izip, izip_longest, islice, repeat 6 | import sys 7 | from types import FunctionType 8 | 9 | def with_checker(*args, **keywords): 10 | if len(args) == 1 and isinstance(args[0],FunctionType): 11 | return Checker()(args[0]) 12 | else: 13 | return Checker(*args, **keywords) 14 | 15 | class Checker(object): 16 | 17 | def __init__(self, *args, **keywords): 18 | self._number_of_calls = keywords.pop('number_of_calls', 100) 19 | self._verbose = keywords.pop('verbose', False) 20 | self._argument_generators = [PayCheckGenerator.get(t) for t in args] 21 | self._keyword_generators = [izip(repeat(name),PayCheckGenerator.get(t)) for (name,t) in keywords.iteritems()] 22 | 23 | def __call__(self, test_func): 24 | if test_func.func_defaults: 25 | self._argument_generators += [PayCheckGenerator.get(t) for t in test_func.func_defaults] 26 | if len(self._argument_generators) + len(self._keyword_generators) > 0: 27 | argument_generators = izip(*self._argument_generators) 28 | keyword_generators = izip(*self._keyword_generators) 29 | generator = islice(izip_longest(argument_generators,keyword_generators,fillvalue=()),self._number_of_calls) 30 | else: 31 | generator = repeat(((),()),self._number_of_calls) 32 | def wrapper(*pre_args): 33 | i = 0 34 | for (args,keywords) in generator: 35 | try: 36 | if self._verbose: 37 | sys.stderr.write("%d: %r\n" % (i, args)) 38 | test_func(*(pre_args+args), **dict(keywords)) 39 | except Exception, e: 40 | if sys.version_info[0] < 3: 41 | raise e.__class__("Failed for input %s with message '%s'" % (args+keywords,e)), None, sys.exc_traceback 42 | else: 43 | raise e.__class__("Failed for input {}".format(args)).with_traceback(e.__traceback__) 44 | i += 1 45 | 46 | wrapper.__doc__ = test_func.__doc__ 47 | wrapper.__name__ = test_func.__name__ 48 | 49 | return wrapper 50 | 51 | __all__ = [ 52 | 'with_checker', 53 | 'Checker', 54 | ] 55 | -------------------------------------------------------------------------------- /tests/test_generator.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck.generator import * 3 | import sys 4 | 5 | class TestGenerator(unittest.TestCase): 6 | def test_get_int(self): 7 | self.assert_(isinstance( 8 | PayCheckGenerator.get(int), 9 | IntGenerator 10 | )) 11 | 12 | def test_get_string(self): 13 | self.assert_(isinstance( 14 | PayCheckGenerator.get(str), 15 | StringGenerator 16 | )) 17 | 18 | if sys.version_info[0] < 3: 19 | def test_get_unicode(self): 20 | self.assert_(isinstance( 21 | PayCheckGenerator.get(unicode), 22 | UnicodeGenerator 23 | )) 24 | 25 | def test_get_boolean(self): 26 | self.assert_(isinstance( 27 | PayCheckGenerator.get(bool), 28 | BooleanGenerator 29 | )) 30 | 31 | def test_get_float(self): 32 | self.assert_(isinstance( 33 | PayCheckGenerator.get(float), 34 | FloatGenerator 35 | )) 36 | 37 | def test_get_unknown_type_throws_exception(self): 38 | getter = lambda: PayCheckGenerator.get(TestGenerator) 39 | self.assertRaises(UnknownTypeException, getter) 40 | 41 | def test_bad_object_throws_exception(self): 42 | getter = lambda: PayCheckGenerator.get("what?") 43 | self.assertRaises(UnknownTypeException, getter) 44 | 45 | def test_get_list_of_type(self): 46 | generator = PayCheckGenerator.get([int]) 47 | self.assertTrue(isinstance(generator, ListGenerator)) 48 | self.assertTrue(isinstance(generator.inner, IntGenerator)) 49 | 50 | def test_get_nested_list_of_type(self): 51 | generator = PayCheckGenerator.get([[int]]) 52 | self.assertTrue(isinstance(generator, ListGenerator)) 53 | self.assertTrue(isinstance(generator.inner, ListGenerator)) 54 | self.assertTrue(isinstance(generator.inner.inner, IntGenerator)) 55 | 56 | def test_empty_list(self): 57 | getter = lambda: PayCheckGenerator.get([]) 58 | self.assertRaises(IncompleteTypeException, getter) 59 | 60 | def test_empty_dict(self): 61 | getter = lambda: PayCheckGenerator.get({}) 62 | self.assertRaises(IncompleteTypeException, getter) 63 | 64 | def test_dict_of_str_int(self): 65 | generator = PayCheckGenerator.get({str:int}) 66 | self.assertTrue(isinstance(generator, DictGenerator)) 67 | self.assertTrue(isinstance(generator.inner, TupleGenerator)) 68 | print(generator.inner.generators[0].__class__) 69 | self.assertTrue(isinstance(generator.inner.generators[0], StringGenerator)) 70 | self.assertTrue(isinstance(generator.inner.generators[1], IntGenerator)) 71 | 72 | tests = [TestGenerator] 73 | 74 | if __name__ == '__main__': 75 | unittest.main() 76 | -------------------------------------------------------------------------------- /tests/test_types.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from paycheck import with_checker, irange, frange 3 | import sys 4 | 5 | class TestTypes(unittest.TestCase): 6 | 7 | @with_checker(str) 8 | def test_string(self, s): 9 | self.assertTrue(isinstance(s, str)) 10 | 11 | @with_checker(int) 12 | def test_int(self, i): 13 | self.assertTrue(isinstance(i, int)) 14 | 15 | @with_checker(irange(1,10)) 16 | def test_irange(self, i): 17 | self.assertTrue(isinstance(i, int)) 18 | 19 | @with_checker(float) 20 | def test_float(self, f): 21 | self.assertTrue(isinstance(f, float)) 22 | 23 | @with_checker(frange(1,10)) 24 | def test_frange(self, f): 25 | self.assertTrue(isinstance(f, float)) 26 | 27 | @with_checker(complex) 28 | def test_complex(self, c): 29 | self.assertTrue(isinstance(c, complex)) 30 | 31 | if sys.version_info[0] < 3: 32 | @with_checker(unicode) 33 | def test_unicode(self, u): 34 | self.assertTrue(isinstance(u, unicode) or 35 | isinstance(u, str)) 36 | 37 | @with_checker(bool) 38 | def test_boolean(self, b): 39 | self.assertEquals(b, b == True) 40 | 41 | @with_checker([int]) 42 | def test_get_list(self, list_of_ints): 43 | self.assertTrue(isinstance(list_of_ints, list)) 44 | for i in list_of_ints: 45 | self.assertTrue(isinstance(i, int)) 46 | 47 | @with_checker(set([str])) 48 | def test_get_list(self, set_of_strs): 49 | self.assertTrue(isinstance(set_of_strs, set)) 50 | for s in set_of_strs: 51 | self.assertTrue(isinstance(s, str)) 52 | 53 | @with_checker({str: int}) 54 | def test_get_dict(self, dict_of_str_int): 55 | self.assertTrue(isinstance(dict_of_str_int, dict)) 56 | for key, value in dict_of_str_int.items(): 57 | self.assertTrue(isinstance(key, str)) 58 | self.assertTrue(isinstance(value, int)) 59 | 60 | @with_checker(str, [[bool]]) 61 | def test_nested_types(self, s, list_of_lists_of_bools): 62 | self.assertTrue(isinstance(s, str)) 63 | self.assertTrue(isinstance(list_of_lists_of_bools, list)) 64 | 65 | for list_of_bools in list_of_lists_of_bools: 66 | self.assertTrue(isinstance(list_of_bools, list)) 67 | for b in list_of_bools: 68 | self.assertTrue(isinstance(b, bool)) 69 | 70 | @with_checker(int, {str: int}) 71 | def test_dict_of_str_key_int_values(self, i, dict_of_str_int): 72 | self.assertTrue(isinstance(i, int)) 73 | self.assertTrue(isinstance(dict_of_str_int, dict)) 74 | 75 | for key, value in dict_of_str_int.items(): 76 | self.assertTrue(isinstance(key, str)) 77 | self.assertTrue(isinstance(value, int)) 78 | 79 | @with_checker([{str: int}]) 80 | def test_list_of_dict_of_int_string(self, list_of_dict_of_int_string): 81 | self.assertTrue(isinstance(list_of_dict_of_int_string, list)) 82 | 83 | for dict_of_int_string in list_of_dict_of_int_string: 84 | self.assertTrue(isinstance(dict_of_int_string, dict)) 85 | 86 | for key, value in dict_of_int_string.items(): 87 | self.assertTrue(isinstance(key, str)) 88 | self.assertTrue(isinstance(value, int)) 89 | 90 | tests = [TestTypes] 91 | 92 | if __name__ == '__main__': 93 | unittest.main() 94 | -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h2. Hey! PayCheck! 2 | 3 | PayCheck is a half-baked implementation of 4 | "ScalaCheck":http://code.google.com/p/scalacheck/, which itself is an 5 | implementation of "QuickCheck":http://www.cs.chalmers.se/~rjmh/QuickCheck/ for 6 | Haskell. PayCheck is useful for defining a specification of what a function 7 | should do, rather than testing its results for a given input. 8 | 9 | Thanks to gcross for some of the "more recent changes":http://github.com/gcross/paycheck/tree/master 10 | 11 | h3. Installing PayCheck 12 | 13 |
14 |
15 | sudo easy_install paycheck
16 |
17 |
18 |
19 | That's it. Get going.
20 |
21 | h3. A Quick Example
22 |
23 | Let's steal an example right from ScalaCheck. Here are the string functions
24 | ported to PayCheck. See what's going on? We're defining the types of the
25 | parameters in with_checker, then values of that type are getting passed to the
26 | function.
27 |
28 |
29 |
30 | import unittest
31 | from paycheck import with_checker
32 |
33 | class TestStrings(unittest.TestCase):
34 | """
35 | More-or-less a direct port of the string testing example from the ScalaCheck
36 | doc at: http://code.google.com/p/scalacheck/
37 | """
38 |
39 | @with_checker(str, str)
40 | def test_starts_with(self, a, b):
41 | self.assertTrue((a+b).startswith(a))
42 |
43 | @with_checker(str, str)
44 | def test_ends_with(self, a, b):
45 | self.assertTrue((a+b).endswith(b))
46 |
47 | # Is this really always true?
48 | @with_checker(str, str)
49 | def test_concat(self, a, b):
50 | self.assertTrue(len(a+b) > len(a))
51 | self.assertTrue(len(a+b) > len(b))
52 |
53 | @with_checker(str, str)
54 | def test_substring2(self, a, b):
55 | self.assertEquals( (a+b)[len(a):], b )
56 |
57 | @with_checker(str, str, str)
58 | def test_substring3(self, a, b, c):
59 | self.assertEquals((a+b+c)[len(a):len(a)+len(b)], b)
60 |
61 | if __name__ == '__main__':
62 | unittest.main()
63 |
64 |
65 |
66 | Then give the ol' test a run. You'll likely see a problem:
67 |
68 |
69 |
70 | $ python test_strings.py
71 | F....
72 | ======================================================================
73 | FAIL: test_concat (__main__.TestStrings)
74 | ----------------------------------------------------------------------
75 | Traceback (most recent call last):
76 | File "paycheck/checker.py", line 11, in wrapper
77 | test_func(self, *v)
78 | File "test_strings.py", line 20, in test_concat
79 | self.assertTrue(len(a+b) > len(a))
80 | AssertionError: Failed for input ('UGzo2LP<(9Gl_*o*GH$H<+{wPiNk?', '')
81 |
82 | ----------------------------------------------------------------------
83 | Ran 5 tests in 0.051s
84 |
85 | FAILED (failures=1)
86 |
87 |
88 |
89 | As predicted, test_concat has bombed; note that PayCheck is nice
90 | enough to tell you which inputs caused the problem. In this case, we
91 | see that propety test_concat fails for the empty string, which is caused
92 | by the fact that we used ">" instead of ">=".
93 |
94 | h3. Nested and More Complex Types
95 |
96 | Container and nested types are specified to PayCheck "by analogy".
97 | That is, unlike scalar types, which are specified by giving the type
98 | that you want, container types are specified by creating a non-empty
99 | container of the type you want which contains a specification of the
100 | type that you want generated containers to contain; note that the
101 | contained element is itself allowed to be a container, allowing for
102 | arbitrarily nested types. PayCheck will infer from your containers
103 | the type of container and contained elements that you want to
104 | generate. This includes dictionaries: it will look at the first
105 | key/value mapping that it sees and infer from it both the key type and
106 | the value type. Containers will be generated with between 0 and
107 | paycheck.generator.LIST_LEN elements.
108 |
109 | The following examples illustrate how this works:
110 |
111 |
112 |
113 | import unittest
114 | from paycheck import with_checker
115 |
116 | class TestTypes(unittest.TestCase):
117 |
118 | @with_checker(int)
119 | def test_int(self, i):
120 | self.assertTrue(isinstance(i, int))
121 |
122 | @with_checker([int])
123 | def test_get_list(self, list_of_ints):
124 | self.assertTrue(isinstance(list_of_ints, list))
125 | for i in list_of_ints:
126 | self.assertTrue(isinstance(i, int))
127 |
128 | @with_checker([{str: int}])
129 | def test_list_of_dict_of_int_string(self, list_of_dict_of_int_string):
130 | self.assertTrue(isinstance(list_of_dict_of_int_string, list))
131 |
132 | for dict_of_int_string in list_of_dict_of_int_string:
133 | self.assertTrue(isinstance(dict_of_int_string, dict))
134 |
135 | for key, value in dict_of_int_string.items():
136 | self.assertTrue(isinstance(key, str))
137 | self.assertTrue(isinstance(value, int))
138 |
139 | if __name__ == '__main__':
140 | unittest.main()
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/paycheck/generator.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import string
3 | import random
4 | from itertools import izip, islice
5 | from math import log, exp, pi
6 | import cmath
7 |
8 | # ------------------------------------------------------------------------------
9 | # Constants
10 | # ------------------------------------------------------------------------------
11 |
12 | MIN_INT = -sys.maxint - 1
13 | MAX_INT = sys.maxint
14 |
15 | MAX_UNI = sys.maxunicode
16 |
17 | LIST_LEN = 30
18 |
19 | # ------------------------------------------------------------------------------
20 | # Exceptions
21 | # ------------------------------------------------------------------------------
22 |
23 | class PayCheckException(Exception):
24 | pass
25 |
26 | class UnknownTypeException(PayCheckException):
27 | def __init__(self, t_def):
28 | self.t_def = t_def
29 |
30 | def __str__(self):
31 | return "PayCheck doesn't know about type: " + str(self.t_def)
32 |
33 | class IncompleteTypeException(PayCheckException):
34 | def __init__(self, t_def):
35 | self.t_def = t_def
36 |
37 | def __str__(self):
38 | return "The type specification '" + str(self.t_def) + " is incomplete."
39 |
40 | # ------------------------------------------------------------------------------
41 | # Base Generator
42 | # ------------------------------------------------------------------------------
43 |
44 | class PayCheckGenerator(object):
45 | def __iter__(self):
46 | return self
47 |
48 | def next(self):
49 | return self.__next__()
50 |
51 | @classmethod
52 | def get(cls, t_def):
53 | try:
54 | if isinstance(t_def, PayCheckGenerator):
55 | return t_def
56 | elif isinstance(t_def, type):
57 | if issubclass(t_def, PayCheckGenerator):
58 | return t_def()
59 | else:
60 | return scalar_generators[t_def]()
61 | else:
62 | return container_generators[type(t_def)](t_def)
63 | except KeyError:
64 | raise UnknownTypeException(t_def)
65 |
66 | # ------------------------------------------------------------------------------
67 | # Basic Type Generators
68 | # ------------------------------------------------------------------------------
69 |
70 | class StringGenerator(PayCheckGenerator):
71 | def __next__(self):
72 | length = random.randint(0, LIST_LEN)
73 | return ''.join([chr(random.randint(ord('!'), ord('~'))) for x in xrange(length)])
74 |
75 | if sys.version_info[0] < 3:
76 | class UnicodeGenerator(PayCheckGenerator):
77 | def __next__(self):
78 | length = random.randint(0, LIST_LEN)
79 | return ''.join([unicode(random.randint(0, MAX_UNI)) for x in xrange(length)])
80 |
81 | class IntGenerator(PayCheckGenerator):
82 | def __init__(self, min=MIN_INT, max=MAX_INT, step=1):
83 | PayCheckGenerator.__init__(self)
84 | self._min = min
85 | self._boundary = (max-min)//step
86 | self._step = step
87 |
88 | def __next__(self):
89 | return int(random.randint(0,self._boundary)*self._step+self._min)
90 |
91 | def irange(min,max,step=1):
92 | return IntGenerator(min,max,step)
93 |
94 | class BooleanGenerator(PayCheckGenerator):
95 | def __next__(self):
96 | return random.randint(0, 1) == 1
97 |
98 | class UniformFloatGenerator(PayCheckGenerator):
99 | def __init__(self,min=-1e7,max=1e7):
100 | self._min = min
101 | self._length = max-min
102 |
103 | def __next__(self):
104 | return random.random()*self._length+self._min
105 |
106 | frange = UniformFloatGenerator
107 |
108 | unit_interval_float = frange(0,1)
109 |
110 | class NonNegativeFloatGenerator(PayCheckGenerator):
111 | def __init__(self,minimum_magnitude=1e-7,maximum_magnitude=1e+7):
112 | minimum_magnitude = log(minimum_magnitude)
113 | maximum_magnitude = log(maximum_magnitude)
114 | self._scale_range = maximum_magnitude-minimum_magnitude
115 | self._minimum_magnitude = minimum_magnitude
116 | def __next__(self):
117 | return exp(random.random() * self._scale_range + self._minimum_magnitude)
118 | non_negative_float = NonNegativeFloatGenerator
119 |
120 | class PositiveFloatGenerator(NonNegativeFloatGenerator):
121 | def __next__(self):
122 | value = 0
123 | while value == 0:
124 | value = NonNegativeFloatGenerator.__next__(self)
125 | return value
126 | positive_float = PositiveFloatGenerator
127 |
128 | class FloatGenerator(NonNegativeFloatGenerator):
129 | def __next__(self):
130 | return NonNegativeFloatGenerator.__next__(self)*random.choice([+1,-1])
131 |
132 | class ComplexGenerator(NonNegativeFloatGenerator):
133 | def __next__(self):
134 | return NonNegativeFloatGenerator.__next__(self) * cmath.exp(random.random()*2*pi*1j)
135 |
136 | # ------------------------------------------------------------------------------
137 | # Collection Generators
138 | # ------------------------------------------------------------------------------
139 |
140 | class CollectionGenerator(PayCheckGenerator):
141 | def __init__(self, t_def):
142 | PayCheckGenerator.__init__(self)
143 | self.inner = PayCheckGenerator.get(t_def)
144 |
145 | def __next__(self):
146 | return self.to_container(islice(self.inner,random.randint(0,LIST_LEN)))
147 |
148 | class ListGenerator(CollectionGenerator):
149 | def __init__(self, example):
150 | try:
151 | CollectionGenerator.__init__(self,iter(example).next())
152 | except StopIteration:
153 | raise IncompleteTypeException(example)
154 |
155 | def to_container(self,generator):
156 | return list(generator)
157 |
158 | class SetGenerator(ListGenerator):
159 | def to_container(self,generator):
160 | return set(generator)
161 |
162 | class DictGenerator(CollectionGenerator):
163 | def __init__(self, example):
164 | try:
165 | CollectionGenerator.__init__(self,example.iteritems().next())
166 | except StopIteration:
167 | raise IncompleteTypeException(example)
168 |
169 | def to_container(self,generator):
170 | return dict(generator)
171 |
172 | class TupleGenerator(PayCheckGenerator):
173 | def __init__(self, example):
174 | PayCheckGenerator.__init__(self)
175 | self.generators = map(PayCheckGenerator.get,example)
176 |
177 | def __iter__(self):
178 | return izip(*self.generators)
179 |
180 | # ------------------------------------------------------------------------------
181 | # Dictionary of Generators
182 | # ------------------------------------------------------------------------------
183 |
184 | scalar_generators = {
185 | str: StringGenerator,
186 | int: IntGenerator,
187 | bool: BooleanGenerator,
188 | float: FloatGenerator,
189 | complex: ComplexGenerator,
190 | }
191 |
192 | if sys.version_info[0] < 3:
193 | scalar_generators[unicode] = UnicodeGenerator
194 |
195 | container_generators = {
196 | list: ListGenerator,
197 | dict: DictGenerator,
198 | set: SetGenerator,
199 | tuple: TupleGenerator,
200 | }
201 |
202 | # ------------------------------------------------------------------------------
203 | # List of exports
204 | # ------------------------------------------------------------------------------
205 |
206 | __all__ = [
207 | 'MIN_INT',
208 | 'MAX_INT',
209 | 'LIST_LEN',
210 | 'PayCheckException',
211 | 'UnknownTypeException',
212 | 'IncompleteTypeException',
213 | 'PayCheckGenerator',
214 | 'StringGenerator',
215 | 'IntGenerator',
216 | 'irange',
217 | 'BooleanGenerator',
218 | 'UniformFloatGenerator',
219 | 'frange',
220 | 'unit_interval_float',
221 | 'NonNegativeFloatGenerator',
222 | 'non_negative_float',
223 | 'PositiveFloatGenerator',
224 | 'positive_float',
225 | 'FloatGenerator',
226 | 'ComplexGenerator',
227 | 'CollectionGenerator',
228 | 'ListGenerator',
229 | 'SetGenerator',
230 | 'DictGenerator',
231 | 'TupleGenerator',
232 | 'scalar_generators',
233 | 'container_generators',
234 | ]
235 |
236 | if sys.version_info[0] < 3:
237 | __all__.append('UnicodeGenerator')
238 |
--------------------------------------------------------------------------------