scripts: csv.py: Extended -s/-S to support exprs and hidden fields
The main benefit of this is allowing the sort order to be controlled by fields that don't necessarily need to be printed: ./scripts/csv.py input.csv -ba -sb -fc By default this sorts lexicographically, but this can be changed by providing an expression: ./scripts/csv.py input.csv -ba -sb='int(b)' -fc Note that sort fields do _not_ change inferred by fields, this allows sort flags to be added to existing queries without changing the results too much: ./scripts/csv.py input.csv -fc ./scripts/csv.py input.csv -sb -fc
This commit is contained in:
+29
-5
@@ -1225,7 +1225,8 @@ def infer(fields_, results,
|
|||||||
by=None,
|
by=None,
|
||||||
fields=None,
|
fields=None,
|
||||||
exprs=[],
|
exprs=[],
|
||||||
defines=[]):
|
defines=[],
|
||||||
|
sort=None):
|
||||||
# we only really care about the last expr for each field
|
# we only really care about the last expr for each field
|
||||||
exprs = {k: expr for k, expr in exprs}
|
exprs = {k: expr for k, expr in exprs}
|
||||||
|
|
||||||
@@ -1251,6 +1252,11 @@ def infer(fields_, results,
|
|||||||
by = list(co.OrderedDict.fromkeys(by).keys())
|
by = list(co.OrderedDict.fromkeys(by).keys())
|
||||||
fields = list(co.OrderedDict.fromkeys(fields).keys())
|
fields = list(co.OrderedDict.fromkeys(fields).keys())
|
||||||
|
|
||||||
|
# make sure sort fields are included
|
||||||
|
if sort is not None:
|
||||||
|
by.extend(k for k, reverse in sort
|
||||||
|
if k not in by and k not in fields)
|
||||||
|
|
||||||
# find best type for all fields used by field exprs
|
# find best type for all fields used by field exprs
|
||||||
fields__ = set(it.chain.from_iterable(
|
fields__ = set(it.chain.from_iterable(
|
||||||
exprs[k].fields() if k in exprs else {k}
|
exprs[k].fields() if k in exprs else {k}
|
||||||
@@ -1568,12 +1574,17 @@ def main(csv_paths, *,
|
|||||||
|
|
||||||
# separate out exprs
|
# separate out exprs
|
||||||
exprs = [(k, v)
|
exprs = [(k, v)
|
||||||
for k, v in it.chain(by or [], fields or [])
|
for k, v in it.chain(
|
||||||
|
by or [],
|
||||||
|
fields or [],
|
||||||
|
((k, v) for (k, v), reverse in sort or []))
|
||||||
if v is not None]
|
if v is not None]
|
||||||
if by is not None:
|
if by is not None:
|
||||||
by = [k for k, _ in by]
|
by = [k for k, _ in by]
|
||||||
if fields is not None:
|
if fields is not None:
|
||||||
fields = [k for k, _ in fields]
|
fields = [k for k, _ in fields]
|
||||||
|
if sort is not None:
|
||||||
|
sort = [(k, reverse) for (k, v), reverse in sort]
|
||||||
|
|
||||||
if by is None and fields is None:
|
if by is None and fields is None:
|
||||||
print("error: needs --by or --fields to figure out fields",
|
print("error: needs --by or --fields to figure out fields",
|
||||||
@@ -1592,7 +1603,8 @@ def main(csv_paths, *,
|
|||||||
by=by,
|
by=by,
|
||||||
fields=fields,
|
fields=fields,
|
||||||
exprs=exprs,
|
exprs=exprs,
|
||||||
defines=defines)
|
defines=defines,
|
||||||
|
sort=sort)
|
||||||
results_ = []
|
results_ = []
|
||||||
for r in results:
|
for r in results:
|
||||||
results_.append(Result(**{
|
results_.append(Result(**{
|
||||||
@@ -1728,12 +1740,24 @@ if __name__ == "__main__":
|
|||||||
'-s', '--sort',
|
'-s', '--sort',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
action=AppendSort,
|
action=AppendSort,
|
||||||
help="Sort by this field.")
|
type=lambda x: (
|
||||||
|
lambda k, v=None: (
|
||||||
|
k.strip(),
|
||||||
|
RExpr(v) if v is not None else None)
|
||||||
|
)(*x.split('=', 1)),
|
||||||
|
help="Sort by this field. Can include an expression of the form "
|
||||||
|
"field=expr.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-S', '--reverse-sort',
|
'-S', '--reverse-sort',
|
||||||
nargs='?',
|
nargs='?',
|
||||||
action=AppendSort,
|
action=AppendSort,
|
||||||
help="Sort by this field, but backwards.")
|
type=lambda x: (
|
||||||
|
lambda k, v=None: (
|
||||||
|
k.strip(),
|
||||||
|
RExpr(v) if v is not None else None)
|
||||||
|
)(*x.split('=', 1)),
|
||||||
|
help="Sort by this field, but backwards. Can include an expression "
|
||||||
|
"of the form field=expr.")
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-Y', '--summary',
|
'-Y', '--summary',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
|
|||||||
Reference in New Issue
Block a user