Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ls WiP: tried to add filtering and {}formating with alt names #1118

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions dandi/cli/cmd_ls.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@
@click.option(
"-F",
"--fields",
help="Comma-separated list of fields to display. "
"An empty value to trigger a list of "
"available fields to be printed out",
help="Comma-separated list of fields to display. 'path' field is mandatory thus"
"will always be added. Field could provide an alternative name as "
"'ALTERNATIVE==ORIGINAL', and '{STRING}' will be considered to be a subject to"
"'str.format()' operation using all other fields.",
)
@click.option(
"-f",
Expand Down Expand Up @@ -120,12 +121,12 @@ def ls(
fields = fields.split(",")
# Map possibly present short names back to full names
fields = [PYOUT_SHORT_NAMES_rev.get(f.lower(), f) for f in fields]
unknown_fields = set(fields).difference(all_fields)
if unknown_fields:
display_known_fields(all_fields)
raise click.UsageError(
"Following fields are not known: %s" % ", ".join(unknown_fields)
)
# unknown_fields = set(fields).difference(all_fields)
# if unknown_fields:
# display_known_fields(all_fields)
# raise click.UsageError(
# "Following fields are not known: %s" % ", ".join(unknown_fields)
# )

urls = map(is_url, paths)
# Actually I do not see why and it could be useful to compare local-vs-remote
Expand Down Expand Up @@ -159,11 +160,15 @@ def assets_gen():
if format == "auto":
format = "yaml" if any(urls) or (len(paths) == 1 and not recursive) else "pyout"

field_names = {f.split("==", 1)[0]: f for f in fields}
if len(field_names) != len(fields):
raise ValueError("non unique names detected")

if format == "pyout":
if fields and fields[0] != "path":
# we must always have path - our "id"
fields = ["path"] + fields
out = PYOUTFormatter(fields=fields, wait_for_top=3, max_workers=jobs)
out = PYOUTFormatter(fields=field_names, wait_for_top=3, max_workers=jobs)
elif format == "json":
out = JSONFormatter()
elif format == "json_pp":
Expand All @@ -177,7 +182,7 @@ def assets_gen():

async_keys = set(all_fields)
if fields is not None:
async_keys = async_keys.intersection(fields)
async_keys = async_keys.intersection(field_names)
async_keys = tuple(async_keys.difference(common_fields))

errors = defaultdict(list) # problem: [] paths
Expand Down Expand Up @@ -233,7 +238,34 @@ def assets_gen():
errors["Empty record"].append(asset)
lgr.debug("Skipping a record for %s since empty", asset)
continue
out(rec)
if fields:
# get it flattened out and only the ones requested
rec_display = {}
for f in fields:
f_name = f
# could be alt_name==field
if "==" in f:
f_name, f = f.split("==", 1)
if f in rec:
# as is, nothing fancy
f_value = rec[f]
elif f.startswith("{") and f.endswith("}"):
# # it is a str.format, strip {} for display
# if f_name.startswith('{'):
# f_name = f_name
try:
# TODO: this all doesn't work on those fields which are "async"
# i.e. loadded delayed in a thread within pyout upon a callback
f_value = f.format(**rec)
except Exception:
lgr.error("Cannot str.format %r using %r", f, rec)
f_value = "ERROR"
else:
f_value = "N/A"
rec_display[f_name] = f_value
else:
rec_display = rec
out(rec_display)
if errors:
lgr.warning(
"Failed to operate on some paths (empty records were listed):\n %s",
Expand Down