Implementing an interactive shell

...for browsing metadata
This commit is contained in:
Jamie Hardt
2024-11-24 16:23:39 -08:00
parent f0353abd4e
commit 98ca1ec462

View File

@@ -7,6 +7,9 @@ import sys
import json import json
from enum import Enum from enum import Enum
from base64 import b64encode from base64 import b64encode
from cmd import Cmd
from shlex import split
from typing import List, Dict
class MyJSONEncoder(json.JSONEncoder): class MyJSONEncoder(json.JSONEncoder):
@@ -23,6 +26,85 @@ class MissingDataError(RuntimeError):
pass pass
class MetaBrowser(Cmd):
prompt = "(wavinfo) "
metadata: List | Dict
path: List[str] = []
@property
def cwd(self):
root: List | Dict = self.metadata
for key in self.path:
if isinstance(root, list):
root = root[int(key)]
else:
root = root[key]
return root
@staticmethod
def print_value(collection, key):
val = collection[key]
if isinstance(val, int):
print(f" - {key}: {val}")
elif isinstance(val, str):
print(f" - {key}: \"{val}\"")
elif isinstance(val, dict):
print(f" - {key}: Dict ({len(val)} keys)")
elif isinstance(val, list):
print(f" - {key}: List ({len(val)} keys)")
elif isinstance(val, bytes):
print(f" - {key}: ({len(val)} bytes)")
elif val == None:
print(f" - {key}: (NO VALUE)")
else:
print(f" - {key}: Unknown")
def do_ls(self, _):
'List items at the current node: LS'
root = self.cwd
if isinstance(root, list):
print(f"List:")
for i in range(len(root)):
self.print_value(root, i)
elif isinstance(root, dict):
print(f"Dictionary:")
for key in root:
self.print_value(root, key)
else:
print(f"Cannot print node, is not a list or dictionary.")
def do_cd(self, args):
'Switch to a different node: CD node-name | ".."'
argv = split(args)
if argv[0] == "..":
self.path = self.path[0:-1]
else:
if isinstance(self.cwd, list):
if int(argv[0]) < len(self.cwd):
self.path = self.path + [argv[0]]
else:
print(f"Index {argv[0]} does not exist")
elif isinstance(self.cwd, dict):
if argv[0] in self.cwd.keys():
self.path = self.path + [argv[0]]
else:
print(f"Key \"{argv[0]}\" does not exist")
if len(self.path) > 0:
self.prompt = "(" + "/".join(self.path) + ") "
else:
self.prompt = "(wavinfo) "
def do_bye(self, _):
'Exit the interactive browser: BYE'
return True
def main(): def main():
parser = OptionParser() parser = OptionParser()
@@ -38,7 +120,15 @@ def main():
default=False, default=False,
action='store_true') action='store_true')
parser.add_option('-i',
help='Read metadata with an interactive prompt',
default=False,
action='store_true')
(options, args) = parser.parse_args(sys.argv) (options, args) = parser.parse_args(sys.argv)
interactive_dict = []
for arg in args[1:]: for arg in args[1:]:
try: try:
this_file = WavInfoReader(path=arg) this_file = WavInfoReader(path=arg)
@@ -65,7 +155,12 @@ def main():
ret_dict['scopes'][scope][name] = value ret_dict['scopes'][scope][name] = value
json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, indent=2) if options.i:
interactive_dict.append(ret_dict)
else:
json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout,
indent=2)
except MissingDataError as e: except MissingDataError as e:
print("MissingDataError: Missing metadata (%s) in file %s" % print("MissingDataError: Missing metadata (%s) in file %s" %
(e, arg), file=sys.stderr) (e, arg), file=sys.stderr)
@@ -73,6 +168,12 @@ def main():
except Exception as e: except Exception as e:
raise e raise e
if len(interactive_dict) > 0:
cli = MetaBrowser()
cli.metadata = interactive_dict
cli.cmdloop()
if __name__ == "__main__": if __name__ == "__main__":
main() main()