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

MultiColumnTable._get_field_value()   B

Complexity

Conditions 5

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
dl 0
loc 9
rs 8.5454
c 0
b 0
f 0
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
import json
17
import math
18
import logging
19
import sys
20
21
from prettytable import PrettyTable
22
from six.moves import zip
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in zip.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
23
24
from st2client import formatters
25
from st2client.utils import strutil
26
from st2client.utils.terminal import get_terminal_size
27
28
29
LOG = logging.getLogger(__name__)
30
31
# Minimum width for the ID to make sure the ID column doesn't wrap across
32
# multiple lines
33
MIN_ID_COL_WIDTH = 26
34
35
# Minimum width for a column
36
MIN_COL_WIDTH = 5
37
38
# Default attribute display order to use if one is not provided
39
DEFAULT_ATTRIBUTE_DISPLAY_ORDER = ['id', 'name', 'pack', 'description']
40
41
# Attributes which contain bash escape sequences - we can't split those across multiple lines
42
# since things would break
43
COLORIZED_ATTRIBUTES = {
44
    'status': {
45
        'col_width': 24  # Note: len('succeed' + ' (XXXX elapsed)') <= 24
46
    }
47
}
48
49
50
class MultiColumnTable(formatters.Formatter):
51
52
    def __init__(self):
53
        self._table_width = 0
54
55
    @classmethod
56
    def format(cls, entries, *args, **kwargs):
57
        attributes = kwargs.get('attributes', [])
58
        attribute_transform_functions = kwargs.get('attribute_transform_functions', {})
59
        widths = kwargs.get('widths', [])
60
        widths = widths or []
61
62
        if not widths and attributes:
63
            # Dynamically calculate column size based on the terminal size
64
            lines, cols = get_terminal_size()
65
66
            if attributes[0] == 'id':
67
                # consume iterator and save as entries so collection is accessible later.
68
                entries = [e for e in entries]
69
                # first column contains id, make sure it's not broken up
70
                first_col_width = cls._get_required_column_width(values=[e.id for e in entries],
71
                                                                 minimum_width=MIN_ID_COL_WIDTH)
72
                cols = (cols - first_col_width)
73
                col_width = int(math.floor((cols / len(attributes))))
74
            else:
75
                col_width = int(math.floor((cols / len(attributes))))
76
                first_col_width = col_width
77
            widths = []
78
            subtract = 0
79
            for index in range(0, len(attributes)):
80
                attribute_name = attributes[index]
81
82
                if index == 0:
83
                    widths.append(first_col_width)
84
                    continue
85
86
                if attribute_name in COLORIZED_ATTRIBUTES:
87
                    current_col_width = COLORIZED_ATTRIBUTES[attribute_name]['col_width']
88
                    subtract += (current_col_width - col_width)
89
                else:
90
                    # Make sure we subtract the added width from the last column so we account
91
                    # for the fixed width columns and make sure table is not wider than the
92
                    # terminal width.
93
                    if index == (len(attributes) - 1) and subtract:
94
                        current_col_width = (col_width - subtract)
95
96
                        if current_col_width <= MIN_COL_WIDTH:
97
                            # Make sure column width is always grater than MIN_COL_WIDTH
98
                            current_col_width = MIN_COL_WIDTH
99
                    else:
100
                        current_col_width = col_width
101
102
                widths.append(current_col_width)
103
104
        if not attributes or 'all' in attributes:
105
            entries = list(entries) if entries else []
106
107
            if len(entries) >= 1:
108
                attributes = entries[0].__dict__.keys()
109
                attributes = sorted([attr for attr in attributes if not attr.startswith('_')])
110
            else:
111
                # There are no entries so we can't infer available attributes
112
                attributes = []
113
114
        # Determine table format.
115
        if len(attributes) == len(widths):
116
            # Customize width for each column.
117
            columns = zip(attributes, widths)
118
        else:
119
            # If only 1 width value is provided then
120
            # apply it to all columns else fix at 28.
121
            width = widths[0] if len(widths) == 1 else 28
122
            columns = zip(attributes,
123
                          [width for i in range(0, len(attributes))])
124
125
        # Format result to table.
126
        table = PrettyTable()
127
        for column in columns:
128
            table.field_names.append(column[0])
129
            table.max_width[column[0]] = column[1]
130
        table.padding_width = 1
131
        table.align = 'l'
132
        table.valign = 't'
133
        for entry in entries:
134
            # TODO: Improve getting values of nested dict.
135
            values = []
136
            for field_name in table.field_names:
137
                if '.' in field_name:
138
                    field_names = field_name.split('.')
139
                    value = getattr(entry, field_names.pop(0), {})
140
                    for name in field_names:
141
                        value = cls._get_field_value(value, name)
142
                        if type(value) is str:
143
                            break
144
                    value = strutil.strip_carriage_returns(strutil.unescape(value))
145
                    values.append(value)
146
                else:
147
                    value = cls._get_simple_field_value(entry, field_name)
148
                    transform_function = attribute_transform_functions.get(field_name,
149
                                                                           lambda value: value)
150
                    value = transform_function(value=value)
151
                    value = strutil.strip_carriage_returns(strutil.unescape(value))
152
                    values.append(value)
153
            table.add_row(values)
154
155
        # width for the note
156
        try:
157
            cls.table_width = len(table.get_string().split("\n")[0])
158
        except IndexError:
159
            cls.table_width = 0
160
161
        return table
162
163
    @property
164
    def table_width(self):
165
        return self._table_width
166
167
    @table_width.setter
168
    def table_width(self, value):
169
        self._table_width = value
170
171
    @staticmethod
172
    def _get_simple_field_value(entry, field_name):
173
        """
174
        Format a value for a simple field.
175
        """
176
        value = getattr(entry, field_name, '')
177
        if isinstance(value, (list, tuple)):
178
            if len(value) == 0:
179
                value = ''
180
            elif isinstance(value[0], (str, unicode)):
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'unicode'
Loading history...
181
                # List contains simple string values, format it as comma
182
                # separated string
183
                value = ', '.join(value)
184
185
        return value
186
187
    @staticmethod
188
    def _get_field_value(value, field_name):
189
        r_val = value.get(field_name, None)
190
        if r_val is None:
191
            return ''
192
193
        if isinstance(r_val, list) or isinstance(r_val, dict):
194
            return r_val if len(r_val) > 0 else ''
195
        return r_val
196
197
    @staticmethod
198
    def _get_friendly_column_name(name):
199
        if not name:
200
            return None
201
202
        friendly_name = name.replace('_', ' ').replace('.', ' ').capitalize()
203
        return friendly_name
204
205
    @staticmethod
206
    def _get_required_column_width(values, minimum_width=0):
207
        max_width = len(max(values, key=len)) if values else minimum_width
208
        return max_width if max_width > minimum_width else minimum_width
209
210
211
class PropertyValueTable(formatters.Formatter):
212
213
    @classmethod
214
    def format(cls, subject, *args, **kwargs):
215
        attributes = kwargs.get('attributes', None)
216
        attribute_display_order = kwargs.get('attribute_display_order',
217
                                             DEFAULT_ATTRIBUTE_DISPLAY_ORDER)
218
        attribute_transform_functions = kwargs.get('attribute_transform_functions', {})
219
220
        if not attributes or 'all' in attributes:
221
            attributes = sorted([attr for attr in subject.__dict__
222
                                 if not attr.startswith('_')])
223
224
        for attr in attribute_display_order[::-1]:
225
            if attr in attributes:
226
                attributes.remove(attr)
227
                attributes = [attr] + attributes
228
        table = PrettyTable()
229
        table.field_names = ['Property', 'Value']
230
        table.max_width['Property'] = 20
231
        table.max_width['Value'] = 60
232
        table.padding_width = 1
233
        table.align = 'l'
234
        table.valign = 't'
235
236
        for attribute in attributes:
237
            if '.' in attribute:
238
                field_names = attribute.split('.')
239
                value = cls._get_attribute_value(subject, field_names.pop(0))
240
                for name in field_names:
241
                    value = cls._get_attribute_value(value, name)
242
                    if type(value) is str:
243
                        break
244
            else:
245
                value = cls._get_attribute_value(subject, attribute)
246
247
            transform_function = attribute_transform_functions.get(attribute,
248
                                                                   lambda value: value)
249
            value = transform_function(value=value)
250
251
            if type(value) is dict or type(value) is list:
252
                value = json.dumps(value, indent=4)
253
254
            value = strutil.strip_carriage_returns(strutil.unescape(value))
255
            table.add_row([attribute, value])
256
        return table
257
258
    @staticmethod
259
    def _get_attribute_value(subject, attribute):
260
        if isinstance(subject, dict):
261
            r_val = subject.get(attribute, None)
262
        else:
263
            r_val = getattr(subject, attribute, None)
264
        if r_val is None:
265
            return ''
266
        if isinstance(r_val, list) or isinstance(r_val, dict):
267
            return r_val if len(r_val) > 0 else ''
268
        return r_val
269
270
271
class SingleRowTable(object):
272
    @staticmethod
273
    def note_box(entity, limit):
274
        if limit == 0:
275
            return None
276
        elif limit == 1:
277
            message = "Note: Only one %s is displayed. Use -n/--last flag for more results." \
278
                % entity[:-1]
279
        else:
280
            message = "Note: Only first %s %s are displayed. Use -n/--last flag for more" \
281
                " results." % (limit, entity)
282
        # adding default padding
283
        message_length = len(message) + 3
284
        m = MultiColumnTable()
285
        if m.table_width > message_length:
286
            note = PrettyTable([""], right_padding_width=(m.table_width - message_length))
287
        else:
288
            note = PrettyTable([""])
289
        note.header = False
290
        note.add_row([message])
291
        return sys.stderr.write(str(note) + "\n")
292