import re import reason_qualifier # pylint: disable=missing-docstring color_map = { 'header' : '#e5e5c0', # greyish yellow 'blank' : '#ffffff', # white 'plain_text' : '#e5e5c0', # greyish yellow 'borders' : '#bbbbbb', # grey 'white' : '#ffffff', # white 'green' : '#66ff66', # green 'yellow' : '#fffc00', # yellow 'red' : '#ff6666', # red #### additional keys for shaded color of a box #### depending on stats of GOOD/FAIL '100pct' : '#32CD32', # green, 94% to 100% of success '95pct' : '#c0ff80', # step twrds yellow, 88% to 94% of success '90pct' : '#ffff00', # yellow, 82% to 88% '85pct' : '#ffc040', # 76% to 82% '75pct' : '#ff4040', # red, 1% to 76% '0pct' : '#d080d0', # violet, <1% of success } _brief_mode = False def set_brief_mode(): global _brief_mode _brief_mode = True def is_brief_mode(): return _brief_mode def color_keys_row(): """ Returns one row table with samples of 'NNpct' colors defined in the color_map and numbers of corresponding %% """ ### This function does not require maintenance in case of ### color_map augmenting - as long as ### color keys for box shading have names that end with 'pct' keys = filter(lambda key: key.endswith('pct'), color_map.keys()) def num_pct(key): return int(key.replace('pct','')) keys.sort(key=num_pct) html = '' for key in keys: html+= "\t\t\t   \n"\ % color_map[key] hint = key.replace('pct',' %') if hint[0]<>'0': ## anything but 0 % hint = 'to ' + hint html+= "\t\t\t %s \n" % hint html = """ \n \n \n %s \n

""" % html return html def calculate_html(link, data, tooltip=None, row_label=None, column_label=None): if not is_brief_mode(): hover_text = '%s:%s' % (row_label, column_label) if data: ## cell is not empty hover_text += '
%s' % tooltip else: ## avoid "None" printed in empty cells data = ' ' html = ('
' '%s%s
' % (link, data, hover_text)) return html # no hover if embedded into AFE but links shall redirect to new window if data: ## cell is non empty html = '%s' % (link, data) return html else: ## cell is empty return ' ' class box: def __init__(self, data, color_key = None, header = False, link = None, tooltip = None, row_label = None, column_label = None): ## in brief mode we display grid table only and nothing more ## - mouse hovering feature is stubbed in brief mode ## - any link opens new window or tab redirect = "" if is_brief_mode(): ## we are acting under AFE ## any link shall open new window redirect = " target=NEW" if data: data = "%s" % data if link and not tooltip: ## FlipAxis corner, column and row headers self.data = ('%s' % (link, redirect, data)) else: self.data = calculate_html(link, data, tooltip, row_label, column_label) if color_map.has_key(color_key): self.color = color_map[color_key] elif header: self.color = color_map['header'] elif data: self.color = color_map['plain_text'] else: self.color = color_map['blank'] self.header = header def html(self): if self.data: data = self.data else: data = ' ' if self.header: box_html = 'th' else: box_html = 'td' return "<%s bgcolor=%s>%s" % \ (box_html, self.color, data, box_html) def grade_from_status(status_idx, status): # % of goodness # GOOD (6) -> 1 # TEST_NA (8) is not counted # ## If the test doesn't PASS, it FAILS # else -> 0 if status == status_idx['GOOD']: return 1.0 else: return 0.0 def average_grade_from_status_count(status_idx, status_count): average_grade = 0 total_count = 0 for key in status_count.keys(): if key not in (status_idx['TEST_NA'], status_idx['RUNNING']): average_grade += (grade_from_status(status_idx, key) * status_count[key]) total_count += status_count[key] if total_count != 0: average_grade = average_grade / total_count else: average_grade = 0.0 return average_grade def shade_from_status_count(status_idx, status_count): if not status_count: return None ## average_grade defines a shade of the box ## 0 -> violet ## 0.76 -> red ## 0.88-> yellow ## 1.0 -> green average_grade = average_grade_from_status_count(status_idx, status_count) ## find appropiate keyword from color_map if average_grade<0.01: shade = '0pct' elif average_grade<0.75: shade = '75pct' elif average_grade<0.85: shade = '85pct' elif average_grade<0.90: shade = '90pct' elif average_grade<0.95: shade = '95pct' else: shade = '100pct' return shade def status_html(db, box_data, shade): """ status_count: dict mapping from status (integer key) to count eg. { 'GOOD' : 4, 'FAIL' : 1 } """ status_count_subset = box_data.status_count.copy() test_na = db.status_idx['TEST_NA'] running = db.status_idx['RUNNING'] good = db.status_idx['GOOD'] status_count_subset[test_na] = 0 # Don't count TEST_NA status_count_subset[running] = 0 # Don't count RUNNING html = "%d / %d " % (status_count_subset.get(good, 0), sum(status_count_subset.values())) if test_na in box_data.status_count.keys(): html += ' (%d N/A)' % box_data.status_count[test_na] if running in box_data.status_count.keys(): html += ' (%d running)' % box_data.status_count[running] if box_data.reasons_list: reasons_list = box_data.reasons_list aggregated_reasons_list = \ reason_qualifier.aggregate_reason_fields(reasons_list) for reason in aggregated_reasons_list: ## a bit of more postprocessing ## to look nicer in a cell ## in future: to do subtable within the cell reason = reason.replace('
','\n') reason = reason.replace('<','[').replace('>',']') reason = reason.replace('|','\n').replace('&',' AND ') reason = reason.replace('\n','
') html += '
' + reason tooltip = "" for status in sorted(box_data.status_count.keys(), reverse = True): status_word = db.status_word[status] tooltip += "%d %s " % (box_data.status_count[status], status_word) return (html,tooltip) def status_count_box(db, tests, link = None): """ Display a ratio of total number of GOOD tests to total number of all tests in the group of tests. More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips """ if not tests: return box(None, None) status_count = {} for test in tests: count = status_count.get(test.status_num, 0) status_count[test.status_num] = count + 1 return status_precounted_box(db, status_count, link) def status_precounted_box(db, box_data, link = None, x_label = None, y_label = None): """ Display a ratio of total number of GOOD tests to total number of all tests in the group of tests. More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips """ status_count = box_data.status_count if not status_count: return box(None, None) shade = shade_from_status_count(db.status_idx, status_count) html,tooltip = status_html(db, box_data, shade) precounted_box = box(html, shade, False, link, tooltip, x_label, y_label) return precounted_box def print_table(matrix): """ matrix: list of lists of boxes, giving a matrix of data Each of the inner lists is a row, not a column. Display the given matrix of data as a table. """ print ('') % ( color_map['borders']) for row in matrix: print '' for element in row: print element.html() print '' print '
' def print_main_header(): hover_css="""\ a.info{ position:relative; /*this is the key*/ z-index:1 color:#000; text-decoration:none} a.info:hover{z-index:25;} a.info span{display: none} a.info:hover span{ /*the span will display just on :hover state*/ display:block; position:absolute; top:1em; left:1em; min-width: 100px; overflow: visible; border:1px solid #036; background-color:#fff; color:#000; text-align: left } """ print '' print '

' print 'Functional' print '   ' def group_name(group): name = re.sub('_', '
', group.name) if re.search('/', name): (owner, machine) = name.split('/', 1) name = owner + '
' + machine return name