improve online help of frappy-cli
- help text shown exactly once (even with no or more arguments) - automatically generated client object names + stay in interactive mode even when not all clients succeded Change-Id: Iefcac66df92f47363e43bc9b97bb2082f153e5df Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30583 Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de> Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de> Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
494960a2ac
commit
746df2eb94
@ -18,7 +18,6 @@
|
||||
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# Module authors:
|
||||
# Alexander Lenz <alexander.lenz@frm2.tum.de>
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
@ -34,7 +33,43 @@ sys.path.insert(0, path.abspath(path.join(path.dirname(__file__), '..')))
|
||||
|
||||
from frappy.client.interactive import Client, watch
|
||||
|
||||
for node in sys.argv[1:]:
|
||||
Client(node)
|
||||
_USAGE = """
|
||||
Usage:
|
||||
%s
|
||||
# for all SECoP modules objects are created in the main namespace
|
||||
|
||||
code.interact(banner='', local=sys.modules['__main__'].__dict__)
|
||||
<module> # list all parameters
|
||||
<module>.<param> = <value> # change parameter
|
||||
<module>(<target>) # set target and wait until not busy
|
||||
# 'status' and 'value' changes are shown every 1 sec
|
||||
%s.mininterval = 0.2 # change minimal update interval to 0.2 sec (default is 1 second)
|
||||
|
||||
watch(T) # watch changes of T.status and T.value (stop with ctrl-C)
|
||||
watch(T='status target') # watch status and target parameters
|
||||
watch(io, T=True) # watch io and all parameters of T
|
||||
"""
|
||||
|
||||
_CLIENT_USAGE = """
|
||||
c = Client('localhost:5000')
|
||||
"""
|
||||
|
||||
Client.show_usage = False
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
_usage_args = ("\ncli = Client('localhost:5000')\n", 'cli')
|
||||
success = True
|
||||
else:
|
||||
_usage_args = ('', '_c0')
|
||||
success = False
|
||||
|
||||
for _idx, _node in enumerate(sys.argv[1:]):
|
||||
_client_name = '_c%d' % _idx
|
||||
try:
|
||||
setattr(sys.modules['__main__'], _client_name, Client(_node, name=_client_name))
|
||||
success = True
|
||||
except Exception as e:
|
||||
print(repr(e))
|
||||
|
||||
if success:
|
||||
print(_USAGE % _usage_args)
|
||||
code.interact(banner='', local=sys.modules['__main__'].__dict__)
|
||||
|
@ -19,17 +19,8 @@
|
||||
# Markus Zolliker <markus.zolliker@psi.ch>
|
||||
#
|
||||
# *****************************************************************************
|
||||
"""simple interactive python client"""
|
||||
"""simple interactive python client
|
||||
|
||||
import sys
|
||||
import time
|
||||
import re
|
||||
from queue import Queue
|
||||
from frappy.client import SecopClient
|
||||
from frappy.errors import SECoPError
|
||||
from frappy.datatypes import get_datatype
|
||||
|
||||
USAGE = """
|
||||
Usage:
|
||||
|
||||
from frappy.client.interactive import Client
|
||||
@ -48,12 +39,22 @@ watch(T='status target') # watch status and target parameters
|
||||
watch(io, T=True) # watch io and all parameters of T
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import re
|
||||
from queue import Queue
|
||||
from frappy.client import SecopClient
|
||||
from frappy.errors import SECoPError
|
||||
from frappy.datatypes import get_datatype
|
||||
|
||||
main = sys.modules['__main__']
|
||||
|
||||
LOG_LEVELS = {'debug', 'comlog', 'info', 'warning', 'error', 'off'}
|
||||
|
||||
|
||||
class Logger:
|
||||
show_time = False
|
||||
|
||||
def __init__(self, loglevel='info'):
|
||||
func = self.noop
|
||||
for lev in 'debug', 'info', 'warning', 'error':
|
||||
@ -63,12 +64,15 @@ class Logger:
|
||||
self._minute = 0
|
||||
|
||||
def emit(self, fmt, *args, **kwds):
|
||||
now = time.time()
|
||||
minute = now // 60
|
||||
if minute != self._minute:
|
||||
self._minute = minute
|
||||
print(time.strftime('--- %H:%M:%S ---', time.localtime(now)))
|
||||
print('%6.3f' % (now % 60.0), str(fmt) % args)
|
||||
if self.show_time:
|
||||
now = time.time()
|
||||
minute = now // 60
|
||||
if minute != self._minute:
|
||||
self._minute = minute
|
||||
print(time.strftime('--- %H:%M:%S ---', time.localtime(now)))
|
||||
print('%6.3f' % (now % 60.0), str(fmt) % args)
|
||||
else:
|
||||
print(str(fmt) % args)
|
||||
|
||||
@staticmethod
|
||||
def noop(fmt, *args, **kwds):
|
||||
@ -200,7 +204,6 @@ class Module:
|
||||
return self.read()
|
||||
self.target = target # this sets self._running
|
||||
type(self).value.prev = None # show at least one value
|
||||
show_final_value = True
|
||||
try:
|
||||
while self._running.get():
|
||||
self._watch_parameter(self._name, 'value', mininterval=self._secnode.mininterval)
|
||||
@ -210,7 +213,7 @@ class Module:
|
||||
self._running = None
|
||||
self._watch_parameter(self._name, 'status')
|
||||
self._secnode.readParameter(self._name, 'value')
|
||||
self._watch_parameter(self._name, 'value', forced=show_final_value)
|
||||
self._watch_parameter(self._name, 'value', forced=True)
|
||||
return self.value
|
||||
|
||||
def __repr__(self):
|
||||
@ -319,29 +322,36 @@ class Client(SecopClient):
|
||||
secnodes = {}
|
||||
mininterval = 1
|
||||
|
||||
def __init__(self, uri, loglevel='info'):
|
||||
def __init__(self, uri, loglevel='info', name=''):
|
||||
# remove previous client:
|
||||
prev = self.secnodes.pop(uri, None)
|
||||
log = Logger(loglevel)
|
||||
removed_modules = []
|
||||
if prev:
|
||||
prev.log.info('remove previous client to %s', uri)
|
||||
log.info('remove previous client to %s', uri)
|
||||
for modname in prev.modules:
|
||||
prevnode = getattr(getattr(main, modname, None), '_secnode', None)
|
||||
if prevnode == prev:
|
||||
prev.log.info('remove previous module %s', modname)
|
||||
removed_modules.append(modname)
|
||||
delattr(main, modname)
|
||||
prev.disconnect()
|
||||
self.secnodes[uri] = self
|
||||
super().__init__(uri, Logger(loglevel))
|
||||
if name:
|
||||
log.info('\n>>> %s = Client(%r)', name, uri)
|
||||
super().__init__(uri, log)
|
||||
self.connect()
|
||||
created_modules = []
|
||||
skipped_modules = []
|
||||
for modname, moddesc in self.modules.items():
|
||||
prev = getattr(main, modname, None)
|
||||
if prev is None:
|
||||
self.log.info('create module %s', modname)
|
||||
created_modules.append(modname)
|
||||
else:
|
||||
if getattr(prev, '_secnode', None) is None:
|
||||
self.log.error('skip module %s overwriting a global variable' % modname)
|
||||
skipped_modules.append(modname)
|
||||
continue
|
||||
self.log.info('overwrite module %s', modname)
|
||||
removed_modules.append(modname)
|
||||
created_modules.append(modname)
|
||||
attrs = {}
|
||||
for pname, pinfo in moddesc['parameters'].items():
|
||||
attrs[pname] = Param(pname, pinfo['datainfo'])
|
||||
@ -352,8 +362,14 @@ class Client(SecopClient):
|
||||
self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update)
|
||||
self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update)
|
||||
setattr(main, modname, mobj)
|
||||
if removed_modules:
|
||||
self.log.info('removed modules: %s', ' '.join(removed_modules))
|
||||
if skipped_modules:
|
||||
self.log.info('skipped modules overwriting globals: %s', ' '.join(skipped_modules))
|
||||
if created_modules:
|
||||
self.log.info('created modules: %s', ' '.join(created_modules))
|
||||
self.register_callback(None, self.unhandledMessage)
|
||||
self.log.info('%s', USAGE)
|
||||
log.show_time = True
|
||||
|
||||
def unhandledMessage(self, action, ident, data):
|
||||
"""handle logging messages"""
|
||||
@ -365,3 +381,6 @@ class Client(SecopClient):
|
||||
return
|
||||
self.log.info('module %s not found', modname)
|
||||
self.log.info('unhandled: %s %s %r', action, ident, data)
|
||||
|
||||
def __repr__(self):
|
||||
return 'Client(%r)' % self.uri
|
||||
|
Loading…
x
Reference in New Issue
Block a user