Example #1
0
 def test_accepts_other(self):
     '''check that expanding non-processed objects returns exactly the object'''
     for no_prc_case in self.no_proc_cases:
         instance = ExpandCombinations(self.input_case[no_prc_case])
         submsg = repr(self.input_case[no_prc_case])
         with self.subTest(msg=submsg, case=no_prc_case):
             self.assertIsInstance(
                 instance, ExpandCombinations,
                 'for {!r}'.format(self.input_case[no_prc_case], ctx='instance'))
         iterator = iter(instance)
         with self.subTest(msg=submsg, case=no_prc_case, ctx='iterator'):
Example #2
0
 def test_uses_copy_of_flat_dict(self):
     '''check that content of a dict is copied to output without references to input'''
     for exp_case in self.fd_cases:
         src_obj = self.input_case[exp_case]  # reference to input object
         src_keys = list(src_obj.keys())
         if not src_obj:
             with self.subTest(msg=repr(src_keys), ctx='empty'):
                 # take a (fresh) copy of input case that is safe to modify
                 in_obj = odict(copy.deepcopy(src_obj))
                 instance = ExpandCombinations(in_obj)
                 captured = []
                 for out_ele in instance:
                     captured.append(out_ele)
                 self.assertEqual(1, len(captured), 'should be only single output element')
                 self.assertEqual(self.expected_out[exp_case], captured, 'exp == out list')
                 in_obj['new'] = 'break'
                 self.assertEqual(self.expected_out[exp_case], captured, 'input key added')
             continue
         for perm in permutations(src_keys):
             with self.subTest(msg=repr(perm), ctx='permutation'):
                 # take a (fresh) copy of input case that is safe to modify
                 in_obj = odict(copy.deepcopy(src_obj))
                 for key in perm:  # adjust odict keys to match permutation order
                     in_obj.move_to_end(key)
                 self.assertEqual(perm, list(in_obj.keys()), 'keys should match permutation')
                 instance = ExpandCombinations(in_obj)
                 captured = []
                 for out_ele in instance:
                     captured.append(out_ele)
                     # «single» output should be same as input for this simple case
                     self.assertEqual(src_obj, out_ele, 'src == out ele')
                     self.assertEqual(self.expected_out[exp_case][0], out_ele, 'exp == out ele')
                 self.assertEqual(1, len(captured), 'should be only single output element')
                 self.assertEqual(self.expected_out[exp_case], captured, 'exp == out list')
                 in_obj[perm[0]] = 'changed'
                 self.assertEqual(self.expected_out[exp_case], captured, 'input key changed')
                 del in_obj[perm[-1]]
                 self.assertEqual(self.expected_out[exp_case], captured, 'input key deleted')
                 in_obj['new'] = 'break'
                 self.assertEqual(self.expected_out[exp_case], captured, 'input key added')
Example #3
0
 def test_accepts_flat_dict(self):
     '''check that a flat dictionary is valid, and uses custom iterator'''
     for exp_case in self.fd_cases:
         instance = ExpandCombinations(self.input_case[exp_case])
         with self.subTest():
             self.assertIsInstance(
                 instance, ExpandCombinations,
                 'for {!r}'.format(self.input_case[exp_case]))
         iterator = iter(instance)
         with self.subTest():
             self.assertIsInstance(
                 iterator, ExpandCombinations,
                 'for {!r}'.format(self.input_case[exp_case]))
Example #4
0
 def test_gen_variant_dict(self):
     '''check that dictionary entries generate a variant per list element'''
     for exp_case in self.vd_cases:
         expect_ele_cnt = len(self.expected_out[exp_case])
         src_obj = self.input_case[exp_case]  # reference to input object
         for perm_set in multiple_key_permutations([d_ref for d_ref in
                                                    self._get_dict_from_expandable(src_obj)]):
             # for each key permutation (all dictionaries)
             with self.subTest(msg=repr(perm_set), ctx='permutation', case=exp_case):
                 # take a (fresh) copy of the input case that is safe to modify
                 in_obj = odict(copy.deepcopy(src_obj))
                 # get (matching) references to the dictionaries in the copy
                 in_ref = [ref for ref in self._get_dict_from_expandable(in_obj)]
                 for idx, ref in enumerate(in_ref):  # set key order for permutation set
                     for key in perm_set[idx]:
                         ref.move_to_end(key)
                     self.assertEqual(
                         perm_set[idx], list(ref.keys()), 'keys should match permutation')
                 instance = ExpandCombinations(in_obj)  # using adjusted key sequence
                 captured = []  # would prefer set, but dict not hashable
                 for out_ele in instance:
                     with self.subTest(msg=repr(perm_set), ctx='inline'):
                         # inline check; each output element should match a unique expected case
                         with self.subTest(msg=repr(perm_set), ctx='duplicate', dup=out_ele):
                             self.assertNotIn(out_ele, captured, 'generated ele not unique')
                         captured.append(out_ele)
                         self.assertIn(
                             out_ele, self.expected_out[exp_case], 'generated ele not expected')
                 self.assertEqual(expect_ele_cnt, len(captured), 'wrong output element count')
                 # full post iteration check, elements should change one step to the next
                 with self.subTest(msg=repr(perm_set), ctx='post check'):
                     self._unordered_list_compare(self.expected_out[exp_case], captured)
                     # make sure that (post iteration) input changes do not affect collected data
                     for idx, perm in enumerate(perm_set):
                         if isinstance(in_ref[idx][perm[0]], list):
                             in_ref[idx][perm[0]].append('extra')
                             subcase = 'input ele appended'
                         else:
                             in_ref[idx][perm[0]] = 'changed'
                             subcase = 'input ele changed'
                         with self.subTest(msg=repr(perm_set), ctx=subcase, prm=perm, idx=idx):
                             self._unordered_list_compare(self.expected_out[exp_case], captured)
                         del in_ref[idx][perm[-1]]
                         with self.subTest(msg=repr(perm_set),
                                           ctx='input key deleted', prm=perm, idx=idx):
                             self._unordered_list_compare(self.expected_out[exp_case], captured)
                         in_ref[idx]['pluskey'] = 'added'
                         with self.subTest(msg=repr(perm),
                                           ctx='input key added', prm=perm, idx=idx):
                             self._unordered_list_compare(self.expected_out[exp_case], captured)
Example #5
0
 def test_accepts_flat_list(self):
     '''check that a flat list is valid, and uses standard iterator'''
     for exp_case in self.fl_cases:
         instance = ExpandCombinations(self.input_case[exp_case])
         with self.subTest():
             self.assertIsInstance(
                 instance, ExpandCombinations,
                 'for {!r}'.format(self.input_case[exp_case]))
         iterator = iter(instance)
         with self.subTest():
             self.assertNotIsInstance(
                 iterator, ExpandCombinations,
                 'for {!r}, and should not be'.format(self.input_case[exp_case]))
         with self.subTest():
             self.assertIsInstance(
                 iterator, iter([]).__class__,
                 # iterator, list_iterator,  # NameError: name 'list_iterator' is not defined
                 'for {!r}'.format(self.input_case[exp_case]))
Example #6
0
 def test_flatten_nested(self):
     '''check that nested lists are flattened on output, and not references'''
     for nest_case in self.nl_cases:
         in_obj = copy.deepcopy(self.input_case[nest_case])
         instance = ExpandCombinations(in_obj)
         captured = []
         ele_idx = 0
         for out_ele in instance:
             captured.append(out_ele)
             with self.subTest(msg=repr(self.input_case[nest_case]), ctx='for'):
                 # Do an on the fly check while iterating
                 self.assertEqual(self.expected_out[nest_case][ele_idx], out_ele)
             ele_idx += 1
         with self.subTest(msg=repr(self.input_case[nest_case]), ctx='captured'):
             self.assertEqual(self.expected_out[nest_case], captured)
             # modify all elements in the input list
             for idx in range(len(self.input_case[nest_case])):
                 in_obj[idx] = 'changed'
             # verify that the caputure ouput has not been changed
             with self.subTest(msg=repr(self.input_case[nest_case]), ctx='detect reference'):
                 self.assertEqual(self.expected_out[nest_case], captured)
Example #7
0
 def test_uses_copyof_flat_list(self):
     '''check that the content of a flat list is not linked (referenced) by output'''
     for exp_case in self.fl_cases:
         in_obj = self.input_case[exp_case].copy()
         instance = ExpandCombinations(in_obj)
         captured = []
         ele_idx = 0
         for out_ele in instance:
             captured.append(out_ele)
             with self.subTest(msg=repr(self.input_case[exp_case]), ctx='iterate'):
                 # Do an on the fly check
                 self.assertEqual(self.input_case[exp_case][ele_idx], out_ele, 'src != out')
                 self.assertEqual(in_obj[ele_idx], out_ele, 'in != out')  # better be same
                 # now modify the input element, and make sure that the output did not change too
                 # in_obj[ele_idx] = '@'
                 in_obj[ele_idx] = '@'
                 self.assertNotEqual(in_obj[ele_idx], out_ele, 'mod in == out')
                 self.assertEqual(self.input_case[exp_case][ele_idx], out_ele, 'src chg != out')
             ele_idx += 1
         with self.subTest(msg=repr(self.input_case[exp_case]), ctx='post iteration'):
             self.assertEqual(self.input_case[exp_case], captured, 'expected == captured')
             if in_obj:  # only not equal when input was not an empty list
                 self.assertNotEqual(in_obj, captured, 'in != captured')
Example #8
0
def mymain(*supplied_keys):
    '''wrapper for test/start code so that variables do not look like constants'''
    smpl_keys = supplied_keys
    samples = {
        's1': {'key1': 'constant value', 'key2': ['option 1', 'option 2', ], },
        's2': {'key1': 'constant value', 'key2': ['option 1', 'option 2', ],
               'key3': ['option 3', 'option 4', ], },
        's3': {'key1': 'default value', 'key2': [
            'option 1',
            {'key3': 'fixed value', 'key4': ['option 2', 'option 3'], },
            {'key1': 'override', 'key2': 'keep key'}, ], },
        'list1': ['first', 'second', 'third', ],
        'list2': ['dup', 'dup', 'third', ],
        'l1': ['a', ['b', 'c'], 'd', ],
        'l2': [
            'a',
            {'k1': [1, 2, ], 'k2': 'c'},
            {'k3': ['a', 'b', ], 'k4': 5}, ],
        'dup1': {
            'cmn': 'always',
            'hasdup': ['dup', 'dup', 'other'],
        },
        'equiv1': {'key': 'value', },
        'equiv2': {'key': ['value', ], },
        'equiv3': {'key': [{'key': 'value', }, ], },
        'equiv4': {'key': [{'key': [{'key': 'value', }, ], }, ], },
        'equiv5': {'other': [{'key': 'value'}, ], },
        'equiv6': {'key': [{'other': [{'key': 'value', }, ], }, ], },
        'equiv7': {'other1': [{'other2': [{'key': 'value', }, ], }, ], },
        'test0': 'simple string',
        'test1': {'key': 'value', 'dummy': [], },
        'sub1': {
            'family': 'bjt',
            'footprint': '',
            'package': ['TO220', {
                'footprint': ['SIL', 'triangle', ],
                'package': 'TO92',
                }, 'SOT23', ],
        },
        'sub2': {
            'footprint': '',
            'mounting': 'THT',
            'package': [
                {
                    'package': 'TO92',
                    'footprint': ['SIL', 'triangle', ],
                }, {
                    'package': 'SOT23',
                    'mounting': 'SMD',
                },
                'TO220', ],
            'label': ['pin', '', ],
            'type': ['NPN', 'PNP', ],
            'pinout': ['BCE', 'BEC', 'CBE', 'CEB', 'EBC', 'ECB', ],
        },
        'sub3': {
            'footprint': '',
            'mounting': 'THT',
            'package': ['TO220', {
                'package': 'TO92',
                'footprint': ['SIL', 'triangle', ],
                }, {
                    'package': 'SOT23',
                    'mounting': 'SMD',
                }, ],
            'label': ['pin', '', ],
            'type': ['NPN', 'PNP', ],
            'pinout': ['BCE', 'BEC', 'CBE', 'CEB', 'EBC', 'ECB', ],
        },
        'meals': {
            'appetizer': ['calamari', 'potatoe skins', 'cheesy nachos', 'escargot', ],
            'entrée': [
                'chicken',
                {'entrée': ['white fish', 'rainbow trout'], 'wine': 'white'},
                {'entrée': 'steak', 'wine': 'red'}, ],
            'desert': ['pie', 'tiramisu', 'ice cream', 'apple crisp', ],
        },
    }
    cheeses = ['cheddar', 'goat', 'feta', 'parmesan']
    vegetables = ['avocado', 'mushrooms', 'onions', 'spinach']
    meats = ['bacon', 'beef', 'pepperoni']
    seafood = ['shrimp', 'anchovies', 'prawns']
    samples['pizza'] = [
        {'first': [cheeses, vegetables, meats, seafood, ], },
        {
            'first': [cheeses, vegetables, meats, seafood, ],
            'second': [cheeses, vegetables, meats, seafood, ],
        },
        {
            'first': [cheeses, vegetables, meats, seafood, ],
            'second': [cheeses, vegetables, meats, seafood, ],
            'third': [cheeses, vegetables, meats, seafood, ],
        },
    ]
    # print(samples['pizza'])  # DEBUG
    samples['pizza2'] = {
        'toppings': (cheeses, meats)
    }
    # print(samples['pizza2'])  # DEBUG

    if len(sys.argv) > 1:
        smpl_keys = sys.argv[1:]

    pizza_keys = ['first', 'second', 'third']
    for smpl in smpl_keys:
        if smpl not in samples:
            print('sample {!r} does not exist'.format(smpl))
            continue
        print('\nsample {} input data:'.format(smpl))
        print(samples[smpl])
        test_iter = ExpandCombinations(samples[smpl])
        dedup = []  # only used for pizza
        print('sample {} expanded outputs:'.format(smpl))
        expansion_count = 0
        for cmb in test_iter:
            expansion_count += 1
            print(cmb)
            # pizza is special.  Get the unique topping Combinations
            if smpl == 'pizza':
                cmb_toppings = []
                for pkey in pizza_keys:
                    if pkey in cmb:
                        cmb_toppings.append(cmb[pkey])
                cmb_toppings.sort()
                if cmb_toppings not in dedup:
                    dedup.append(cmb_toppings)
        print('{} expanded combinations'.format(expansion_count))
        if smpl == 'pizza':
            for cmb in dedup:
                print(cmb)
            print('{} unique pizza topping combinations'.format(len(dedup)))