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
from enum import Enum
from base64 import b64encode
from cmd import Cmd
from shlex import split
from typing import List, Dict
class MyJSONEncoder(json.JSONEncoder):
@@ -23,6 +26,85 @@ class MissingDataError(RuntimeError):
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():
parser = OptionParser()
@@ -38,7 +120,15 @@ def main():
default=False,
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)
interactive_dict = []
for arg in args[1:]:
try:
this_file = WavInfoReader(path=arg)
@@ -65,7 +155,12 @@ def main():
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:
print("MissingDataError: Missing metadata (%s) in file %s" %
(e, arg), file=sys.stderr)
@@ -73,6 +168,12 @@ def main():
except Exception as e:
raise e
if len(interactive_dict) > 0:
cli = MetaBrowser()
cli.metadata = interactive_dict
cli.cmdloop()
if __name__ == "__main__":
main()