Skip to content

Commit

Permalink
Merge pull request #2046 from matthewrmshin/cylc-show-multitask
Browse files Browse the repository at this point in the history
cylc show: multi-task interface
  • Loading branch information
hjoliver authored Oct 31, 2016
2 parents 4e68d7d + a027a88 commit 72cc728
Show file tree
Hide file tree
Showing 15 changed files with 280 additions and 174 deletions.
2 changes: 1 addition & 1 deletion bin/cylc-insert
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def main():
else:
items = args
for i, item in enumerate(items):
if not TaskID.is_valid_id_for_insert(item):
if not TaskID.is_valid_id_2(item):
sys.exit('ERROR: "%s": invalid task ID (argument %d)' % (
item, i + 1))
prompt('Insert %s in %s' % (items, suite), options.force)
Expand Down
108 changes: 49 additions & 59 deletions bin/cylc-show
Original file line number Diff line number Diff line change
Expand Up @@ -37,80 +37,70 @@ from cylc.task_id import TaskID


def main():
"""Implement "cylc show" CLI."""
parser = COP(
__doc__, comms=True, noforce=True,
argdoc=[('REG', 'Suite name'),
('[' + TaskID.SYNTAX_OPT_POINT + ']', 'Task name or ID')])
__doc__, comms=True, noforce=True, multitask=True,
argdoc=[
('REG', 'Suite name'),
('[TASKID ...]', 'Task names or identifiers')])

(options, args) = parser.parse_args()
options, args = parser.parse_args()
suite = args[0]
task_args = args[1:]

pclient = SuiteInfoClient(
suite, options.owner, options.host, options.comms_timeout,
options.port, options.db, my_uuid=options.set_uuid,
print_uuid=options.print_uuid
)

if len(args) == 1:
if not task_args:
# Print suite info.
suite_info = pclient.get_info('get_suite_info')
for key, value in sorted(suite_info.items(), reverse=True):
print '%s: %s' % (key, value or "(not given)")
sys.exit(0)

point_string = None
arg = args[1]
try:
name, point_string = TaskID.split(arg)
except ValueError:
# Print task info.
name = arg
else:
# Print task instance info.
task_id = arg

info = pclient.get_info('get_task_info', name=name)
if not info:
sys.exit("ERROR: task not found: %s" % name)
for key, value in sorted(info.items(), reverse=True):
print "%s: %s" % (key, value or "(not given)")

if point_string is not None:
result = pclient.get_info('get_task_requisites',
name=name,
point_string=point_string)
if not result:
sys.exit("ERROR: task instance not found: %s" % task_id)

for task_id in result.keys():
[pre, out, extra_info] = result[task_id]

print '\nprerequisites (- => not satisfied):'
if len(pre) == 0:
print ' (None)'
for item in sorted(pre):
[msg, state] = item
if state:
descr = ' + '
else:
descr = ' - '
print descr + msg

print '\noutputs (- => not completed):'
if len(out) == 0:
print ' (None)'
for item in sorted(out):
[msg, state] = item
if state:
descr = ' + '
else:
descr = ' - '
print descr + msg

if len(extra_info.keys()) > 0:
return

task_names = [arg for arg in task_args if TaskID.is_valid_name(arg)]
task_ids = [arg for arg in task_args if TaskID.is_valid_id_2(arg)]

if task_names:
results = pclient.get_info('get_task_info', names=task_names)
for task_name, result in sorted(results.items()):
if len(results) > 1:
print "----\nTASK NAME: %s" % task_name
for key, value in sorted(result.items(), reverse=True):
print "%s: %s" % (key, value or "(not given)")

if task_ids:
results, bad_items = pclient.get_info(
'get_task_requisites', items=task_ids)
for task_id, result in sorted(results.items()):
if len(results) > 1:
print "----\nTASK ID: %s" % task_id
for key, value in sorted(
result["descriptions"].items(), reverse=True):
print "%s: %s" % (key, value or "(not given)")

for name, done in [
("prerequisites", "satisfied"), ("outputs", "completed")]:
print '\n%s (- => not %s):' % (name, done)
if not result[name]:
print ' (None)'
for msg, state in sorted(result[name]):
if state:
print ' + ' + msg
else:
print ' - ' + msg

if result["extras"]:
print '\nother:'
for item in extra_info:
print ' o ', item, '...', extra_info[item]
for key, value in result["extras"].items():
print ' o %s ... %s' % (key, value)
for bad_item in bad_items:
sys.stderr.write("No matching tasks found: %s\n" % bad_item)
if bad_items:
sys.exit(1)


if __name__ == "__main__":
Expand Down
79 changes: 30 additions & 49 deletions lib/cylc/gui/app_gcylc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1553,18 +1553,17 @@ def update_tb(self, tb, line, tags=None):
tb.insert(tb.get_end_iter(), line)

def popup_requisites(self, w, e, task_id):
"""Show prerequisites of task_id in a pop up window."""
name, point_string = TaskID.split(task_id)
result = self.get_comms_info(
'get_task_requisites', name=name, point_string=point_string)
if result:
# (else no tasks were found at all -suite shutting down)
if task_id not in result:
warning_dialog(
"Task proxy " + task_id +
" not found in " + self.cfg.suite +
".\nTasks are removed once they are no longer needed.",
self.window).warn()
return
results, bad_items = self.get_comms_info(
'get_task_requisites', items=[task_id])
if not results or task_id in bad_items:
warning_dialog(
"Task proxy " + task_id +
" not found in " + self.cfg.suite +
".\nTasks are removed once they are no longer needed.",
self.window).warn()
return

window = gtk.Window()
window.set_title(task_id + " State")
Expand Down Expand Up @@ -1595,45 +1594,27 @@ def popup_requisites(self, w, e, task_id):
self.update_tb(tb, 'TASK ', [bold])
self.update_tb(tb, task_id, [bold, blue])
self.update_tb(tb, ' in SUITE ', [bold])
self.update_tb(tb, self.cfg.suite + '\n\n', [bold, blue])

[pre, out, extra_info] = result[task_id]

self.update_tb(tb, 'Prerequisites', [bold])
self.update_tb(tb, ' (')
self.update_tb(tb, 'red', [red])
self.update_tb(tb, '=> NOT satisfied)\n')

if len(pre) == 0:
self.update_tb(tb, ' - (None)\n')
for item in pre:
[msg, state] = item
if state:
tags = None
else:
tags = [red]
self.update_tb(tb, ' - ' + msg + '\n', tags)

self.update_tb(tb, '\nOutputs', [bold])
self.update_tb(tb, ' (')
self.update_tb(tb, 'red', [red])
self.update_tb(tb, '=> NOT completed)\n')

if len(out) == 0:
self.update_tb(tb, ' - (None)\n')
for item in out:
[msg, state] = item
if state:
tags = []
else:
tags = [red]
self.update_tb(tb, ' - ' + msg + '\n', tags)
self.update_tb(tb, self.cfg.suite + '\n', [bold, blue])

for name, done in [
("prerequisites", "satisfied"), ("outputs", "completed")]:
self.update_tb(tb, '\n' + name.title(), [bold])
self.update_tb(tb, ' (')
self.update_tb(tb, 'red', [red])
self.update_tb(tb, '=> NOT %s)\n' % done)
if not results[task_id][name]:
self.update_tb(tb, ' - (None)\n')
for msg, state in results[task_id][name]:
if state:
tags = None
else:
tags = [red]
self.update_tb(tb, ' - ' + msg + '\n', tags)

if len(extra_info.keys()) > 0:
if results[task_id]['extras']:
self.update_tb(tb, '\nOther\n', [bold])
for item in extra_info:
self.update_tb(
tb, ' - ' + item + ': ' + str(extra_info[item]) + '\n')
for key, value in results[task_id]['extras'].items():
self.update_tb(tb, ' - %s: %s\n' % (key, value))

self.update_tb(tb, '\nNOTE: ', [bold])
self.update_tb(
Expand Down Expand Up @@ -2180,7 +2161,7 @@ def insert_task(self, w, window, entry_task_ids, entry_stop_point):
warning_dialog('Enter valid task/family IDs', self.window).warn()
return
for i, task_id in enumerate(task_ids):
if not TaskID.is_valid_id_for_insert(task_id):
if not TaskID.is_valid_id_2(task_id):
warning_dialog(
'"%s": invalid task ID (argument %d)' % (task_id, i + 1),
self.window).warn()
Expand Down
12 changes: 8 additions & 4 deletions lib/cylc/network/https/suite_info_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ def get_suite_info(self):

@cherrypy.expose
@cherrypy.tools.json_out()
def get_task_info(self, name):
return self._put("get_task_info", (name,))
def get_task_info(self, names):
if not isinstance(names, list):
names = [names]
return self._put("get_task_info", (names,))

@cherrypy.expose
@cherrypy.tools.json_out()
Expand Down Expand Up @@ -114,8 +116,10 @@ def get_graph_raw(self, start_point_string, stop_point_string,

@cherrypy.expose
@cherrypy.tools.json_out()
def get_task_requisites(self, name, point_string):
return self._put("get_task_requisites", (name, point_string))
def get_task_requisites(self, items):
if not isinstance(items, list):
items = [items]
return self._put("get_task_requisites", (items,))

def _put(self, command, command_args, command_kwargs=None):
if command_args is None:
Expand Down
18 changes: 10 additions & 8 deletions lib/cylc/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -769,12 +769,15 @@ def info_get_suite_info(self):
return {'title': self.config.cfg['title'],
'description': self.config.cfg['description']}

def info_get_task_info(self, name):
def info_get_task_info(self, names):
"""Return info of a task."""
try:
return self.config.describe(name)
except KeyError:
return {}
results = {}
for name in names:
try:
results[name] = self.config.describe(name)
except KeyError:
results[name] = {}
return results

def info_get_all_families(self, exclude_root=False):
"""Return info of all families."""
Expand Down Expand Up @@ -804,10 +807,9 @@ def info_get_graph_raw(self, cto, ctn, group_nodes=None,
rgraph, self.config.suite_polling_tasks, self.config.leaves,
self.config.feet)

def info_get_task_requisites(self, name, point_string):
def info_get_task_requisites(self, items):
"""Return prerequisites of a task."""
return self.pool.get_task_requisites(
TaskID.get(name, self.get_standardised_point_string(point_string)))
return self.pool.get_task_requisites(items)

def command_set_stop_cleanly(self, kill_active_tasks=False):
"""Stop job submission and set the flag for clean shutdown."""
Expand Down
4 changes: 2 additions & 2 deletions lib/cylc/task_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ def is_valid_id(cls, id_str):
point and cls.POINT_REC.match(point))

@classmethod
def is_valid_id_for_insert(cls, id_str):
"""Return whether id_str is good as an insert client argument.
def is_valid_id_2(cls, id_str):
"""Return whether id_str is good as a client argument for e.g. insert.
Return True if "." or "/" appears once in the string. Cannot really
do more as the string may have wildcards.
Expand Down
Loading

0 comments on commit 72cc728

Please sign in to comment.