Interspersed precent/notes in measurement scripts

This is a bit more complicated, but make testmarks really showed how
confusing this could get.

Now, instead of:

  suite                             passed    time
  test_alloc                       304/304     1.6 (100.0%)
  test_badblocks                 6880/6880  1323.3 (100.0%)
  ... snip ...
  test_rbyd                  385878/385878   592.7 (100.0%)
  test_relocations               7899/7899   318.8 (100.0%)
  TOTAL                      548206/548206  6229.7 (100.0%)

Percents/notes are interspersed next to their relevant fields:

  suite                             passed             time
  test_alloc                       304/304 (100.0%)     1.6
  test_badblocks                 6880/6880 (100.0%)  1323.3
  ... snip ...
  test_rbyd                  385878/385878 (100.0%)   592.7
  test_relocations               7899/7899 (100.0%)   318.8
  TOTAL                      548206/548206 (100.0%)  6229.7

Note has no effect on scripts with only a single field (code.py, etc).

But it does make multi-field diffs a bit more readable:

  $ ./scripts/stack.py -u after.stack.csv -d before.stack.csv -p
  function                       frame             limit
  lfsr_bd_sync                       8 (+100.0%)     216 (+100.0%)
  lfsr_bd_flush                     40 (+25.0%)      208 (+4.0%)
  ... snip ...
  lfsr_file_flush                   32 (+0.0%)      2424 (-0.3%)
  lfsr_file_flush_                 216 (-3.6%)      2392 (-0.3%)
  TOTAL                           9008 (+0.4%)      2600 (-0.3%)
This commit is contained in:
Christopher Haster
2024-06-02 14:40:52 -05:00
parent a231bbac6e
commit 06bfed7a8b
8 changed files with 466 additions and 455 deletions
+52 -51
View File
@@ -399,14 +399,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -420,22 +420,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -446,30 +453,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -496,21 +490,28 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# print our table # print our table
for line in lines: for line in lines:
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
def main(obj_paths, *, def main(obj_paths, *,
+52 -51
View File
@@ -387,14 +387,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -408,22 +408,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -434,30 +441,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -484,21 +478,28 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# print our table # print our table
for line in lines: for line in lines:
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
def annotate(Result, results, *, def annotate(Result, results, *,
+52 -51
View File
@@ -399,14 +399,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -420,22 +420,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -446,30 +453,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -496,21 +490,28 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# print our table # print our table
for line in lines: for line in lines:
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
def main(obj_paths, *, def main(obj_paths, *,
+71 -67
View File
@@ -723,14 +723,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -744,22 +744,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -770,30 +777,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -820,13 +814,19 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# adjust the name width based on the call depth # adjust the name width based on the call depth
if not summary: if not summary:
@@ -855,11 +855,12 @@ def table(Result, results, diff_results=None, *,
widths[0] += 4*max(depth_-1, 0) widths[0] += 4*max(depth_-1, 0)
# print the tree recursively # print the tree recursively
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[0][0], widths[0], lines[0][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[0][1:-1])), widths[i], x[0],
lines[0][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[0][1:], 1))))
if not summary: if not summary:
def recurse(results_, depth_, prefixes=('', '', '', '')): def recurse(results_, depth_, prefixes=('', '', '', '')):
@@ -887,14 +888,15 @@ def table(Result, results, diff_results=None, *,
r = table_[name] r = table_[name]
is_last = (i == len(names_)-1) is_last = (i == len(names_)-1)
line = table_entry(name, r)
line = [x if isinstance(x, tuple) else (x, []) for x in line]
print('%s%-*s %s' % ( print('%s%-*s %s' % (
prefixes[0+is_last], prefixes[0+is_last],
widths[0] - len(prefixes[0+is_last]), widths[0] - len(prefixes[0+is_last]), line[0][0],
name, ' '.join('%*s%-*s' % (
' '.join('%*s' % (w, x) widths[i], x[0],
for w, x in zip( notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
widths[1:], for i, x in enumerate(line[1:], 1))))
table_entry(name, r)[1:]))))
# recurse? # recurse?
if depth_ > 1: if depth_ > 1:
@@ -909,11 +911,12 @@ def table(Result, results, diff_results=None, *,
# we have enough going on with diffing to make the top layer # we have enough going on with diffing to make the top layer
# a special case # a special case
for name, line in zip(names, lines[1:-1]): for name, line in zip(names, lines[1:-1]):
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
if name in table and depth > 1: if name in table and depth > 1:
recurse( recurse(
@@ -924,11 +927,12 @@ def table(Result, results, diff_results=None, *,
"| ", "| ",
" ")) " "))
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[-1][0], widths[0], lines[-1][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[-1][1:-1])), widths[i], x[0],
lines[-1][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[-1][1:], 1))))
def annotate(Result, results, *, def annotate(Result, results, *,
+71 -67
View File
@@ -687,14 +687,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -708,22 +708,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -734,30 +741,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -784,13 +778,19 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# adjust the name width based on the call depth # adjust the name width based on the call depth
if not summary: if not summary:
@@ -819,11 +819,12 @@ def table(Result, results, diff_results=None, *,
widths[0] += 4*max(depth_-1, 0) widths[0] += 4*max(depth_-1, 0)
# print the tree recursively # print the tree recursively
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[0][0], widths[0], lines[0][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[0][1:-1])), widths[i], x[0],
lines[0][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[0][1:], 1))))
if not summary: if not summary:
def recurse(results_, depth_, prefixes=('', '', '', '')): def recurse(results_, depth_, prefixes=('', '', '', '')):
@@ -851,14 +852,15 @@ def table(Result, results, diff_results=None, *,
r = table_[name] r = table_[name]
is_last = (i == len(names_)-1) is_last = (i == len(names_)-1)
line = table_entry(name, r)
line = [x if isinstance(x, tuple) else (x, []) for x in line]
print('%s%-*s %s' % ( print('%s%-*s %s' % (
prefixes[0+is_last], prefixes[0+is_last],
widths[0] - len(prefixes[0+is_last]), widths[0] - len(prefixes[0+is_last]), line[0][0],
name, ' '.join('%*s%-*s' % (
' '.join('%*s' % (w, x) widths[i], x[0],
for w, x in zip( notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
widths[1:], for i, x in enumerate(line[1:], 1))))
table_entry(name, r)[1:]))))
# recurse? # recurse?
if depth_ > 1: if depth_ > 1:
@@ -873,11 +875,12 @@ def table(Result, results, diff_results=None, *,
# we have enough going on with diffing to make the top layer # we have enough going on with diffing to make the top layer
# a special case # a special case
for name, line in zip(names, lines[1:-1]): for name, line in zip(names, lines[1:-1]):
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
if name in table and depth > 1: if name in table and depth > 1:
recurse( recurse(
@@ -888,11 +891,12 @@ def table(Result, results, diff_results=None, *,
"| ", "| ",
" ")) " "))
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[-1][0], widths[0], lines[-1][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[-1][1:-1])), widths[i], x[0],
lines[-1][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[-1][1:], 1))))
def annotate(Result, results, *, def annotate(Result, results, *,
+64 -66
View File
@@ -358,14 +358,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -379,22 +379,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -405,30 +412,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -455,13 +449,19 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# adjust the name width based on the call depth # adjust the name width based on the call depth
if not summary: if not summary:
@@ -486,11 +486,12 @@ def table(Result, results, diff_results=None, *,
widths[0] += 4*max(depth_-1, 0) widths[0] += 4*max(depth_-1, 0)
# print the tree recursively # print the tree recursively
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[0][0], widths[0], lines[0][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[0][1:-1])), widths[i], x[0],
lines[0][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[0][1:], 1))))
if not summary: if not summary:
line_table = {n: l for n, l in zip(names, lines[1:-1])} line_table = {n: l for n, l in zip(names, lines[1:-1])}
@@ -502,17 +503,13 @@ def table(Result, results, diff_results=None, *,
line = line_table[name] line = line_table[name]
is_last = (i == len(names_)-1) is_last = (i == len(names_)-1)
print('%s%-*s ' % ( print('%s%-*s %s' % (
prefixes[0+is_last], prefixes[0+is_last],
widths[0] - len(prefixes[0+is_last]), widths[0] - len(prefixes[0+is_last]), line[0][0],
line[0]), ' '.join('%*s%-*s' % (
end='') widths[i], x[0],
print(' %s%s' % ( notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
' '.join('%*s' % (w, x) for i, x in enumerate(line[1:], 1))))
for w, x in zip(widths[1:], line[1:-1])),
line[-1]),
end='')
print()
# recurse? # recurse?
if name in table and depth_ > 1: if name in table and depth_ > 1:
@@ -530,11 +527,12 @@ def table(Result, results, diff_results=None, *,
recurse(names, depth) recurse(names, depth)
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], lines[-1][0], widths[0], lines[-1][0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], lines[-1][1:-1])), widths[i], x[0],
lines[-1][-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(lines[-1][1:], 1))))
def main(ci_paths, def main(ci_paths,
+52 -51
View File
@@ -348,14 +348,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -369,22 +369,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -395,30 +402,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -445,21 +439,28 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# print our table # print our table
for line in lines: for line in lines:
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
def main(obj_paths, *, def main(obj_paths, *,
+52 -51
View File
@@ -479,14 +479,14 @@ def table(Result, results, diff_results=None, *,
lines = [] lines = []
# header # header
header = [] header = [
header.append('%s%s' % ( '%s%s' % (
','.join(by), ','.join(by),
' (%d added, %d removed)' % ( ' (%d added, %d removed)' % (
sum(1 for n in table if n not in diff_table), sum(1 for n in table if n not in diff_table),
sum(1 for n in diff_table if n not in table)) sum(1 for n in diff_table if n not in table))
if diff_results is not None and not percent else '') if diff_results is not None and not percent else '')
if not summary else '') if not summary else '']
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
header.append(k) header.append(k)
@@ -500,22 +500,29 @@ def table(Result, results, diff_results=None, *,
header.append('n'+k) header.append('n'+k)
for k in fields: for k in fields:
header.append('d'+k) header.append('d'+k)
header.append('')
lines.append(header) lines.append(header)
def table_entry(name, r, diff_r=None): def table_entry(name, r, diff_r=None):
entry = [] entry = [name]
entry.append(name)
if diff_results is None: if diff_results is None:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
(getattr(r, k).table(),
getattr(getattr(r, k), 'notes', lambda: [])())
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
elif percent: elif percent:
for k in fields: for k in fields:
entry.append(getattr(r, k).table() entry.append(
if getattr(r, k, None) is not None (getattr(r, k).table()
else types[k].none) if getattr(r, k, None) is not None
else types[k].none,
(lambda t: ['+∞%'] if t == +m.inf
else ['-∞%'] if t == -m.inf
else ['%+.1f%%' % (100*t)])(
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None)))))
else: else:
for k in fields: for k in fields:
entry.append(getattr(diff_r, k).table() entry.append(getattr(diff_r, k).table()
@@ -526,30 +533,17 @@ def table(Result, results, diff_results=None, *,
if getattr(r, k, None) is not None if getattr(r, k, None) is not None
else types[k].none) else types[k].none)
for k in fields: for k in fields:
entry.append(types[k].diff( entry.append(
getattr(r, k, None), (types[k].diff(
getattr(diff_r, k, None))) getattr(r, k, None),
if diff_results is None: getattr(diff_r, k, None)),
notes = [] (lambda t: ['+∞%'] if t == +m.inf
for k in fields: else ['-∞%'] if t == -m.inf
try: else ['%+.1f%%' % (100*t)] if t
notes.extend(getattr(r, k).notes()) else [])(
except AttributeError: types[k].ratio(
pass getattr(r, k, None),
entry.append(' (%s)' % ', '.join(notes) getattr(diff_r, k, None)))))
if notes else '')
else:
ratios = [
types[k].ratio(
getattr(r, k, None),
getattr(diff_r, k, None))
for k in fields]
entry.append(' (%s)' % ', '.join(
'+∞%' if t == +m.inf
else '-∞%' if t == -m.inf
else '%+.1f%%' % (100*t)
for t in ratios)
if percent or any(ratios) else '')
return entry return entry
# entries # entries
@@ -576,21 +570,28 @@ def table(Result, results, diff_results=None, *,
diff_r = next(iter(fold(Result, diff_results, by=[])), None) diff_r = next(iter(fold(Result, diff_results, by=[])), None)
lines.append(table_entry('TOTAL', r, diff_r)) lines.append(table_entry('TOTAL', r, diff_r))
# find the best widths, note that column 0 contains the names and # homogenize
# column -1 the ratios/notes, so those are handled a bit differently lines = [
widths = [ [x if isinstance(x, tuple) else (x, []) for x in line]
((max(it.chain([w], (len(l[i]) for l in lines)))+1+4-1)//4)*4-1 for line in lines]
for w, i in zip(
it.chain([23], it.repeat(7)), # find the best widths, note that column 0 contains the names and is
range(len(lines[0])-1))] # handled a bit differently
widths = co.defaultdict(lambda: 7, {0: 23})
notes = co.defaultdict(lambda: 0)
for line in lines:
for i, x in enumerate(line):
widths[i] = max(widths[i], ((len(x[0])+1+4-1)//4)*4-1)
notes[i] = max(notes[i], 1+2*len(x[1])+sum(len(n) for n in x[1]))
# print our table # print our table
for line in lines: for line in lines:
print('%-*s %s%s' % ( print('%-*s %s' % (
widths[0], line[0], widths[0], line[0][0],
' '.join('%*s' % (w, x) ' '.join('%*s%-*s' % (
for w, x in zip(widths[1:], line[1:-1])), widths[i], x[0],
line[-1])) notes[i], ' (%s)' % ', '.join(x[1]) if x[1] else '')
for i, x in enumerate(line[1:], 1))))
def main(csv_paths, *, def main(csv_paths, *,