cli.py
200 lines
| 6.3 KiB
| text/x-python
|
PythonLexer
|
r934 | import click | ||
import schainpy | ||||
|
r935 | import subprocess | ||
|
r936 | import os | ||
import sys | ||||
import glob | ||||
|
r944 | save_stdout = sys.stdout | ||
|
r1180 | sys.stdout = open('/dev/null', 'w') | ||
|
r943 | from multiprocessing import cpu_count | ||
|
r1047 | from schainpy.controller import Project | ||
|
r944 | from schainpy.model import Operation, ProcessingUnit | ||
|
r943 | from schainpy.utils import log | ||
|
r944 | from importlib import import_module | ||
from pydoc import locate | ||||
from fuzzywuzzy import process | ||||
|
r1180 | from schainpy.cli import templates | ||
|
r944 | sys.stdout = save_stdout | ||
|
r934 | |||
|
r1180 | def getProcs(): | ||
modules = dir(schainpy.model) | ||||
procs = check_module(modules, ProcessingUnit) | ||||
try: | ||||
procs.remove('ProcessingUnit') | ||||
except Exception as e: | ||||
pass | ||||
return procs | ||||
def getOperations(): | ||||
module = dir(schainpy.model) | ||||
noProcs = [x for x in module if not x.endswith('Proc')] | ||||
operations = check_module(noProcs, Operation) | ||||
try: | ||||
operations.remove('Operation') | ||||
except Exception as e: | ||||
pass | ||||
return operations | ||||
def getArgs(op): | ||||
module = locate('schainpy.model.{}'.format(op)) | ||||
args = module().getAllowedArgs() | ||||
try: | ||||
args.remove('self') | ||||
except Exception as e: | ||||
pass | ||||
try: | ||||
args.remove('dataOut') | ||||
except Exception as e: | ||||
pass | ||||
return args | ||||
def getAll(): | ||||
allModules = dir(schainpy.model) | ||||
modules = check_module(allModules, Operation) | ||||
modules.extend(check_module(allModules, ProcessingUnit)) | ||||
return modules | ||||
|
r934 | def print_version(ctx, param, value): | ||
if not value or ctx.resilient_parsing: | ||||
return | ||||
click.echo(schainpy.__version__) | ||||
ctx.exit() | ||||
|
r944 | |||
PREFIX = 'experiment' | ||||
|
r934 | @click.command() | ||
@click.option('--version', '-v', is_flag=True, callback=print_version, help='SChain version', type=str) | ||||
@click.argument('command', default='run', required=True) | ||||
|
r944 | @click.argument('nextcommand', default=None, required=False, type=str) | ||
|
r1081 | def main(command, nextcommand, version): | ||
|
r946 | """COMMAND LINE INTERFACE FOR SIGNAL CHAIN - JICAMARCA RADIO OBSERVATORY \n | ||
Available commands.\n | ||||
--xml: runs a schain XML generated file\n | ||||
run: runs any python script starting 'experiment_'\n | ||||
generate: generates a template schain script\n | ||||
search: return avilable operations, procs or arguments of the give operation/proc\n""" | ||||
|
r1081 | if command == 'xml': | ||
runFromXML(nextcommand) | ||||
|
r935 | elif command == 'generate': | ||
|
r934 | generate() | ||
elif command == 'test': | ||||
test() | ||||
|
r936 | elif command == 'run': | ||
|
r944 | runschain(nextcommand) | ||
elif command == 'search': | ||||
search(nextcommand) | ||||
else: | ||||
log.error('Command {} is not defined'.format(command)) | ||||
|
r1081 | |||
|
r944 | def check_module(possible, instance): | ||
def check(x): | ||||
try: | ||||
instancia = locate('schainpy.model.{}'.format(x)) | ||||
return isinstance(instancia(), instance) | ||||
except Exception as e: | ||||
return False | ||||
clean = clean_modules(possible) | ||||
return [x for x in clean if check(x)] | ||||
def clean_modules(module): | ||||
noEndsUnder = [x for x in module if not x.endswith('__')] | ||||
noStartUnder = [x for x in noEndsUnder if not x.startswith('__')] | ||||
noFullUpper = [x for x in noStartUnder if not x.isupper()] | ||||
return noFullUpper | ||||
def search(nextcommand): | ||||
if nextcommand is None: | ||||
|
r1180 | log.error('There is no Operation/ProcessingUnit to search', '') | ||
|
r944 | elif nextcommand == 'procs': | ||
|
r1180 | procs = getProcs() | ||
|
r1081 | log.success( | ||
|
r1180 | 'Current ProcessingUnits are:\n{}'.format('\n'.join(procs)), '') | ||
|
r944 | |||
elif nextcommand == 'operations': | ||||
|
r1180 | operations = getOperations() | ||
log.success('Current Operations are:\n{}'.format( | ||||
'\n'.join(operations)), '') | ||||
|
r944 | else: | ||
try: | ||||
|
r1180 | args = getArgs(nextcommand) | ||
|
r945 | if len(args) == 0: | ||
|
r1180 | log.success('`{}` has no arguments'.format(nextcommand), '') | ||
|
r945 | else: | ||
|
r1180 | log.success('`{}` arguments: {}'.format( | ||
nextcommand, ', '.join(args)), '') | ||||
|
r944 | except Exception as e: | ||
|
r1180 | log.error('Module `{}` does not exists'.format(nextcommand), '') | ||
allModules = getAll() | ||||
similar = [t[0] for t in process.extract(nextcommand, allModules, limit=12) if t[1]>80] | ||||
log.success('Possible modules are: {}'.format(', '.join(similar)), '') | ||||
|
r944 | |||
def runschain(nextcommand): | ||||
if nextcommand is None: | ||||
currentfiles = glob.glob('./{}_*.py'.format(PREFIX)) | ||||
numberfiles = len(currentfiles) | ||||
if numberfiles > 1: | ||||
log.error('There is more than one file to run') | ||||
elif numberfiles == 1: | ||||
subprocess.call(['python ' + currentfiles[0]], shell=True) | ||||
|
r936 | else: | ||
|
r944 | log.error('There is no file to run') | ||
|
r934 | else: | ||
|
r944 | try: | ||
subprocess.call(['python ' + nextcommand], shell=True) | ||||
except Exception as e: | ||||
log.error("I cannot run the file. Does it exists?") | ||||
|
r934 | |||
|
r939 | |||
|
r935 | def basicInputs(): | ||
|
r934 | inputs = {} | ||
|
r1081 | inputs['desc'] = click.prompt( | ||
'Enter a description', default="A schain project", type=str) | ||||
inputs['name'] = click.prompt( | ||||
'Name of the project', default="project", type=str) | ||||
inputs['path'] = click.prompt('Data path', default=os.getcwd( | ||||
), type=click.Path(exists=True, resolve_path=True)) | ||||
inputs['startDate'] = click.prompt( | ||||
'Start date', default='1970/01/01', type=str) | ||||
inputs['endDate'] = click.prompt( | ||||
'End date', default='2017/12/31', type=str) | ||||
inputs['startHour'] = click.prompt( | ||||
'Start hour', default='00:00:00', type=str) | ||||
|
r934 | inputs['endHour'] = click.prompt('End hour', default='23:59:59', type=str) | ||
|
r935 | inputs['figpath'] = inputs['path'] + '/figs' | ||
return inputs | ||||
|
r939 | |||
|
r935 | def generate(): | ||
inputs = basicInputs() | ||||
inputs['multiprocess'] = click.confirm('Is this a multiprocess script?') | ||||
if inputs['multiprocess']: | ||||
|
r1081 | inputs['nProcess'] = click.prompt( | ||
'How many process?', default=cpu_count(), type=int) | ||||
|
r935 | current = templates.multiprocess.format(**inputs) | ||
else: | ||||
current = templates.basic.format(**inputs) | ||||
|
r944 | scriptname = '{}_{}.py'.format(PREFIX, inputs['name']) | ||
|
r935 | script = open(scriptname, 'w') | ||
try: | ||||
script.write(current) | ||||
|
r944 | log.success('Script {} generated'.format(scriptname)) | ||
|
r935 | except Exception as e: | ||
|
r943 | log.error('I cannot create the file. Do you have writing permissions?') | ||
|
r935 | |||
|
r934 | |||
def test(): | ||||
|
r943 | log.warning('testing') | ||
|
r939 | |||
def runFromXML(filename): | ||||
|
r1047 | controller = Project() | ||
|
r939 | if not controller.readXml(filename): | ||
return | ||||
controller.start() | ||||
return | ||||