scripts: csv.py: Tweaked hidden fields to not imply -b/--by defaults

So now the hidden variants of field specifiers can be used to manipulate
by fields and field fields without implying a complete field set:

  $ ./scripts/csv.py lfs.code.csv \
          -Bsubsystem=lfsr_file -Dfunction='lfsr_file_*' \
          -fcode_size

Is the same as:

  $ ./scripts/csv.py lfs.code.csv \
          -bfile -bsubsystem=lfsr_file -Dfunction='lfsr_file_*' \
          -fcode_size

Attempting to use -b/--by here would delete/merge the file field, as
cvs.py assumes -b/-f specify all of the relevant field type.

Note that fields can also be explicitly deleted with -D/--define's new
glob support:

  $ ./scripts/csv.py lfs.code.csv -Dfile='*' -fcode_size

---

This solves an annoying problem specific to csv.py, where manipulating
by fields and field fields would often force you to specify all relevant
-b/-f fields. With how benchmarks are parameterized, this list ends up
_looong_.

It's a bit of a hack/abuse of the hidden flags, but the alternative
would be field globbing, which 1. would be a real pain-in-the-ass to
implement, and 2. affect almost all of the scripts. Reusing the hidden
flags for this keeps the complexity limited to csv.py.
This commit is contained in:
Christopher Haster
2025-05-15 15:08:23 -05:00
parent 7526b469b9
commit 43c2330edc

View File

@ -2179,7 +2179,8 @@ def main(csv_paths, *,
if args.get('help_exprs'):
return CsvExpr.help()
if by is None and fields is None:
if ((by is None or all(hidden for (k, v), hidden in by))
and (fields is None or all(hidden for (k, v), hidden in fields))):
print("error: needs --by or --fields to figure out fields",
file=sys.stderr)
sys.exit(-1)
@ -2208,40 +2209,6 @@ def main(csv_paths, *,
elif depth == 0:
depth = mt.inf
# separate out enumerates/mods/exprs
#
# enumerate enumerates: -ia
# by supports mods: -ba=%(b)s
# fields/sort/etc supports exprs: -fa=b+c
#
enumerates = [k
for (k, v), hidden in (by or [])
if v == enumerate]
mods = [(k, v)
for k, v in it.chain(
((k, v) for (k, v), hidden in (by or [])
if v != enumerate))
if v is not None]
exprs = [(k, v)
for k, v in it.chain(
((k, v) for (k, v), hidden in (fields or [])),
((k, v) for (k, v), reverse in (sort or [])),
((k, v) for (k, v), reverse in (hot or [])))
if v is not None]
labels = None
if by is not None:
labels = [k for (k, v), hidden in by if not hidden]
by = [k for (k, v), hidden in by]
if fields is not None:
fields = [k for (k, v), hidden in fields
if not hidden
or args.get('output')
or args.get('output_json')]
if sort is not None:
sort = [(k, reverse) for (k, v), reverse in sort]
if hot is not None:
hot = [(k, reverse) for (k, v), reverse in hot]
# find results
if not args.get('use', None):
# not enough info?
@ -2265,32 +2232,80 @@ def main(csv_paths, *,
notes=notes,
**args)
# separate out enumerates/mods/exprs
#
# enumerate enumerates: -ia
# by supports mods: -ba=%(b)s
# fields/sort/etc supports exprs: -fa=b+c
#
enumerates = [k
for (k, v), hidden in (by or [])
if v == enumerate]
mods = [(k, v)
for k, v in it.chain(
((k, v) for (k, v), hidden in (by or [])
if v != enumerate))
if v is not None]
exprs = [(k, v)
for k, v in it.chain(
((k, v) for (k, v), hidden in (fields or [])),
((k, v) for (k, v), reverse in (sort or [])),
((k, v) for (k, v), reverse in (hot or [])))
if v is not None]
# figure out labels/by/fields
labels__ = None
by__ = []
fields__ = []
if by is not None and any(not hidden for (k, v), hidden in by):
labels__ = [k for (k, v), hidden in by if not hidden]
if by is not None:
by__ = [k for (k, v), hidden in by]
if fields is not None:
fields__ = [k for (k, v), hidden in fields
if not hidden
or args.get('output')
or args.get('output_json')]
# if by not specified, guess it's anything not in fields/defines/exprs/etc
if not by:
by = [k for k in fields_
if k not in (fields or [])
if by is None or all(hidden for (k, v), hidden in by):
by__.extend(k for k in fields_
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 (sort or []))
and not any(k == k_ for (k_, _), _ in (sort or []))
and k != children
and not any(k == k_ for k_, _ in (hot or []))
and not any(k == k_ for (k_, _), _ in (hot or []))
and k != notes
and not any(k == k_
for _, expr in exprs
for k_ in expr.fields())]
for k_ in expr.fields()))
# if fields not specified, guess it's anything not in by/defines/exprs/etc
if not fields:
fields = [k for k in fields_
if k not in (by or [])
if fields is None or all(hidden for (k, v), hidden in fields):
fields__.extend(k for k in fields_
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 (sort or []))
and not any(k == k_ for (k_, _), _ in (sort or []))
and k != children
and not any(k == k_ for k_, _ in (hot or []))
and not any(k == k_ for (k_, _), _ in (hot or []))
and k != notes
and not any(k == k_
for _, expr in exprs
for k_ in expr.fields())]
for k_ in expr.fields()))
labels = labels__
by = by__
fields = fields__
# filter exprs from sort/hot
if sort is not None:
sort = [(k, reverse) for (k, v), reverse in sort]
if hot is not None:
hot = [(k, reverse) for (k, v), reverse in hot]
# ok ok, now that by/fields/bla/bla/bla is all figured out
#
# build result type
Result = compile(fields_, results,
by=by,
@ -2450,7 +2465,8 @@ if __name__ == "__main__":
nargs='?',
type=lambda x: (x, enumerate),
const=('i', enumerate),
help="Like -i/--enumerate, but hidden from the table renderer.")
help="Like -i/--enumerate, but hidden from the table renderer, "
"and doesn't affect -b/--by defaults.")
parser.add_argument(
'-b', '--by',
action=AppendBy,
@ -2469,7 +2485,8 @@ if __name__ == "__main__":
k.strip(),
v.strip() if v is not None else None)
)(*x.split('=', 1)),
help="Like -b/--by, but hidden from the table renderer.")
help="Like -b/--by, but hidden from the table renderer, "
"and doesn't affect -b/--by defaults.")
class AppendField(argparse.Action):
def __call__(self, parser, namespace, value, option):
if namespace.fields is None:
@ -2496,7 +2513,8 @@ if __name__ == "__main__":
k.strip(),
v.strip() if v is not None else None)
)(*x.split('=', 1)),
help="Like -f/--field, but hidden from the table renderer.")
help="Like -f/--field, but hidden from the table renderer, "
"and doesn't affect -f/--field defaults.")
parser.add_argument(
'-D', '--define',
dest='defines',