From 2430b7d5cd63eb9dfec1565801e64afc1152857d Mon Sep 17 00:00:00 2001 From: Dave O'Connor Date: Wed, 20 Jan 2021 01:21:44 +0000 Subject: [PATCH] Add initial neohub_cli --- scripts/neohub_cli.py | 115 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 116 insertions(+) create mode 100755 scripts/neohub_cli.py diff --git a/scripts/neohub_cli.py b/scripts/neohub_cli.py new file mode 100755 index 0000000..ff7fb3c --- /dev/null +++ b/scripts/neohub_cli.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: 2020-2021 Andrius Štikonas +# SPDX-FileCopyrightText: 2021 Dave O'Connor +# SPDX-License-Identifier: MIT + +import asyncio +import argparse +from inspect import ismethod, signature +from neohubapi import neohub + + +class Error(Exception): + pass + + +class NeohubCLIUsageError(Error): + pass + + +class NeohubCLI(object): + """A runner for neohub_cli operations.""" + + def __init__(self, command, args, hub_ip=None, hub_port=4242): + self._hub = neohub.NeoHub(host=hub_ip, port=hub_port) + self._command = command + self._args = args + + if command == 'help': + return + + if command not in self._hub_command_methods(): + raise NeohubCLIUsageError(f'Uknown command {command}') + + def _hub_command_methods(self): + """Return a list of NeoHub functions. + + Right now this is just all callables not starting with _ + + """ + all_methods = [ + m for m in dir(self._hub) if ismethod(getattr(self._hub, m))] + + return [m for m in all_methods if not m.startswith('_')] + + def callable(self): + """Return a bound callable for the method we want, or None.""" + if self._command == 'help': + print(self.get_help(self._args)) + return None + + # TODO(daveoc): Set special cases datetime, etc. + hubmethod = getattr(self._hub, self._command) + sig = signature(hubmethod) + if len(sig.parameters) == 0: + # No arguments + return hubmethod + + # TODO(daveoc): populate parameters and bind to methods that need them. + print(f'Cannot do {self._command} yet') + return None + + def get_help(self, args): + """Print help on what commands do""" + if len(args) == 0: + ret = 'Valid commands:\n\n' + for cmd in self._hub_command_methods(): + ret += f' - {cmd}\n' + return ret + + # handle 'help ' + if args[0] not in self._hub_command_methods(): + return f'Command {args[0]} not known' + + docstr = getattr(self._hub, args[0]).__doc__ or 'No help for {args[0]}' + sig = signature(getattr(self._hub, args[0])) + + ret = f'{args[0]}:\n' + + if len(sig.parameters) == 0: + ret += ' - No Arguments\n' + else: + for s in sig.parameters: + ret += f' - {sig.parameters[s]}\n' + + return f'{ret}\n{docstr}\n' + + +async def main(): + argp = argparse.ArgumentParser(description='CLI to neohub devices') + argp.add_argument('--hub_ip', help='IP address of Neohub', default=None) + argp.add_argument( + '--hub_port', help='Port number of Neohub to talk to', default=4242) + argp.add_argument('command', help='Command to issue') + argp.add_argument('arg', help='Arguments to command', nargs='*') + args = argp.parse_args() + + try: + nhc = NeohubCLI( + args.command, + args.arg, + hub_ip=args.hub_ip, + hub_port=args.hub_port) + m = nhc.callable() + if m: + result = await m() + # TODO(daveoc): Make delightful. + print(result) + except Error as e: + print(e) + argp.print_help() + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/setup.py b/setup.py index e1656ee..f46e7f3 100755 --- a/setup.py +++ b/setup.py @@ -27,6 +27,7 @@ setuptools.setup( long_description=long_description, long_description_content_type='text/markdown', packages=setuptools.find_packages(), + scripts=['scripts/neohub_cli.py'], keywords=['neohub', 'heatmiser'], zip_safe=True, )