4
4
import pandas .util .testing as tm
5
5
from pandas .core .reshape .util import cartesian_product
6
6
7
+ from hypothesis import strategies as st
8
+ from hypothesis import given , settings , assume
9
+ from datetime import date
10
+ from dateutil import relativedelta
11
+ import string
12
+
13
+
14
+ NO_OF_EXAMPLES_PER_TEST_CASE = 20
15
+
16
+
17
+ def get_elements (elem_type ):
18
+ strategy = st .nothing ()
19
+ if elem_type == bool :
20
+ strategy = st .booleans ()
21
+ elif elem_type == int :
22
+ strategy = st .integers ()
23
+ elif elem_type == float :
24
+ strategy = st .floats ()
25
+ elif elem_type == str :
26
+ strategy = st .text (string .ascii_letters , max_size = 10 )
27
+ return strategy
28
+
29
+
30
+ @st .composite
31
+ def get_seq (draw , types , mixed = False , min_size = None , max_size = None , transform_func = None ):
32
+ """helper function to generate strategy for creating lists. parameters define the nature of to be generated list.
33
+ :param types: what type of elements constitute the list
34
+ :param mixed: if True, list will contains elements from all types listed in arg, oterwise it will have elements only from types[0].
35
+ :param min_size: minimum size of the list.
36
+ :param max_size: maximum size of the list.
37
+ :param transform_func: a callable which can be applied to whole list after it has been generated.
38
+ """
39
+ strategy = st .nothing ()
40
+ if min_size is None :
41
+ min_size = draw (st .integers (min_value = 0 , max_value = 100 ))
42
+
43
+ if max_size is None :
44
+ max_size = draw (st .integers (min_value = min_size , max_value = 100 ))
45
+
46
+ assert min_size <= max_size , 'max_size must be greater than equal to min_size'
47
+
48
+ elem_strategies = []
49
+ for elem_type in types :
50
+ elem_strategies .append (get_elements (elem_type ))
51
+ if not mixed :
52
+ break
53
+
54
+ if transform_func :
55
+ strategy = draw (st .lists (st .one_of (elem_strategies ),
56
+ min_size = min_size , max_size = max_size ).map (transform_func ))
57
+ else :
58
+ strategy = draw (st .lists (st .one_of (elem_strategies ),
59
+ min_size = min_size , max_size = max_size ))
60
+ return strategy
61
+
7
62
8
63
class TestCartesianProduct (object ):
9
64
10
- def test_simple (self ):
11
- x , y = list ('ABC' ), [1 , 22 ]
65
+ @settings (max_examples = NO_OF_EXAMPLES_PER_TEST_CASE )
66
+ @given (get_seq ((str ,), False , 1 , 1 ),
67
+ get_seq ((int ,), False , 1 , 2 ))
68
+ def test_simple (self , x , y ):
69
+ x = list (x [0 ])
70
+ # non-empty test case is handled in test_empty, therefore ignore it here
71
+ assume (len (x ) != 0 )
12
72
result1 , result2 = cartesian_product ([x , y ])
13
- expected1 = np .array (['A' , 'A' , 'B' , 'B' , 'C' , 'C' ])
14
- expected2 = np .array ([1 , 22 , 1 , 22 , 1 , 22 ])
73
+ expected1 = np .array ([item1 for item1 in x for item2 in y ])
74
+ expected2 = np .array ([item2 for item1 in x for item2 in y ])
75
+
15
76
tm .assert_numpy_array_equal (result1 , expected1 )
16
77
tm .assert_numpy_array_equal (result2 , expected2 )
17
78
79
+ @settings (max_examples = NO_OF_EXAMPLES_PER_TEST_CASE )
18
80
def test_datetimeindex (self ):
19
81
# regression test for GitHub issue #6439
20
82
# make sure that the ordering on datetimeindex is consistent
21
- x = date_range ('2000-01-01' , periods = 2 )
83
+ d = st .dates (min_value = date (1900 , 1 , 1 ), max_value = date (2100 , 1 , 1 )).example ()
84
+ n = d + relativedelta .relativedelta (days = 1 )
85
+ x = date_range (d , periods = 2 )
22
86
result1 , result2 = [Index (y ).day for y in cartesian_product ([x , x ])]
23
- expected1 = Index ([1 , 1 , 2 , 2 ])
24
- expected2 = Index ([1 , 2 , 1 , 2 ])
87
+ expected1 = Index ([d .day , d .day , n .day , n .day ])
88
+ expected2 = Index ([d .day , n .day , d .day , n .day ])
89
+
25
90
tm .assert_index_equal (result1 , expected1 )
26
91
tm .assert_index_equal (result2 , expected2 )
27
92
28
- def test_empty (self ):
93
+ @settings (max_examples = NO_OF_EXAMPLES_PER_TEST_CASE )
94
+ @given (st .lists (st .nothing ()),
95
+ get_seq ((int ,), False ),
96
+ get_seq ((str ,), False ))
97
+ def test_empty (self , empty_list , list_of_int , list_of_str ):
29
98
# product of empty factors
30
- X = [[], [0 , 1 ], []]
31
- Y = [[], [], ['a' , 'b' , 'c' ]]
99
+ X = [empty_list , list_of_int , empty_list ]
100
+ Y = [empty_list , empty_list , list_of_str ]
101
+
32
102
for x , y in zip (X , Y ):
33
103
expected1 = np .array ([], dtype = np .asarray (x ).dtype )
34
104
expected2 = np .array ([], dtype = np .asarray (y ).dtype )
@@ -37,13 +107,22 @@ def test_empty(self):
37
107
tm .assert_numpy_array_equal (result2 , expected2 )
38
108
39
109
# empty product (empty input):
40
- result = cartesian_product ([] )
110
+ result = cartesian_product (empty_list )
41
111
expected = []
42
112
assert result == expected
43
113
114
+ @settings (max_examples = NO_OF_EXAMPLES_PER_TEST_CASE )
44
115
def test_invalid_input (self ):
45
- invalid_inputs = [1 , [1 ], [1 , 2 ], [[1 ], 2 ],
46
- 'a' , ['a' ], ['a' , 'b' ], [['a' ], 'b' ]]
116
+ invalid_inputs = [st .integers ().example (),
117
+ st .tuples (st .integers ()).example (),
118
+ st .tuples (st .integers (), st .integers ()).example (),
119
+ st .text (string .ascii_letters , min_size = 1 , max_size = 1 ).example (),
120
+ st .tuples (st .text (string .ascii_letters , min_size = 1 , max_size = 1 )).example (),
121
+ st .tuples (st .text (string .ascii_letters , min_size = 1 , max_size = 1 ),
122
+ st .text (string .ascii_letters , min_size = 1 , max_size = 1 )).example (),
123
+ st .tuples (st .tuples (st .text (string .ascii_letters , min_size = 1 , max_size = 1 )),
124
+ st .text (string .ascii_letters , min_size = 1 , max_size = 1 )).example ()]
125
+
47
126
msg = "Input must be a list-like of list-likes"
48
127
for X in invalid_inputs :
49
128
tm .assert_raises_regex (TypeError , msg , cartesian_product , X = X )
0 commit comments