Test Failed
Push — master ( 9ba79c...17f3e3 )
by Yousef
01:54 queued 19s
created

savu.core.iterate_plugin_group_utils   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 166
rs 10
c 0
b 0
f 0
wmc 16

6 Functions

Rating   Name   Duplication   Size   Complexity  
A check_if_end_plugin_in_iterate_group() 0 12 2
A create_clone() 0 6 1
A setup_extra_plugin_data_padding() 0 21 3
A enable_iterative_loop() 0 66 4
A check_if_in_iterative_loop() 0 34 5
A shift_plugin_index() 0 16 1
1
import logging
2
3
from savu.data.data_structures.plugin_data import PluginData
4
5
6
def enable_iterative_loop(setup_fn):
7
    '''
8
    Decorator that can be applied to a plugin's setup() method. Doing so
9
    modifies the plugin's setup slightly to work correctly when at the end of an
10
    iterative loop, by setting up the relevant extra output dataset.
11
    '''
12
    def wrapper(*args, **kwargs):
13
        # run the plugin's original setup() method
14
        setup_fn(*args, **kwargs)
15
        plugin = args[0]
16
17
        if check_if_end_plugin_in_iterate_group(plugin.exp):
18
            # do the other setup required for the plugin to be the end plugin of
19
            # an iterative group
20
21
            in_dataset, out_dataset = plugin.get_datasets()
22
            in_pData, out_pData = plugin.get_plugin_datasets()
23
24
            try:
25
                max_frames = plugin.get_max_frames()
26
            except AttributeError:
27
                # the plugin has no get_max_frames() method, so assume it to be
28
                # 'single
29
                max_frames = 'single'
30
31
            # create the cloned dataset
32
            create_clone(out_dataset[1], out_dataset[0])
33
34
            # this is the pattern that was used for the "original" output data
35
            # for the end plugin
36
            out_pattern = out_pData[0].get_pattern_name()
37
            # set the pattern for the PluginData objects associated with the
38
            # newly created cloned dataset
39
            out_pData[1].plugin_data_setup(out_pattern, max_frames)
40
41
            try:
42
                iterate_plugin_group = check_if_in_iterative_loop(plugin.exp)
43
                start_plugin = iterate_plugin_group.start_plugin
44
                start_plugin_in_pData, start_plugin_out_pData = \
45
                    start_plugin.get_plugin_datasets()
46
                # this is the pattern that was used for the input data for the
47
                # start plugin
48
                in_pattern = start_plugin_in_pData[0].get_pattern_name()
49
                # this is the padding that is going to be applied to the input
50
                # data for the start plugin
51
                in_padding = start_plugin_in_pData[0].padding
52
53
                # create PluginData object for original and cloned Data objects,
54
                # that have the pattern of the start plugin, and append to the
55
                # start plugin's 'plugin_in_datasets'
56
                orig_start_pData = PluginData(out_dataset[0], start_plugin)
57
                orig_start_pData.padding = in_padding
58
                orig_start_pData.plugin_data_setup(in_pattern, 'single')
59
                start_plugin.parameters['plugin_in_datasets'].append(orig_start_pData)
60
                clone_start_pData = PluginData(out_dataset[1], start_plugin)
61
                clone_start_pData.padding = in_padding
62
                clone_start_pData.plugin_data_setup(in_pattern, 'single')
63
                start_plugin.parameters['plugin_in_datasets'].append(clone_start_pData)
64
                # "re-finalise" the plugin datasets for the start plugin, now
65
                # that these new PluginData obejcts have been added
66
                start_plugin._finalise_plugin_datasets()
67
            except AttributeError as e:
68
                logging.debug('In plugin setup, will not create new ' \
69
                              'PluginData objects')
70
71
    return wrapper
72
73
def setup_extra_plugin_data_padding(padding_fn):
74
    """
75
    Decorator that can be applied to a filter plugin's set_filter_padding()
76
    method. Doing so modifies/extends the filter plugin's padding function
77
    slightly to also set the padding for the additional PluginData objects that
78
    are created when an iterative loop is defined.
79
    """
80
81
    def wrapper(*args, **kwargs):
82
        # run the plugin's original set_filter_padding() method
83
        padding_fn(*args, **kwargs)
84
        plugin = args[0]
85
86
        if check_if_end_plugin_in_iterate_group(plugin.exp):
87
            # check for any padding on the original output data, and apply it to
88
            # the cloned data
89
            in_pData, out_pData = plugin.get_plugin_datasets()
90
            if out_pData[0].padding is not None:
91
                out_pData[1].padding = out_pData[0].padding
92
93
    return wrapper
94
95
def create_clone(clone, data):
96
    '''
97
    Create a clone of a Data object
98
    '''
99
    clone.create_dataset(data)
100
    clone.data_info.set('clone', data.get_name())
101
102
def check_if_in_iterative_loop(exp):
103
    '''
104
    Inspect the metadata inside the Experiment object to determine if current
105
    processing is inside an iterative loop
106
    '''
107
    try:
108
        current_plugin_index = exp.meta_data.get('nPlugin')
109
        for group in exp.meta_data.get('iterate_groups'):
110
            start_index = shift_plugin_index(exp, group.start_index)
111
            end_index = shift_plugin_index(exp, group.end_index)
112
            if start_index <= current_plugin_index and \
113
                end_index >= current_plugin_index:
114
                return group
115
116
        # never hit an instance of IteratePluginGroup where the current plugin
117
        # index was within the start and end plugin indices, so processing is
118
        # not inside an iterative loop
119
        return None
120
    except AttributeError as e:
121
        # TODO: Currently, an AttributeError only occurs inside two framework
122
        # tests:
123
        # - astra_multiple_parameter_test.py
124
        # - multiple_parameter_test.py
125
        # due to the exp variable still being None (ie, when this check of if
126
        # the processing is in an iterative loop or not occurs, the Experiment
127
        # object hasn't yet been set in these tests).
128
        #
129
        # These framework tests should be investigated to better understand:
130
        # - in what cases the Experiment object isn't yet set when running Savu
131
        # - if this check can occur elsewhere, to avoid causing those framework
132
        #   tests to fail
133
        err_str = f"Error when checking if inside an iterative loop: {e}"
134
        logging.debug(err_str)
135
        return None
136
137
def check_if_end_plugin_in_iterate_group(exp):
138
    '''
139
    Determines if the current plugin is at the end of an iterative loop
140
    '''
141
    iterate_plugin_group = check_if_in_iterative_loop(exp)
142
    if iterate_plugin_group is None:
143
        return False
144
145
    end_index = shift_plugin_index(exp, iterate_plugin_group.end_index)
146
    is_end_plugin = end_index == exp.meta_data.get('nPlugin')
147
148
    return is_end_plugin
149
150
def shift_plugin_index(exp, index):
151
    '''
152
    The indices used for plugins when editing a process list in the
153
    configurator, and the indices used by PluginRunner._run_plugin_list(),
154
    differ based on a few different things, such as:
155
    - zero-based indexing internally in Savu, but one-based indexing in the
156
      configurator
157
    - the number of loaders in the process list
158
159
    This function is for shifting the one-based plugin index as would be seen in
160
    the configurator, to the nPlugin experimental metadata value as would be
161
    seen for the same plugin in the for loop in PluginRunner._run_plugin_list().
162
    '''
163
    n_loaders = exp.meta_data.plugin_list._get_n_loaders()
164
    SHIFT_TO_ZERO_BASED = 1
165
    return index - SHIFT_TO_ZERO_BASED - n_loaders