comparison planemo/lib/python3.7/site-packages/galaxy/util/permutations.py @ 1:56ad4e20f292 draft

"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author guerler
date Fri, 31 Jul 2020 00:32:28 -0400
parents
children
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 """ There is some shared logic between matching/multiplying inputs in workflows
2 and tools. This module is meant to capture some general permutation logic that
3 can be applicable for both cases but will only be used in the newer tools case
4 first.
5
6 Maybe this doesn't make sense and maybe much of this stuff could be replaced
7 with itertools product and permutations. These are open questions.
8 """
9 from collections import OrderedDict
10
11 from galaxy.exceptions import MessageException
12 from galaxy.util.bunch import Bunch
13
14 input_classification = Bunch(
15 SINGLE="single",
16 MATCHED="matched",
17 MULTIPLIED="multiplied",
18 )
19
20
21 class InputMatchedException(MessageException):
22 """ Indicates problem matching inputs while building up inputs
23 permutations. """
24
25
26 def expand_multi_inputs(inputs, classifier, key_filter=None):
27 key_filter = key_filter or (lambda x: True)
28
29 single_inputs, matched_multi_inputs, multiplied_multi_inputs = __split_inputs(
30 inputs,
31 classifier,
32 key_filter
33 )
34
35 # Build up every combination of inputs to be run together.
36 input_combos = __extend_with_matched_combos(single_inputs, matched_multi_inputs)
37 input_combos = __extend_with_multiplied_combos(input_combos, multiplied_multi_inputs)
38
39 return input_combos
40
41
42 def __split_inputs(inputs, classifier, key_filter):
43 key_filter = key_filter or (lambda x: True)
44
45 single_inputs = OrderedDict()
46 matched_multi_inputs = OrderedDict()
47 multiplied_multi_inputs = OrderedDict()
48
49 for input_key in filter(key_filter, inputs):
50 input_type, expanded_val = classifier(input_key)
51 if input_type == input_classification.SINGLE:
52 single_inputs[input_key] = expanded_val
53 elif input_type == input_classification.MATCHED:
54 matched_multi_inputs[input_key] = expanded_val
55 elif input_type == input_classification.MULTIPLIED:
56 multiplied_multi_inputs[input_key] = expanded_val
57
58 return (single_inputs, matched_multi_inputs, multiplied_multi_inputs)
59
60
61 def __extend_with_matched_combos(single_inputs, multi_inputs):
62 """
63
64 {a => 1, b => 2} and {c => {3, 4}, d => {5, 6}}
65
66 Becomes
67
68 [ {a => 1, b => 2, c => 3, d => 5}, {a => 1, b => 2, c => 4, d => 6}, ]
69
70 """
71
72 if len(multi_inputs) == 0:
73 return [single_inputs]
74
75 matched_multi_inputs = []
76
77 first_multi_input_key = next(iter(multi_inputs.keys()))
78 first_multi_value = multi_inputs.get(first_multi_input_key)
79
80 for value in first_multi_value:
81 new_inputs = __copy_and_extend_inputs(single_inputs, first_multi_input_key, value)
82 matched_multi_inputs.append(new_inputs)
83
84 for multi_input_key, multi_input_values in multi_inputs.items():
85 if multi_input_key == first_multi_input_key:
86 continue
87 if len(multi_input_values) != len(first_multi_value):
88 raise InputMatchedException("Received %d inputs for '%s' and %d inputs for '%s', these should be of equal length" %
89 (len(multi_input_values), multi_input_key, len(first_multi_value), first_multi_input_key))
90
91 for index, value in enumerate(multi_input_values):
92 matched_multi_inputs[index][multi_input_key] = value
93
94 return matched_multi_inputs
95
96
97 def __extend_with_multiplied_combos(input_combos, multi_inputs):
98 combos = input_combos
99
100 for multi_input_key, multi_input_value in multi_inputs.items():
101 iter_combos = []
102
103 for combo in combos:
104 for input_value in multi_input_value:
105 iter_combo = __copy_and_extend_inputs(combo, multi_input_key, input_value)
106 iter_combos.append(iter_combo)
107
108 combos = iter_combos
109
110 return combos
111
112
113 def __copy_and_extend_inputs(inputs, key, value):
114 new_inputs = dict(inputs)
115 new_inputs[key] = value
116 return new_inputs