scripts: Added -U/--undefine as inverse -D/--define to most scripts
This adds -U/--undefine as an inverse -D/--define, allowing you to select results where a given field does _not_ match a set of values/globs. For example, make bench-marks, which need to ignore stack/heap/usage probes as a special case, can easily filter like so: $ ./scripts/csv.py test.csv -Uprobe=stack,heap,usage --- One thing globbing is pretty bad at is inverse matches. This is _usually_ easy enough to work around, but has been an annoyance enough times that I think _some_ option to inverse filter is warranted. I'm not sure -U/--undefine is the best name for this, since field isn't really "undefined" as a result (well kinda? if you're relying on implicit by/field rules?), but it gets the job done.
This commit is contained in:
@@ -600,9 +600,7 @@ bench-marks: SUMMARYFLAGS+=-Si
|
||||
bench-marks: $(BENCH_CSV)
|
||||
$(strip ./scripts/csv.py \
|
||||
<(./scripts/csv.py $^ \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Fi='min(enumerate())' \
|
||||
-fn='max(n)' \
|
||||
@@ -624,18 +622,14 @@ bench-marks-csv: $(BUILDDIR)/lfs3.bench.csv
|
||||
bench-marks-diff: $(BENCH_CSV)
|
||||
$(strip ./scripts/csv.py \
|
||||
<(./scripts/csv.py $^ \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Fi='min(enumerate())' \
|
||||
-fn='max(n)' \
|
||||
-ft='max(float(bench_simtime)/1.0e9)' \
|
||||
-o-) \
|
||||
-d <(./scripts/csv.py $(BUILDDIR)/lfs3.bench.csv \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Fi='min(enumerate())' \
|
||||
-fn='max(n)' \
|
||||
@@ -652,9 +646,7 @@ bench-bottlenecks: SUMMARYFLAGS+=-Sruntime
|
||||
bench-bottlenecks: $(BENCH_CSV)
|
||||
$(strip ./scripts/csv.py \
|
||||
<(./scripts/csv.py $^ \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Fi='min(enumerate())' \
|
||||
-fn='max(n)' \
|
||||
@@ -673,9 +665,7 @@ bench-bottlenecks: $(BENCH_CSV)
|
||||
bench-ops: SUMMARYFLAGS+=-Si
|
||||
bench-ops: $(BENCH_CSV)
|
||||
$(strip ./scripts/csv.py $^ \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Hprobe=bench+probe \
|
||||
-Fi='min(enumerate())' \
|
||||
@@ -692,9 +682,7 @@ bench-ops: $(BENCH_CSV)
|
||||
bench-widths: SUMMARYFLAGS+=-Si
|
||||
bench-widths: $(BENCH_CSV)
|
||||
$(strip ./scripts/csv.py $^ \
|
||||
-Dprobe=append,remove,create,delete,fetch,lookup,$\
|
||||
commit,namelookup,$\
|
||||
write,stat,read \
|
||||
-Uprobe=stack,heap,usage \
|
||||
-bprobe='%(case)s+%(probe)s' \
|
||||
-Hprobe=bench+probe \
|
||||
-Fi='min(enumerate())' \
|
||||
|
||||
+27
-5
@@ -529,6 +529,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -540,20 +541,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1048,6 +1056,7 @@ def main(obj_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
**args):
|
||||
# figure out what fields we're interested in
|
||||
@@ -1080,6 +1089,7 @@ def main(obj_paths, *,
|
||||
results = fold(CodeResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort)
|
||||
|
||||
# find previous results?
|
||||
@@ -1096,7 +1106,8 @@ def main(obj_paths, *,
|
||||
# fold
|
||||
diff_results = fold(CodeResult, diff_results,
|
||||
by=by,
|
||||
defines=defines)
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# write results to JSON
|
||||
if args.get('output_json'):
|
||||
@@ -1188,6 +1199,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+27
-5
@@ -398,6 +398,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -409,20 +410,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -992,6 +1000,7 @@ def main(gcda_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
hits=False,
|
||||
**args):
|
||||
@@ -1046,6 +1055,7 @@ def main(gcda_paths, *,
|
||||
results = fold(CovResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort)
|
||||
|
||||
# find previous results?
|
||||
@@ -1062,7 +1072,8 @@ def main(gcda_paths, *,
|
||||
# fold
|
||||
diff_results = fold(CovResult, diff_results,
|
||||
by=by,
|
||||
defines=defines)
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# annotate sources
|
||||
if (args.get('annotate')
|
||||
@@ -1167,6 +1178,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+33
-4
@@ -2069,6 +2069,7 @@ def compile(fields_, results,
|
||||
|
||||
def homogenize(Result, results, *,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
depth=1,
|
||||
depth_=0,
|
||||
**_):
|
||||
@@ -2087,6 +2088,10 @@ def homogenize(Result, results, *,
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(r.get(k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
|
||||
# append a result
|
||||
results_.append(Result(
|
||||
@@ -2125,6 +2130,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -2136,20 +2142,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -2920,6 +2933,7 @@ def main(csv_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=None,
|
||||
children=None,
|
||||
@@ -3039,6 +3053,7 @@ def main(csv_paths, *,
|
||||
if not any(k == k_ for (k_, _), _ in (by or []))
|
||||
and not any(k == k_ for (k_, _), _ in (fields or []))
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)
|
||||
and not any(k == k_ for (k_, _), _ in (sort or []))
|
||||
and not any(k == k_ for (k_, _), _ in (hot or []))
|
||||
and k != z
|
||||
@@ -3054,6 +3069,7 @@ def main(csv_paths, *,
|
||||
if not any(k == k_ for (k_, _), _ in (by or []))
|
||||
and not any(k == k_ for (k_, _), _ in (fields or []))
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)
|
||||
and not any(k == k_ for (k_, _), _ in (sort or []))
|
||||
and not any(k == k_ for (k_, _), _ in (hot or []))
|
||||
and k != z
|
||||
@@ -3093,6 +3109,7 @@ def main(csv_paths, *,
|
||||
# homogenize
|
||||
results = homogenize(Result, results,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# fold
|
||||
@@ -3128,6 +3145,7 @@ def main(csv_paths, *,
|
||||
# homogenize
|
||||
diff_results = homogenize(Result, diff_results,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# fold
|
||||
@@ -3319,6 +3337,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+26
-4
@@ -745,6 +745,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -756,20 +757,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1307,6 +1315,7 @@ def main(obj_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=None,
|
||||
hot=None,
|
||||
@@ -1356,6 +1365,7 @@ def main(obj_paths, *,
|
||||
results = fold(CtxResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort,
|
||||
depth=depth)
|
||||
|
||||
@@ -1381,6 +1391,7 @@ def main(obj_paths, *,
|
||||
diff_results = fold(CtxResult, diff_results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# hotify?
|
||||
@@ -1483,6 +1494,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+27
-5
@@ -529,6 +529,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -540,20 +541,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1048,6 +1056,7 @@ def main(obj_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
**args):
|
||||
# figure out what fields we're interested in
|
||||
@@ -1080,6 +1089,7 @@ def main(obj_paths, *,
|
||||
results = fold(DataResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort)
|
||||
|
||||
# find previous results?
|
||||
@@ -1096,7 +1106,8 @@ def main(obj_paths, *,
|
||||
# fold
|
||||
diff_results = fold(DataResult, diff_results,
|
||||
by=by,
|
||||
defines=defines)
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# write results to JSON
|
||||
if args.get('output_json'):
|
||||
@@ -1188,6 +1199,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+26
-4
@@ -844,6 +844,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -855,20 +856,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1505,6 +1513,7 @@ def main_(perf_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
branches=False,
|
||||
caches=False,
|
||||
@@ -1574,6 +1583,7 @@ def main_(perf_paths, *,
|
||||
results = fold(PerfResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort,
|
||||
depth=depth)
|
||||
|
||||
@@ -1599,6 +1609,7 @@ def main_(perf_paths, *,
|
||||
diff_results = fold(PerfResult, diff_results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# hotify?
|
||||
@@ -1727,6 +1738,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+26
-4
@@ -818,6 +818,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -829,20 +830,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1493,6 +1501,7 @@ def main_(paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=None,
|
||||
hot=None,
|
||||
@@ -1570,6 +1579,7 @@ def main_(paths, *,
|
||||
results = fold(PerfBdResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort,
|
||||
depth=depth)
|
||||
|
||||
@@ -1595,6 +1605,7 @@ def main_(paths, *,
|
||||
diff_results = fold(PerfBdResult, diff_results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# hotify?
|
||||
@@ -1728,6 +1739,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+53
-13
@@ -356,7 +356,9 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def __ge__(self, other):
|
||||
return self.a <= other.a
|
||||
|
||||
def collect(csv_paths, defines=[]):
|
||||
def collect(csv_paths, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# collect results from CSV files
|
||||
fields = []
|
||||
results = []
|
||||
@@ -373,22 +375,34 @@ def collect(csv_paths, defines=[]):
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
|
||||
results.append(r)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return fields, results
|
||||
|
||||
def fold(results, by=None, x=None, y=None, defines=[]):
|
||||
def fold(results, by=None, x=None, y=None, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
if not all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
if by:
|
||||
@@ -1232,7 +1246,8 @@ def main_(ring, csv_paths, *,
|
||||
by=None,
|
||||
x=None,
|
||||
y=None,
|
||||
define=[],
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
labels=[],
|
||||
chars=[],
|
||||
@@ -1330,10 +1345,17 @@ def main_(ring, csv_paths, *,
|
||||
all_x = (x or []) + subplots_get('x', **subplot, subplots=subplots)
|
||||
all_y = (y or []) + subplots_get('y', **subplot, subplots=subplots)
|
||||
all_defines = co.defaultdict(lambda: set())
|
||||
for k, vs in it.chain(define or [],
|
||||
subplots_get('define', **subplot, subplots=subplots)):
|
||||
for k, vs in it.chain(
|
||||
defines,
|
||||
subplots_get('defines', **subplot, subplots=subplots)):
|
||||
all_defines[k] |= vs
|
||||
all_defines = sorted(all_defines.items())
|
||||
all_undefines = co.defaultdict(lambda: set())
|
||||
for k, vs in it.chain(
|
||||
undefines,
|
||||
subplots_get('undefines', **subplot, subplots=subplots)):
|
||||
all_undefines[k] |= vs
|
||||
all_undefines = sorted(all_undefines.items())
|
||||
|
||||
if not all_by and not all_y:
|
||||
print("error: needs --by or -y to figure out fields",
|
||||
@@ -1423,14 +1445,17 @@ def main_(ring, csv_paths, *,
|
||||
## our main drawing logic
|
||||
|
||||
# first collect results from CSV files
|
||||
fields_, results = collect(csv_paths)
|
||||
fields_, results = collect(csv_paths,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# if y not specified, guess it's anything not in by/defines/x
|
||||
all_y_ = all_y
|
||||
if not all_y:
|
||||
all_y_ = [k for k in fields_
|
||||
if k not in all_by
|
||||
and not any(k == k_ for k_, _ in all_defines)]
|
||||
and not any(k == k_ for k_, _ in all_defines)
|
||||
and not any(k == k_ for k_, _ in all_undefines)]
|
||||
|
||||
# then extract the requested datasets
|
||||
#
|
||||
@@ -1603,7 +1628,8 @@ def main_(ring, csv_paths, *,
|
||||
# allow subplot params to override global params
|
||||
x_ = set((x or []) + s.args.get('x', []))
|
||||
y_ = set((y or []) + s.args.get('y', []))
|
||||
define_ = define + s.args.get('define', [])
|
||||
defines_ = defines + s.args.get('defines', [])
|
||||
undefines_ = undefines + s.args.get('undefines', [])
|
||||
xlim_ = s.args.get('xlim', xlim)
|
||||
ylim_ = s.args.get('ylim', ylim)
|
||||
xlim_stddev_ = s.args.get('xlim_stddev', xlim_stddev)
|
||||
@@ -1630,7 +1656,9 @@ def main_(ring, csv_paths, *,
|
||||
# data can be constrained by subplot-specific defines,
|
||||
# so re-extract for each plot
|
||||
subdatasets, subdataattrs = fold(
|
||||
results, all_by, all_x, all_y_, define_)
|
||||
results, all_by, all_x, all_y_,
|
||||
defines=defines_,
|
||||
undefines=undefines_)
|
||||
|
||||
# order by labels
|
||||
subdatasets = co.OrderedDict(sorted(
|
||||
@@ -1991,14 +2019,26 @@ if __name__ == "__main__":
|
||||
help="Field to use for the y-axis.")
|
||||
parser.add_argument(
|
||||
'-D', '--define',
|
||||
dest='defines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
action='append',
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+53
-13
@@ -240,7 +240,9 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def __ge__(self, other):
|
||||
return self.a <= other.a
|
||||
|
||||
def collect(csv_paths, defines=[]):
|
||||
def collect(csv_paths, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# collect results from CSV files
|
||||
fields = []
|
||||
results = []
|
||||
@@ -257,22 +259,34 @@ def collect(csv_paths, defines=[]):
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
|
||||
results.append(r)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return fields, results
|
||||
|
||||
def fold(results, by=None, x=None, y=None, defines=[]):
|
||||
def fold(results, by=None, x=None, y=None, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
if not all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
if by:
|
||||
@@ -826,7 +840,8 @@ def main(csv_paths, output, *,
|
||||
by=None,
|
||||
x=None,
|
||||
y=None,
|
||||
define=[],
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
labels=[],
|
||||
colors=[],
|
||||
@@ -978,10 +993,17 @@ def main(csv_paths, output, *,
|
||||
all_x = (x or []) + subplots_get('x', **subplot, subplots=subplots)
|
||||
all_y = (y or []) + subplots_get('y', **subplot, subplots=subplots)
|
||||
all_defines = co.defaultdict(lambda: set())
|
||||
for k, vs in it.chain(define or [],
|
||||
subplots_get('define', **subplot, subplots=subplots)):
|
||||
for k, vs in it.chain(
|
||||
defines,
|
||||
subplots_get('defines', **subplot, subplots=subplots)):
|
||||
all_defines[k] |= vs
|
||||
all_defines = sorted(all_defines.items())
|
||||
all_undefines = co.defaultdict(lambda: set())
|
||||
for k, vs in it.chain(
|
||||
undefines,
|
||||
subplots_get('undefines', **subplot, subplots=subplots)):
|
||||
all_undefines[k] |= vs
|
||||
all_undefines = sorted(all_undefines.items())
|
||||
|
||||
if not all_by and not all_y:
|
||||
print("error: needs --by or -y to figure out fields",
|
||||
@@ -989,13 +1011,16 @@ def main(csv_paths, output, *,
|
||||
sys.exit(-1)
|
||||
|
||||
# first collect results from CSV files
|
||||
fields_, results = collect(csv_paths)
|
||||
fields_, results = collect(csv_paths,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# if y not specified, guess it's anything not in by/defines/x
|
||||
if not all_y:
|
||||
all_y = [k for k in fields_
|
||||
if k not in all_by
|
||||
and not any(k == k_ for k_, _ in all_defines)]
|
||||
and not any(k == k_ for k_, _ in all_defines)
|
||||
and not any(k == k_ for k_, _ in all_undefines)]
|
||||
|
||||
# then extract the requested datasets
|
||||
#
|
||||
@@ -1065,7 +1090,8 @@ def main(csv_paths, output, *,
|
||||
# allow subplot params to override global params
|
||||
x_ = set((x or []) + s.args.get('x', []))
|
||||
y_ = set((y or []) + s.args.get('y', []))
|
||||
define_ = define + s.args.get('define', [])
|
||||
defines_ = defines + s.args.get('defines', [])
|
||||
undefines_ = undefines + s.args.get('undefines', [])
|
||||
xlim_ = s.args.get('xlim', xlim)
|
||||
ylim_ = s.args.get('ylim', ylim)
|
||||
xlim_stddev_ = s.args.get('xlim_stddev', xlim_stddev)
|
||||
@@ -1105,7 +1131,9 @@ def main(csv_paths, output, *,
|
||||
# data can be constrained by subplot-specific defines,
|
||||
# so re-extract for each plot
|
||||
subdatasets, subdataattrs = fold(
|
||||
results, all_by, all_x, all_y, define_)
|
||||
results, all_by, all_x, all_y,
|
||||
defines=defines_,
|
||||
undefines=undefines_)
|
||||
|
||||
# order by labels
|
||||
subdatasets = co.OrderedDict(sorted(
|
||||
@@ -1447,14 +1475,26 @@ if __name__ == "__main__":
|
||||
help="Field to use for the y-axis.")
|
||||
parser.add_argument(
|
||||
'-D', '--define',
|
||||
dest='defines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
action='append',
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+26
-4
@@ -486,6 +486,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -497,20 +498,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1048,6 +1056,7 @@ def main(ci_paths,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=None,
|
||||
hot=None,
|
||||
@@ -1094,6 +1103,7 @@ def main(ci_paths,
|
||||
results = fold(StackResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort,
|
||||
depth=depth)
|
||||
|
||||
@@ -1119,6 +1129,7 @@ def main(ci_paths,
|
||||
diff_results = fold(StackResult, diff_results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# hotify?
|
||||
@@ -1226,6 +1237,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+26
-4
@@ -634,6 +634,7 @@ class Rev(co.namedtuple('Rev', 'a')):
|
||||
def fold(Result, results, *,
|
||||
by=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=1,
|
||||
**_):
|
||||
@@ -645,20 +646,27 @@ def fold(Result, results, *,
|
||||
if by is None:
|
||||
by = Result._by
|
||||
|
||||
for k in it.chain(by or [], (k for k, _ in defines)):
|
||||
for k in it.chain(by or [],
|
||||
(k for k, _ in defines),
|
||||
(k for k, _ in undefines)):
|
||||
if k not in Result._by and k not in Result._fields:
|
||||
print("error: could not find field %r?" % k,
|
||||
file=sys.stderr)
|
||||
sys.exit(-1)
|
||||
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
if not all(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(str(getattr(r, k, '')), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
# organize results into conflicts
|
||||
@@ -1196,6 +1204,7 @@ def main(obj_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
sort=None,
|
||||
depth=None,
|
||||
hot=None,
|
||||
@@ -1245,6 +1254,7 @@ def main(obj_paths, *,
|
||||
results = fold(StructResult, results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
sort=sort,
|
||||
depth=depth)
|
||||
|
||||
@@ -1270,6 +1280,7 @@ def main(obj_paths, *,
|
||||
diff_results = fold(StructResult, diff_results,
|
||||
by=by,
|
||||
defines=defines,
|
||||
undefines=undefines,
|
||||
depth=depth)
|
||||
|
||||
# hotify?
|
||||
@@ -1372,6 +1383,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
class AppendSort(argparse.Action):
|
||||
def __call__(self, parser, namespace, value, option):
|
||||
if namespace.sort is None:
|
||||
|
||||
+41
-9
@@ -262,7 +262,9 @@ def dat(x, *args):
|
||||
else:
|
||||
raise
|
||||
|
||||
def collect(csv_paths, defines=[]):
|
||||
def collect(csv_paths, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# collect results from CSV files
|
||||
fields = []
|
||||
results = []
|
||||
@@ -279,22 +281,34 @@ def collect(csv_paths, defines=[]):
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
|
||||
results.append(r)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return fields, results
|
||||
|
||||
def fold(results, by=None, fields=None, defines=[]):
|
||||
def fold(results, by=None, fields=None, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
if not all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
if by:
|
||||
@@ -1017,6 +1031,7 @@ def main_(ring, csv_paths, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
labels=[],
|
||||
chars=[],
|
||||
colors=[],
|
||||
@@ -1087,7 +1102,9 @@ def main_(ring, csv_paths, *,
|
||||
height_ = max(0, shutil.get_terminal_size((80, 5))[1] + height)
|
||||
|
||||
# first collect results from CSV files
|
||||
fields_, results = collect(csv_paths, defines)
|
||||
fields_, results = collect(csv_paths,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
if not by and not fields:
|
||||
print("error: needs --by or --fields to figure out fields",
|
||||
@@ -1098,16 +1115,20 @@ def main_(ring, csv_paths, *,
|
||||
if not by:
|
||||
by = [k for k in fields_
|
||||
if k not in (fields or [])
|
||||
and not any(k == k_ for k_, _ in defines)]
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)]
|
||||
|
||||
# if fields not specified, guess it's anything not in by/defines
|
||||
if not fields:
|
||||
fields = [k for k in fields_
|
||||
if k not in (by or [])
|
||||
and not any(k == k_ for k_, _ in defines)]
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)]
|
||||
|
||||
# then extract the requested dataset
|
||||
datasets, dataattrs = fold(results, by, fields, defines)
|
||||
datasets, dataattrs = fold(results, by, fields,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# build tile heirarchy
|
||||
children = []
|
||||
@@ -1421,6 +1442,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-L', '--add-label',
|
||||
dest='labels',
|
||||
|
||||
+41
-9
@@ -123,7 +123,9 @@ def dat(x, *args):
|
||||
else:
|
||||
raise
|
||||
|
||||
def collect(csv_paths, defines=[]):
|
||||
def collect(csv_paths, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# collect results from CSV files
|
||||
fields = []
|
||||
results = []
|
||||
@@ -140,22 +142,34 @@ def collect(csv_paths, defines=[]):
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in undefines):
|
||||
continue
|
||||
|
||||
results.append(r)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
return fields, results
|
||||
|
||||
def fold(results, by=None, fields=None, defines=[]):
|
||||
def fold(results, by=None, fields=None, *,
|
||||
defines=[],
|
||||
undefines=[]):
|
||||
# filter by matching defines
|
||||
if defines:
|
||||
if defines or undefines:
|
||||
results_ = []
|
||||
for r in results:
|
||||
if all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
if not all(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
results_.append(r)
|
||||
continue
|
||||
if any(any(fnmatch.fnmatchcase(r.get(k, ''), v)
|
||||
for v in vs)
|
||||
for k, vs in defines):
|
||||
continue
|
||||
results_.append(r)
|
||||
results = results_
|
||||
|
||||
if by:
|
||||
@@ -708,6 +722,7 @@ def main(csv_paths, output, *,
|
||||
by=None,
|
||||
fields=None,
|
||||
defines=[],
|
||||
undefines=[],
|
||||
labels=[],
|
||||
colors=[],
|
||||
width=None,
|
||||
@@ -761,7 +776,9 @@ def main(csv_paths, output, *,
|
||||
height_ = HEIGHT
|
||||
|
||||
# first collect results from CSV files
|
||||
fields_, results = collect(csv_paths, defines)
|
||||
fields_, results = collect(csv_paths,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
if not by and not fields:
|
||||
print("error: needs --by or --fields to figure out fields",
|
||||
@@ -772,16 +789,20 @@ def main(csv_paths, output, *,
|
||||
if not by:
|
||||
by = [k for k in fields_
|
||||
if k not in (fields or [])
|
||||
and not any(k == k_ for k_, _ in defines)]
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)]
|
||||
|
||||
# if fields not specified, guess it's anything not in by/labels/defines
|
||||
if not fields:
|
||||
fields = [k for k in fields_
|
||||
if k not in (by or [])
|
||||
and not any(k == k_ for k_, _ in defines)]
|
||||
and not any(k == k_ for k_, _ in defines)
|
||||
and not any(k == k_ for k_, _ in undefines)]
|
||||
|
||||
# then extract the requested dataset
|
||||
datasets, dataattrs = fold(results, by, fields, defines)
|
||||
datasets, dataattrs = fold(results, by, fields,
|
||||
defines=defines,
|
||||
undefines=undefines)
|
||||
|
||||
# build tile heirarchy
|
||||
children = []
|
||||
@@ -1117,6 +1138,17 @@ if __name__ == "__main__":
|
||||
)(*x.split('=', 1)),
|
||||
help="Only include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-U', '--undefine',
|
||||
dest='undefines',
|
||||
action='append',
|
||||
type=lambda x: (
|
||||
lambda k, vs: (
|
||||
k.strip(),
|
||||
{v.strip() for v in vs.split(',')})
|
||||
)(*x.split('=', 1)),
|
||||
help="Don't include results where this field is this value. May "
|
||||
"include comma-separated options and globs.")
|
||||
parser.add_argument(
|
||||
'-L', '--add-label',
|
||||
dest='labels',
|
||||
|
||||
Reference in New Issue
Block a user