From 69819d81b2da0f98afa09d09657296f0ae0e7d77 Mon Sep 17 00:00:00 2001 From: Dave O'Connor Date: Thu, 21 Jan 2021 11:16:39 +0000 Subject: [PATCH] Prettify output, add __str__ to neostat class. --- neohubapi/neostat.py | 13 +++++++++++ scripts/neohub_cli.py | 50 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/neohubapi/neostat.py b/neohubapi/neostat.py index 4d010a0..52062fd 100644 --- a/neohubapi/neostat.py +++ b/neohubapi/neostat.py @@ -98,6 +98,19 @@ class NeoStat(SimpleNamespace): _time = datetime.strptime(self.time, "%H:%M") self.time = timedelta(hours=_time.hour, minutes=_time.minute) + def __str__(self): + """ + String representation. + """ + data_elem = [] + for elem in dir(self): + if not callable(getattr(self, elem)) and not elem.startswith('_'): + data_elem.append(elem) + out = 'HeatMiser NeoStat (%s):\n' % (self.name) + for elem in data_elem: + out += ' - %s: %s\n' % (elem, getattr(self, elem)) + return out + async def identify(self): """ Flashes red LED light diff --git a/scripts/neohub_cli.py b/scripts/neohub_cli.py index ff7fb3c..8aa50c9 100755 --- a/scripts/neohub_cli.py +++ b/scripts/neohub_cli.py @@ -4,6 +4,7 @@ # SPDX-FileCopyrightText: 2021 Dave O'Connor # SPDX-License-Identifier: MIT +import types import asyncio import argparse from inspect import ismethod, signature @@ -18,6 +19,10 @@ class NeohubCLIUsageError(Error): pass +class NeohubCLIInternalError(Error): + pass + + class NeohubCLI(object): """A runner for neohub_cli operations.""" @@ -60,6 +65,47 @@ class NeohubCLI(object): print(f'Cannot do {self._command} yet') return None + def output(self, raw_result, output_format='json'): + """Produce output in a desired format.""" + if output_format == 'raw': + return raw_result + + # Right now, everything just returns hub data or a single outcome + # except get_live_data. Handle special cases. + special_case = getattr(self, f'_output_{self._command}', None) + if special_case: + return special_case(raw_result, output_format) + + if type(raw_result) in (int, str): + return f'{raw_result}' + + if type(raw_result) != types.SimpleNamespace: + raise NeohubCLIInternalError( + 'Unexpected type {type(raw_result)} in output()') + + return self._output_simplenamespace(raw_result, output_format) + + def _output_simplenamespace(self, obj, output_format): + """Output a types.Simplenamespace object.""" + if output_format == 'list': + attrs = dict( + [(a, getattr(obj, a)) for a in dir(obj) + if not a.startswith('_')]) + return '\n'.join([f'{a}: {attrs[a]}' for a in attrs]) + else: + raise NeohubCLIUsageError(f'Unknown output format {output_format}') + + def _output_get_live_data(self, raw_result, output_format): + """Return special case output for get_live_data.""" + out = self._output_simplenamespace(raw_result[0], output_format) + out += '\n\n' + for device_type in raw_result[1]: + out += f'{device_type}:\n' + devices = raw_result[1][device_type] + for d in devices: + out += str(d) + '\n' + return out + def get_help(self, args): """Print help on what commands do""" if len(args) == 0: @@ -91,6 +137,7 @@ async def main(): 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('--format', help='Output format', default='list') argp.add_argument('command', help='Command to issue') argp.add_argument('arg', help='Arguments to command', nargs='*') args = argp.parse_args() @@ -104,8 +151,7 @@ async def main(): m = nhc.callable() if m: result = await m() - # TODO(daveoc): Make delightful. - print(result) + print(nhc.output(result, output_format=args.format)) except Error as e: print(e) argp.print_help()