Path: blob/master/modules/ts/misc/table_formatter.py
16339 views
#!/usr/bin/env python12from __future__ import print_function3import sys, re, os.path, cgi, stat, math4from optparse import OptionParser5from color import getColorizer, dummyColorizer67class tblCell(object):8def __init__(self, text, value = None, props = None):9self.text = text10self.value = value11self.props = props1213class tblColumn(object):14def __init__(self, caption, title = None, props = None):15self.text = caption16self.title = title17self.props = props1819class tblRow(object):20def __init__(self, colsNum, props = None):21self.cells = [None] * colsNum22self.props = props2324def htmlEncode(str):25return '<br/>'.join([cgi.escape(s) for s in str])2627class table(object):28def_align = "left"29def_valign = "middle"30def_color = None31def_colspan = 132def_rowspan = 133def_bold = False34def_italic = False35def_text="-"3637def __init__(self, caption = None, format=None):38self.format = format39self.is_markdown = self.format == 'markdown'40self.columns = {}41self.rows = []42self.ridx = -1;43self.caption = caption44pass4546def newRow(self, **properties):47if len(self.rows) - 1 == self.ridx:48self.rows.append(tblRow(len(self.columns), properties))49else:50self.rows[self.ridx + 1].props = properties51self.ridx += 152return self.rows[self.ridx]5354def trimLastRow(self):55if self.rows:56self.rows.pop()57if self.ridx >= len(self.rows):58self.ridx = len(self.rows) - 15960def newColumn(self, name, caption, title = None, **properties):61if name in self.columns:62index = self.columns[name].index63else:64index = len(self.columns)65if isinstance(caption, tblColumn):66caption.index = index67self.columns[name] = caption68return caption69else:70col = tblColumn(caption, title, properties)71col.index = index72self.columns[name] = col73return col7475def getColumn(self, name):76if isinstance(name, str):77return self.columns.get(name, None)78else:79vals = [v for v in self.columns.values() if v.index == name]80if vals:81return vals[0]82return None8384def newCell(self, col_name, text, value = None, **properties):85if self.ridx < 0:86self.newRow()87col = self.getColumn(col_name)88row = self.rows[self.ridx]89if not col:90return None91if isinstance(text, tblCell):92cl = text93else:94cl = tblCell(text, value, properties)95row.cells[col.index] = cl96return cl9798def layoutTable(self):99columns = self.columns.values()100columns = sorted(columns, key=lambda c: c.index)101102colspanned = []103rowspanned = []104105self.headerHeight = 1106rowsToAppend = 0107108for col in columns:109self.measureCell(col)110if col.height > self.headerHeight:111self.headerHeight = col.height112col.minwidth = col.width113col.line = None114115for r in range(len(self.rows)):116row = self.rows[r]117row.minheight = 1118for i in range(len(row.cells)):119cell = row.cells[i]120if row.cells[i] is None:121continue122cell.line = None123self.measureCell(cell)124colspan = int(self.getValue("colspan", cell))125rowspan = int(self.getValue("rowspan", cell))126if colspan > 1:127colspanned.append((r,i))128if i + colspan > len(columns):129colspan = len(columns) - i130cell.colspan = colspan131#clear spanned cells132for j in range(i+1, min(len(row.cells), i + colspan)):133row.cells[j] = None134elif columns[i].minwidth < cell.width:135columns[i].minwidth = cell.width136if rowspan > 1:137rowspanned.append((r,i))138rowsToAppend2 = r + colspan - len(self.rows)139if rowsToAppend2 > rowsToAppend:140rowsToAppend = rowsToAppend2141cell.rowspan = rowspan142#clear spanned cells143for j in range(r+1, min(len(self.rows), r + rowspan)):144if len(self.rows[j].cells) > i:145self.rows[j].cells[i] = None146elif row.minheight < cell.height:147row.minheight = cell.height148149self.ridx = len(self.rows) - 1150for r in range(rowsToAppend):151self.newRow()152self.rows[len(self.rows) - 1].minheight = 1153154while colspanned:155colspanned_new = []156for r, c in colspanned:157cell = self.rows[r].cells[c]158sum([col.minwidth for col in columns[c:c + cell.colspan]])159cell.awailable = sum([col.minwidth for col in columns[c:c + cell.colspan]]) + cell.colspan - 1160if cell.awailable < cell.width:161colspanned_new.append((r,c))162colspanned = colspanned_new163if colspanned:164r,c = colspanned[0]165cell = self.rows[r].cells[c]166cols = columns[c:c + cell.colspan]167total = cell.awailable - cell.colspan + 1168budget = cell.width - cell.awailable169spent = 0170s = 0171for col in cols:172s += col.minwidth173addition = s * budget / total - spent174spent += addition175col.minwidth += addition176177while rowspanned:178rowspanned_new = []179for r, c in rowspanned:180cell = self.rows[r].cells[c]181cell.awailable = sum([row.minheight for row in self.rows[r:r + cell.rowspan]])182if cell.awailable < cell.height:183rowspanned_new.append((r,c))184rowspanned = rowspanned_new185if rowspanned:186r,c = rowspanned[0]187cell = self.rows[r].cells[c]188rows = self.rows[r:r + cell.rowspan]189total = cell.awailable190budget = cell.height - cell.awailable191spent = 0192s = 0193for row in rows:194s += row.minheight195addition = s * budget / total - spent196spent += addition197row.minheight += addition198199return columns200201def measureCell(self, cell):202text = self.getValue("text", cell)203cell.text = self.reformatTextValue(text)204cell.height = len(cell.text)205cell.width = len(max(cell.text, key = lambda line: len(line)))206207def reformatTextValue(self, value):208if sys.version_info >= (2,7):209unicode = str210if isinstance(value, str):211vstr = value212elif isinstance(value, unicode):213vstr = str(value)214else:215try:216vstr = '\n'.join([str(v) for v in value])217except TypeError:218vstr = str(value)219return vstr.splitlines()220221def adjustColWidth(self, cols, width):222total = sum([c.minWidth for c in cols])223if total + len(cols) - 1 >= width:224return225budget = width - len(cols) + 1 - total226spent = 0227s = 0228for col in cols:229s += col.minWidth230addition = s * budget / total - spent231spent += addition232col.minWidth += addition233234def getValue(self, name, *elements):235for el in elements:236try:237return getattr(el, name)238except AttributeError:239pass240try:241val = el.props[name]242if val:243return val244except AttributeError:245pass246except KeyError:247pass248try:249return getattr(self.__class__, "def_" + name)250except AttributeError:251return None252253def consolePrintTable(self, out):254columns = self.layoutTable()255colrizer = getColorizer(out) if not self.is_markdown else dummyColorizer(out)256257if self.caption:258out.write("%s%s%s" % ( os.linesep, os.linesep.join(self.reformatTextValue(self.caption)), os.linesep * 2))259260headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True})261headerRow.cells = columns262headerRow.minheight = self.headerHeight263264self.consolePrintRow2(colrizer, headerRow, columns)265266for i in range(0, len(self.rows)):267self.consolePrintRow2(colrizer, i, columns)268269def consolePrintRow2(self, out, r, columns):270if isinstance(r, tblRow):271row = r272r = -1273else:274row = self.rows[r]275276#evaluate initial values for line numbers277i = 0278while i < len(row.cells):279cell = row.cells[i]280colspan = self.getValue("colspan", cell)281if cell is not None:282cell.wspace = sum([col.minwidth for col in columns[i:i + colspan]]) + colspan - 1283if cell.line is None:284if r < 0:285rows = [row]286else:287rows = self.rows[r:r + self.getValue("rowspan", cell)]288cell.line = self.evalLine(cell, rows, columns[i])289if len(rows) > 1:290for rw in rows:291rw.cells[i] = cell292i += colspan293294#print content295if self.is_markdown:296out.write("|")297for c in row.cells:298text = ' '.join(self.getValue('text', c) or [])299out.write(text + "|")300out.write(os.linesep)301else:302for ln in range(row.minheight):303i = 0304while i < len(row.cells):305if i > 0:306out.write(" ")307cell = row.cells[i]308column = columns[i]309if cell is None:310out.write(" " * column.minwidth)311i += 1312else:313self.consolePrintLine(cell, row, column, out)314i += self.getValue("colspan", cell)315if self.is_markdown:316out.write("|")317out.write(os.linesep)318319if self.is_markdown and row.props.get('header', False):320out.write("|")321for th in row.cells:322align = self.getValue("align", th)323if align == 'center':324out.write(":-:|")325elif align == 'right':326out.write("--:|")327else:328out.write("---|")329out.write(os.linesep)330331def consolePrintLine(self, cell, row, column, out):332if cell.line < 0 or cell.line >= cell.height:333line = ""334else:335line = cell.text[cell.line]336width = cell.wspace337align = self.getValue("align", ((None, cell)[isinstance(cell, tblCell)]), row, column)338339if align == "right":340pattern = "%" + str(width) + "s"341elif align == "center":342pattern = "%" + str((width - len(line)) // 2 + len(line)) + "s" + " " * (width - len(line) - (width - len(line)) // 2)343else:344pattern = "%-" + str(width) + "s"345346out.write(pattern % line, color = self.getValue("color", cell, row, column))347cell.line += 1348349def evalLine(self, cell, rows, column):350height = cell.height351valign = self.getValue("valign", cell, rows[0], column)352space = sum([row.minheight for row in rows])353if valign == "bottom":354return height - space355if valign == "middle":356return (height - space + 1) // 2357return 0358359def htmlPrintTable(self, out, embeedcss = False):360columns = self.layoutTable()361362if embeedcss:363out.write("<div style=\"font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;\">\n<table style=\"background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:'Lucida Sans Unicode','Lucida Grande',Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;\">\n")364else:365out.write("<div class=\"tableFormatter\">\n<table class=\"tbl\">\n")366if self.caption:367if embeedcss:368out.write(" <caption style=\"font:italic 16px 'Trebuchet MS',Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;\">%s</caption>\n" % htmlEncode(self.reformatTextValue(self.caption)))369else:370out.write(" <caption>%s</caption>\n" % htmlEncode(self.reformatTextValue(self.caption)))371out.write(" <thead>\n")372373headerRow = tblRow(len(columns), {"align": "center", "valign": "top", "bold": True, "header": True})374headerRow.cells = columns375376header_rows = [headerRow]377header_rows.extend([row for row in self.rows if self.getValue("header")])378last_row = header_rows[len(header_rows) - 1]379380for row in header_rows:381out.write(" <tr>\n")382for th in row.cells:383align = self.getValue("align", ((None, th)[isinstance(th, tblCell)]), row, row)384valign = self.getValue("valign", th, row)385cssclass = self.getValue("cssclass", th)386attr = ""387if align:388attr += " align=\"%s\"" % align389if valign:390attr += " valign=\"%s\"" % valign391if cssclass:392attr += " class=\"%s\"" % cssclass393css = ""394if embeedcss:395css = " style=\"border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;\""396if row == last_row:397css = css[:-1] + "padding-bottom:5px;\""398out.write(" <th%s%s>\n" % (attr, css))399if th is not None:400out.write(" %s\n" % htmlEncode(th.text))401out.write(" </th>\n")402out.write(" </tr>\n")403404out.write(" </thead>\n <tbody>\n")405406rows = [row for row in self.rows if not self.getValue("header")]407for r in range(len(rows)):408row = rows[r]409rowattr = ""410cssclass = self.getValue("cssclass", row)411if cssclass:412rowattr += " class=\"%s\"" % cssclass413out.write(" <tr%s>\n" % (rowattr))414i = 0415while i < len(row.cells):416column = columns[i]417td = row.cells[i]418if isinstance(td, int):419i += td420continue421colspan = self.getValue("colspan", td)422rowspan = self.getValue("rowspan", td)423align = self.getValue("align", td, row, column)424valign = self.getValue("valign", td, row, column)425color = self.getValue("color", td, row, column)426bold = self.getValue("bold", td, row, column)427italic = self.getValue("italic", td, row, column)428style = ""429attr = ""430if color:431style += "color:%s;" % color432if bold:433style += "font-weight: bold;"434if italic:435style += "font-style: italic;"436if align and align != "left":437attr += " align=\"%s\"" % align438if valign and valign != "middle":439attr += " valign=\"%s\"" % valign440if colspan > 1:441attr += " colspan=\"%s\"" % colspan442if rowspan > 1:443attr += " rowspan=\"%s\"" % rowspan444for q in range(r+1, min(r+rowspan, len(rows))):445rows[q].cells[i] = colspan446if style:447attr += " style=\"%s\"" % style448css = ""449if embeedcss:450css = " style=\"border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;\""451if r == 0:452css = css[:-1] + "border-top:2px solid #6678B1;\""453out.write(" <td%s%s>\n" % (attr, css))454if td is not None:455out.write(" %s\n" % htmlEncode(td.text))456out.write(" </td>\n")457i += colspan458out.write(" </tr>\n")459460out.write(" </tbody>\n</table>\n</div>\n")461462def htmlPrintHeader(out, title = None):463if title:464titletag = "<title>%s</title>\n" % htmlEncode([str(title)])465else:466titletag = ""467out.write("""<!DOCTYPE HTML>468<html>469<head>470<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">471%s<style type="text/css">472html, body {font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;}473.tbl{background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:"Lucida Sans Unicode","Lucida Grande",Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;}474.tbl span{display:block;white-space:nowrap;}475.tbl thead tr:last-child th {padding-bottom:5px;}476.tbl tbody tr:first-child td {border-top:3px solid #6678B1;}477.tbl th{border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;}478.tbl td{border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;}479.tbl tbody tr:hover td{color:#000099;}480.tbl caption{font:italic 16px "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;}481.firstingroup {border-top:2px solid #6678B1;}482</style>483<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>484<script type="text/javascript">485function abs(val) { return val < 0 ? -val : val }486$(function(){487//generate filter rows488$("div.tableFormatter table.tbl").each(function(tblIdx, tbl) {489var head = $("thead", tbl)490var filters = $("<tr></tr>")491var hasAny = false492$("tr:first th", head).each(function(colIdx, col) {493col = $(col)494var cell495var id = "t" + tblIdx + "r" + colIdx496if (col.hasClass("col_name")){497cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_name' title='Regular expression for name filtering ("resize.*640x480" - resize tests on VGA resolution)'></input></th>")498hasAny = true499}500else if (col.hasClass("col_rel")){501cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_rel' title='Filter out lines with a x-factor of acceleration less than Nx'></input></th>")502hasAny = true503}504else if (col.hasClass("col_cr")){505cell = $("<th><input id='" + id + "' name='" + id + "' type='text' style='width:100%%' class='filter_col_cr' title='Filter out lines with a percentage of acceleration less than N%%'></input></th>")506hasAny = true507}508else509cell = $("<th></th>")510cell.appendTo(filters)511})512513if (hasAny){514$(tbl).wrap("<form id='form_t" + tblIdx + "' method='get' action=''></form>")515$("<input it='test' type='submit' value='Apply Filters' style='margin-left:10px;'></input>")516.appendTo($("th:last", filters.appendTo(head)))517}518})519520//get filter values521var vars = []522var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&')523for(var i = 0; i < hashes.length; ++i)524{525hash = hashes[i].split('=')526vars.push(decodeURIComponent(hash[0]))527vars[decodeURIComponent(hash[0])] = decodeURIComponent(hash[1]);528}529530//set filter values531for(var i = 0; i < vars.length; ++i)532$("#" + vars[i]).val(vars[vars[i]])533534//apply filters535$("div.tableFormatter table.tbl").each(function(tblIdx, tbl) {536filters = $("input:text", tbl)537var predicate = function(row) {return true;}538var empty = true539$.each($("input:text", tbl), function(i, flt) {540flt = $(flt)541var val = flt.val()542var pred = predicate;543if(val) {544empty = false545var colIdx = parseInt(flt.attr("id").slice(flt.attr("id").indexOf('r') + 1))546if(flt.hasClass("filter_col_name")) {547var re = new RegExp(val);548predicate = function(row) {549if (re.exec($(row.get(colIdx)).text()) == null)550return false551return pred(row)552}553} else if(flt.hasClass("filter_col_rel")) {554var percent = parseFloat(val)555if (percent < 0) {556predicate = function(row) {557var val = parseFloat($(row.get(colIdx)).text())558if (!val || val >= 1 || val > 1+percent)559return false560return pred(row)561}562} else {563predicate = function(row) {564var val = parseFloat($(row.get(colIdx)).text())565if (!val || val < percent)566return false567return pred(row)568}569}570} else if(flt.hasClass("filter_col_cr")) {571var percent = parseFloat(val)572predicate = function(row) {573var val = parseFloat($(row.get(colIdx)).text())574if (!val || val < percent)575return false576return pred(row)577}578}579}580});581if (!empty){582$("tbody tr", tbl).each(function (i, tbl_row) {583if(!predicate($("td", tbl_row)))584$(tbl_row).remove()585})586if($("tbody tr", tbl).length == 0) {587$("<tr><td colspan='"+$("thead tr:first th", tbl).length+"'>No results mathing your search criteria</td></tr>")588.appendTo($("tbody", tbl))589}590}591})592})593</script>594</head>595<body>596""" % titletag)597598def htmlPrintFooter(out):599out.write("</body>\n</html>")600601def getStdoutFilename():602try:603if os.name == "nt":604import msvcrt, ctypes605handle = msvcrt.get_osfhandle(sys.stdout.fileno())606size = ctypes.c_ulong(1024)607nameBuffer = ctypes.create_string_buffer(size.value)608ctypes.windll.kernel32.GetFinalPathNameByHandleA(handle, nameBuffer, size, 4)609return nameBuffer.value610else:611return os.readlink('/proc/self/fd/1')612except:613return ""614615def detectHtmlOutputType(requestedType):616if requestedType in ['txt', 'markdown']:617return False618elif requestedType in ["html", "moinwiki"]:619return True620else:621if sys.stdout.isatty():622return False623else:624outname = getStdoutFilename()625if outname:626if outname.endswith(".htm") or outname.endswith(".html"):627return True628else:629return False630else:631return False632633def getRelativeVal(test, test0, metric):634if not test or not test0:635return None636val0 = test0.get(metric, "s")637if not val0:638return None639val = test.get(metric, "s")640if not val or val == 0:641return None642return float(val0)/val643644def getCycleReduction(test, test0, metric):645if not test or not test0:646return None647val0 = test0.get(metric, "s")648if not val0 or val0 == 0:649return None650val = test.get(metric, "s")651if not val:652return None653return (1.0-float(val)/val0)*100654655def getScore(test, test0, metric):656if not test or not test0:657return None658m0 = float(test.get("gmean", None))659m1 = float(test0.get("gmean", None))660if m0 == 0 or m1 == 0:661return None662s0 = float(test.get("gstddev", None))663s1 = float(test0.get("gstddev", None))664s = math.sqrt(s0*s0 + s1*s1)665m0 = math.log(m0)666m1 = math.log(m1)667if s == 0:668return None669return (m0-m1)/s670671metrix_table = \672{673"name": ("Name of Test", lambda test,test0,units: str(test)),674675"samples": ("Number of\ncollected samples", lambda test,test0,units: test.get("samples", units)),676"outliers": ("Number of\noutliers", lambda test,test0,units: test.get("outliers", units)),677678"gmean": ("Geometric mean", lambda test,test0,units: test.get("gmean", units)),679"mean": ("Mean", lambda test,test0,units: test.get("mean", units)),680"min": ("Min", lambda test,test0,units: test.get("min", units)),681"median": ("Median", lambda test,test0,units: test.get("median", units)),682"stddev": ("Standard deviation", lambda test,test0,units: test.get("stddev", units)),683"gstddev": ("Standard deviation of Ln(time)", lambda test,test0,units: test.get("gstddev")),684685"gmean%": ("Geometric mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gmean")),686"mean%": ("Mean (relative)", lambda test,test0,units: getRelativeVal(test, test0, "mean")),687"min%": ("Min (relative)", lambda test,test0,units: getRelativeVal(test, test0, "min")),688"median%": ("Median (relative)", lambda test,test0,units: getRelativeVal(test, test0, "median")),689"stddev%": ("Standard deviation (relative)", lambda test,test0,units: getRelativeVal(test, test0, "stddev")),690"gstddev%": ("Standard deviation of Ln(time) (relative)", lambda test,test0,units: getRelativeVal(test, test0, "gstddev")),691692"gmean$": ("Geometric mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gmean")),693"mean$": ("Mean (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "mean")),694"min$": ("Min (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "min")),695"median$": ("Median (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "median")),696"stddev$": ("Standard deviation (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "stddev")),697"gstddev$": ("Standard deviation of Ln(time) (cycle reduction)", lambda test,test0,units: getCycleReduction(test, test0, "gstddev")),698699"score": ("SCORE", lambda test,test0,units: getScore(test, test0, "gstddev")),700}701702def formatValue(val, metric, units = None):703if val is None:704return "-"705if metric.endswith("%"):706return "%.2f" % val707if metric.endswith("$"):708return "%.2f%%" % val709if metric.endswith("S"):710if val > 3.5:711return "SLOWER"712if val < -3.5:713return "FASTER"714if val > -1.5 and val < 1.5:715return " "716if val < 0:717return "faster"718if val > 0:719return "slower"720#return "%.4f" % val721if units:722return "%.3f %s" % (val, units)723else:724return "%.3f" % val725726if __name__ == "__main__":727if len(sys.argv) < 2:728print("Usage:\n", os.path.basename(sys.argv[0]), "<log_name>.xml")729exit(0)730731parser = OptionParser()732parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html', 'markdown' or 'auto' - default)", metavar="FMT", default="auto")733parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean")734parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), us, ns or ticks)", metavar="UNITS", default="ms")735(options, args) = parser.parse_args()736737options.generateHtml = detectHtmlOutputType(options.format)738if options.metric not in metrix_table:739options.metric = "gmean"740741#print options742#print args743744# tbl = table()745# tbl.newColumn("first", "qqqq", align = "left")746# tbl.newColumn("second", "wwww\nz\nx\n")747# tbl.newColumn("third", "wwasdas")748#749# tbl.newCell(0, "ccc111", align = "right")750# tbl.newCell(1, "dddd1")751# tbl.newCell(2, "8768756754")752# tbl.newRow()753# tbl.newCell(0, "1\n2\n3\n4\n5\n6\n7", align = "center", colspan = 2, rowspan = 2)754# tbl.newCell(2, "xxx\nqqq", align = "center", colspan = 1, valign = "middle")755# tbl.newRow()756# tbl.newCell(2, "+", align = "center", colspan = 1, valign = "middle")757# tbl.newRow()758# tbl.newCell(0, "vcvvbasdsadassdasdasv", align = "right", colspan = 2)759# tbl.newCell(2, "dddd1")760# tbl.newRow()761# tbl.newCell(0, "vcvvbv")762# tbl.newCell(1, "3445324", align = "right")763# tbl.newCell(2, None)764# tbl.newCell(1, "0000")765# if sys.stdout.isatty():766# tbl.consolePrintTable(sys.stdout)767# else:768# htmlPrintHeader(sys.stdout)769# tbl.htmlPrintTable(sys.stdout)770# htmlPrintFooter(sys.stdout)771772import testlog_parser773774if options.generateHtml:775htmlPrintHeader(sys.stdout, "Tables demo")776777getter = metrix_table[options.metric][1]778779for arg in args:780tests = testlog_parser.parseLogFile(arg)781tbl = table(arg, format=options.format)782tbl.newColumn("name", "Name of Test", align = "left")783tbl.newColumn("value", metrix_table[options.metric][0], align = "center", bold = "true")784785for t in sorted(tests):786tbl.newRow()787tbl.newCell("name", str(t))788789status = t.get("status")790if status != "run":791tbl.newCell("value", status)792else:793val = getter(t, None, options.units)794if val:795if options.metric.endswith("%"):796tbl.newCell("value", "%.2f" % val, val)797else:798tbl.newCell("value", "%.3f %s" % (val, options.units), val)799else:800tbl.newCell("value", "-")801802if options.generateHtml:803tbl.htmlPrintTable(sys.stdout)804else:805tbl.consolePrintTable(sys.stdout)806807if options.generateHtml:808htmlPrintFooter(sys.stdout)809810811