GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — plexxi-v2.3.2 ( 5d46fe )
by
unknown
06:59
created

TraceListCommand.run()   C

Complexity

Conditions 8

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
c 0
b 0
f 0
dl 0
loc 18
rs 6.6666
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
from st2client.models import Resource, Trace, TriggerInstance, Rule, LiveAction
17
from st2client.exceptions.operations import OperationFailureException
18
from st2client.formatters import table
19
from st2client.formatters import execution as execution_formatter
20
from st2client.commands import resource
21
from st2client.utils.date import format_isodate_for_user_timezone
22
23
24
TRACE_ATTRIBUTE_DISPLAY_ORDER = ['id', 'trace_tag', 'action_executions', 'rules',
25
                                 'trigger_instances', 'start_timestamp']
26
27
TRACE_HEADER_DISPLAY_ORDER = ['id', 'trace_tag', 'start_timestamp']
28
29
TRACE_COMPONENT_DISPLAY_LABELS = ['id', 'type', 'ref', 'updated_at']
30
31
TRACE_DISPLAY_ATTRIBUTES = ['all']
32
33
TRIGGER_INSTANCE_DISPLAY_OPTIONS = [
34
    'all',
35
    'trigger-instances',
36
    'trigger_instances',
37
    'triggerinstances',
38
    'triggers'
39
]
40
41
ACTION_EXECUTION_DISPLAY_OPTIONS = [
42
    'all',
43
    'executions',
44
    'action-executions',
45
    'action_executions',
46
    'actionexecutions',
47
    'actions'
48
]
49
50
51
class TraceBranch(resource.ResourceBranch):
52
    def __init__(self, description, app, subparsers, parent_parser=None):
53
        super(TraceBranch, self).__init__(
54
            Trace, description, app, subparsers,
55
            parent_parser=parent_parser,
56
            read_only=True,
57
            commands={
58
                'list': TraceListCommand,
59
                'get': TraceGetCommand
60
            })
61
62
63
class SingleTraceDisplayMixin(object):
64
65
    def print_trace_details(self, trace, args, **kwargs):
66
        options = {'attributes': TRACE_ATTRIBUTE_DISPLAY_ORDER if args.json else
67
                   TRACE_HEADER_DISPLAY_ORDER}
68
        options['json'] = args.json
69
        options['yaml'] = args.yaml
70
        options['attribute_transform_functions'] = self.attribute_transform_functions
71
72
        formatter = execution_formatter.ExecutionResult
73
74
        self.print_output(trace, formatter, **options)
75
76
        # Everything should be printed if we are printing json.
77
        if args.json or args.yaml:
78
            return
79
80
        components = []
81
        if any(attr in args.attr for attr in TRIGGER_INSTANCE_DISPLAY_OPTIONS):
82
            components.extend([Resource(**{'id': trigger_instance['object_id'],
83
                                           'type': TriggerInstance._alias.lower(),
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _alias was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
84
                                           'ref': trigger_instance['ref'],
85
                                           'updated_at': trigger_instance['updated_at']})
86
                               for trigger_instance in trace.trigger_instances])
87
        if any(attr in args.attr for attr in ['all', 'rules']):
88
            components.extend([Resource(**{'id': rule['object_id'],
89
                                           'type': Rule._alias.lower(),
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _alias was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
90
                                           'ref': rule['ref'],
91
                                           'updated_at': rule['updated_at']})
92
                               for rule in trace.rules])
93
        if any(attr in args.attr for attr in ACTION_EXECUTION_DISPLAY_OPTIONS):
94
            components.extend([Resource(**{'id': execution['object_id'],
95
                                           'type': LiveAction._alias.lower(),
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _alias was declared protected and should not be accessed from this context.

Prefixing a member variable _ is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class:

class MyParent:
    def __init__(self):
        self._x = 1;
        self.y = 2;

class MyChild(MyParent):
    def some_method(self):
        return self._x    # Ok, since accessed from a child class

class AnotherClass:
    def some_method(self, instance_of_my_child):
        return instance_of_my_child._x   # Would be flagged as AnotherClass is not
                                         # a child class of MyParent
Loading history...
96
                                           'ref': execution['ref'],
97
                                           'updated_at': execution['updated_at']})
98
                               for execution in trace.action_executions])
99
        if components:
100
            components.sort(key=lambda resource: resource.updated_at)
101
            self.print_output(components, table.MultiColumnTable,
102
                              attributes=TRACE_COMPONENT_DISPLAY_LABELS,
103
                              json=args.json, yaml=args.yaml)
104
105
106
class TraceListCommand(resource.ResourceCommand, SingleTraceDisplayMixin):
107
    display_attributes = ['id', 'uid', 'trace_tag', 'start_timestamp']
108
109
    attribute_transform_functions = {
110
        'start_timestamp': format_isodate_for_user_timezone
111
    }
112
113
    attribute_display_order = TRACE_ATTRIBUTE_DISPLAY_ORDER
114
115
    def __init__(self, resource, *args, **kwargs):
0 ignored issues
show
Comprehensibility Bug introduced by
resource is re-defining a name which is already available in the outer-scope (previously defined on line 20).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
116
        super(TraceListCommand, self).__init__(
117
            resource, 'list', 'Get the list of the 50 most recent %s.' %
118
            resource.get_plural_display_name().lower(),
119
            *args, **kwargs)
120
121
        self.default_limit = 50
122
        self.resource_name = resource.get_plural_display_name().lower()
123
        self.group = self.parser.add_mutually_exclusive_group()
124
        self.parser.add_argument('-n', '--last', type=int, dest='last',
125
                                 default=self.default_limit,
126
                                 help=('List N most recent %s.' % self.resource_name))
127
        self.parser.add_argument('-s', '--sort', type=str, dest='sort_order',
128
                                 default='descending',
129
                                 help=('Sort %s by start timestamp, '
130
                                       'asc|ascending (earliest first) '
131
                                       'or desc|descending (latest first)' % self.resource_name))
132
133
        # Filter options
134
        self.group.add_argument('-c', '--trace-tag', help='Trace-tag to filter the list.')
135
        self.group.add_argument('-e', '--execution', help='Execution to filter the list.')
136
        self.group.add_argument('-r', '--rule', help='Rule to filter the list.')
137
        self.group.add_argument('-g', '--trigger-instance',
138
                                help='TriggerInstance to filter the list.')
139
        # Display options
140
        self.parser.add_argument('-a', '--attr', nargs='+',
141
                                 default=self.display_attributes,
142
                                 help=('List of attributes to include in the '
143
                                       'output. "all" will return all '
144
                                       'attributes.'))
145
        self.parser.add_argument('-w', '--width', nargs='+', type=int,
146
                                 default=None,
147
                                 help=('Set the width of columns in output.'))
148
149
    @resource.add_auth_token_to_kwargs_from_cli
150
    def run(self, args, **kwargs):
151
        # Filtering options
152
        if args.trace_tag:
153
            kwargs['trace_tag'] = args.trace_tag
154
        if args.trigger_instance:
155
            kwargs['trigger_instance'] = args.trigger_instance
156
        if args.execution:
157
            kwargs['execution'] = args.execution
158
        if args.rule:
159
            kwargs['rule'] = args.rule
160
161
        if args.sort_order:
162
            if args.sort_order in ['asc', 'ascending']:
163
                kwargs['sort_asc'] = True
164
            elif args.sort_order in ['desc', 'descending']:
165
                kwargs['sort_desc'] = True
166
        return self.manager.query_with_count(limit=args.last, **kwargs)
167
168
    def run_and_print(self, args, **kwargs):
169
        instances, count = self.run(args, **kwargs)
170
171
        if instances and len(instances) == 1:
172
            # For a single Trace we must include the components unless
173
            # user has overriden the attributes to display
174
            if args.attr == self.display_attributes:
175
                args.attr = ['all']
176
            self.print_trace_details(trace=instances[0], args=args)
177
178
            if not args.json and not args.yaml:
179
                if args.last and count and count > args.last:
180
                        table.SingleRowTable.note_box(self.resource_name, 1)
0 ignored issues
show
Coding Style introduced by
The indentation here looks off. 20 spaces were expected, but 24 were found.
Loading history...
181
        else:
182
            if args.json or args.yaml:
183
                self.print_output(reversed(instances), table.MultiColumnTable,
184
                                  attributes=args.attr, widths=args.width,
185
                                  json=args.json, yaml=args.yaml,
186
                                  attribute_transform_functions=self.attribute_transform_functions)
187
            else:
188
                self.print_output(reversed(instances), table.MultiColumnTable,
189
                                  attributes=args.attr, widths=args.width,
190
                                  attribute_transform_functions=self.attribute_transform_functions)
191
192
                if args.last and count and count > args.last:
193
                    table.SingleRowTable.note_box(self.resource_name, args.last)
194
195
196
class TraceGetCommand(resource.ResourceGetCommand, SingleTraceDisplayMixin):
197
    display_attributes = ['all']
198
    attribute_display_order = TRACE_ATTRIBUTE_DISPLAY_ORDER
199
    attribute_transform_functions = {
200
        'start_timestamp': format_isodate_for_user_timezone
201
    }
202
203
    pk_argument_name = 'id'
204
205
    def __init__(self, resource, *args, **kwargs):
0 ignored issues
show
Comprehensibility Bug introduced by
resource is re-defining a name which is already available in the outer-scope (previously defined on line 20).

It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior:

param = 5

class Foo:
    def __init__(self, param):   # "param" would be flagged here
        self.param = param
Loading history...
206
        super(TraceGetCommand, self).__init__(resource, *args, **kwargs)
207
208
        # Causation chains
209
        self.causation_group = self.parser.add_mutually_exclusive_group()
210
211
        self.causation_group.add_argument('-e', '--execution',
212
                                          help='Execution to show causation chain.')
213
        self.causation_group.add_argument('-r', '--rule', help='Rule to show causation chain.')
214
        self.causation_group.add_argument('-g', '--trigger-instance',
215
                                          help='TriggerInstance to show causation chain.')
216
217
        # display filter group
218
        self.display_filter_group = self.parser.add_argument_group()
219
220
        self.display_filter_group.add_argument('--show-executions', action='store_true',
221
                                               help='Only show executions.')
222
        self.display_filter_group.add_argument('--show-rules', action='store_true',
223
                                               help='Only show rules.')
224
        self.display_filter_group.add_argument('--show-trigger-instances', action='store_true',
225
                                               help='Only show trigger instances.')
226
        self.display_filter_group.add_argument('-n', '--hide-noop-triggers', action='store_true',
227
                                               help='Hide noop trigger instances.')
228
229
    @resource.add_auth_token_to_kwargs_from_cli
230
    def run(self, args, **kwargs):
231
        resource_id = getattr(args, self.pk_argument_name, None)
232
        return self.get_resource_by_id(resource_id, **kwargs)
233
234
    @resource.add_auth_token_to_kwargs_from_cli
235
    def run_and_print(self, args, **kwargs):
236
        trace = None
237
        try:
238
            trace = self.run(args, **kwargs)
239
        except resource.ResourceNotFoundError:
240
            self.print_not_found(args.id)
241
            raise OperationFailureException('Trace %s not found.' % (args.id))
242
        # First filter for causation chains
243
        trace = self._filter_trace_components(trace=trace, args=args)
244
        # next filter for display purposes
245
        trace = self._apply_display_filters(trace=trace, args=args)
246
        return self.print_trace_details(trace=trace, args=args)
247
248
    @staticmethod
249
    def _filter_trace_components(trace, args):
250
        """
251
        This function walks up the component causal chain. It only returns
252
        properties in the causal chain and nothing else.
253
        """
254
        # check if any filtering is desired
255
        if not (args.execution or args.rule or args.trigger_instance):
256
            return trace
257
258
        component_id = None
259
        component_type = None
260
261
        # pick the right component type
262
        if args.execution:
263
            component_id = args.execution
264
            component_type = 'action_execution'
265
        elif args.rule:
266
            component_id = args.rule
267
            component_type = 'rule'
268
        elif args.trigger_instance:
269
            component_id = args.trigger_instance
270
            component_type = 'trigger_instance'
271
272
        # Initialize collection to use
273
        action_executions = []
274
        rules = []
275
        trigger_instances = []
276
277
        # setup flag to properly manage termination conditions
278
        search_target_found = component_id and component_type
279
280
        while search_target_found:
281
            components_list = []
282
            if component_type == 'action_execution':
283
                components_list = trace.action_executions
284
                to_update_list = action_executions
285
            elif component_type == 'rule':
286
                components_list = trace.rules
287
                to_update_list = rules
288
            elif component_type == 'trigger_instance':
289
                components_list = trace.trigger_instances
290
                to_update_list = trigger_instances
291
            # Look for search_target in the right collection and
292
            # once found look up the caused_by to keep movig up
293
            # the chain.
294
            search_target_found = False
295
            # init to default value
296
            component_caused_by_id = None
297
            for component in components_list:
298
                test_id = component['object_id']
299
                if test_id == component_id:
300
                    caused_by = component.get('caused_by', {})
301
                    component_id = caused_by.get('id', None)
302
                    component_type = caused_by.get('type', None)
303
                    # If provided the component_caused_by_id must match as well. This is mostly
304
                    # applicable for rules since the same rule may appear multiple times and can
305
                    # only be distinguished by causing TriggerInstance.
306
                    if component_caused_by_id and component_caused_by_id != component_id:
307
                        continue
308
                    component_caused_by_id = None
309
                    to_update_list.append(component)
310
                    # In some cases the component_id and the causing component are combined to
311
                    # provide the complete causation chain. Think rule + triggerinstance
312
                    if component_id and ':' in component_id:
313
                        component_id_split = component_id.split(':')
314
                        component_id = component_id_split[0]
315
                        component_caused_by_id = component_id_split[1]
316
                    search_target_found = True
317
                    break
318
319
        trace.action_executions = action_executions
320
        trace.rules = rules
321
        trace.trigger_instances = trigger_instances
322
        return trace
323
324
    @staticmethod
325
    def _apply_display_filters(trace, args):
326
        """
327
        This function looks at the disaply filters to determine which components
328
        should be displayed.
329
        """
330
        # If all the filters are false nothing is to be filtered.
331
        all_component_types = not(args.show_executions or
332
                                  args.show_rules or
333
                                  args.show_trigger_instances)
334
335
        # check if noop_triggers are to be hidden. This check applies whenever TriggerInstances
336
        # are to be shown.
337
        if (all_component_types or args.show_trigger_instances) and args.hide_noop_triggers:
338
            filtered_trigger_instances = []
339
            for trigger_instance in trace.trigger_instances:
340
                is_noop_trigger_instance = True
341
                for rule in trace.rules:
342
                    caused_by_id = rule.get('caused_by', {}).get('id', None)
343
                    if caused_by_id == trigger_instance['object_id']:
344
                        is_noop_trigger_instance = False
345
                if not is_noop_trigger_instance:
346
                    filtered_trigger_instances.append(trigger_instance)
347
            trace.trigger_instances = filtered_trigger_instances
348
349
        if all_component_types:
350
            return trace
351
352
        if not args.show_executions:
353
            trace.action_executions = []
354
355
        if not args.show_rules:
356
            trace.rules = []
357
358
        if not args.show_trigger_instances:
359
            trace.trigger_instances = []
360
361
        return trace
362