Skip to content

Commit 4d249dc

Browse files
committed
this update will make it possible to list all invocations without knowing the workflow id, invocations will then be grouped by workflow. The user will also have to option of outputing the list as a json.
1 parent 8b68fe7 commit 4d249dc

File tree

3 files changed

+127
-36
lines changed

3 files changed

+127
-36
lines changed

planemo/commands/cmd_list_invocations.py

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
from planemo import options
88
from planemo.cli import command_function
99
from planemo.galaxy import profiles
10-
from planemo.galaxy.api import get_invocations
10+
from planemo.galaxy.api import (
11+
get_invocations,
12+
gi,
13+
)
1114
from planemo.galaxy.workflows import remote_runnable_to_workflow_id
1215
from planemo.io import (
1316
error,
@@ -25,59 +28,106 @@
2528
@click.argument(
2629
"workflow_identifier",
2730
type=click.STRING,
31+
required=False,
32+
default="",
33+
)
34+
@click.option(
35+
"--raw",
36+
is_flag=True,
37+
help="output will be a json structure.",
38+
default=False,
39+
)
40+
@click.option(
41+
"--max_items",
42+
type=click.INT,
43+
help="max number of items returned.",
44+
default=100,
45+
)
46+
@click.option(
47+
"--offset_items",
48+
type=click.INT,
49+
help="skip first X items.",
50+
default=0,
2851
)
2952
@options.profile_option(required=True)
3053
@command_function
31-
def cli(ctx, workflow_identifier, **kwds):
54+
def cli(ctx, workflow_identifier, raw, max_items, offset_items, **kwds):
3255
"""
3356
Get a list of invocations for a particular workflow ID or alias.
3457
"""
35-
info(f"Looking for invocations for workflow {workflow_identifier}...")
36-
runnable = for_runnable_identifier(ctx, workflow_identifier, kwds)
58+
if not raw:
59+
info(f"Looking for invocations for workflow {workflow_identifier}...")
3760
profile = profiles.ensure_profile(ctx, kwds.get("profile"))
38-
assert runnable.is_remote_workflow_uri
39-
workflow_id = remote_runnable_to_workflow_id(runnable)
40-
61+
if workflow_identifier:
62+
runnable = for_runnable_identifier(ctx, workflow_identifier, kwds)
63+
assert runnable.is_remote_workflow_uri
64+
workflow_id = remote_runnable_to_workflow_id(runnable)
65+
else:
66+
workflow_id = ""
67+
gi_client = gi(None, profile["galaxy_url"], profile["galaxy_admin_key"] or profile["galaxy_user_key"])
4168
invocations = get_invocations(
42-
url=profile["galaxy_url"],
43-
key=profile["galaxy_admin_key"] or profile["galaxy_user_key"],
69+
gi=gi_client,
4470
workflow_id=workflow_id,
71+
instance=True,
72+
max_items=max_items,
73+
offset_items=offset_items,
4574
)
75+
if raw:
76+
print(json.dumps(invocations, indent=4, sort_keys=True))
77+
return
4678
if tabulate is not None:
4779
state_colors = {
4880
"ok": "\033[92m", # green
4981
"running": "\033[93m", # yellow
5082
"error": "\033[91m", # red
5183
"paused": "\033[96m", # cyan
5284
"deleted": "\033[95m", # magenta
85+
"deleting": "\033[95m", # magenta
5386
"deleted_new": "\033[95m", # magenta
5487
"new": "\033[96m", # cyan
5588
"queued": "\033[93m", # yellow
89+
"skipped": "\033[90m", # gray
5690
}
57-
print(
58-
tabulate(
59-
{
60-
"Invocation ID": invocations.keys(),
61-
"Jobs status": [
62-
", ".join([f"{state_colors[k]}{v} jobs {k}\033[0m" for k, v in inv["states"].items()])
63-
for inv in invocations.values()
64-
],
65-
"Invocation report URL": [
66-
"{}/workflows/invocations/report?id={}".format(profile["galaxy_url"].strip("/"), inv_id)
67-
for inv_id in invocations
68-
],
69-
"History URL": [
70-
"{}/histories/view?id={}".format(
71-
profile["galaxy_url"].strip("/"), invocations[inv_id]["history_id"]
72-
)
73-
for inv_id in invocations
74-
],
75-
},
76-
headers="keys",
91+
def generate_column_data(data):
92+
return {
93+
"Invocation ID": data.keys(),
94+
"Invocation report URL": [
95+
"{}/workflows/invocations/report?id={}".format(profile["galaxy_url"].strip("/"), inv_id)
96+
for inv_id in data
97+
],
98+
"History URL": [
99+
"{}/histories/view?id={}".format(
100+
profile["galaxy_url"].strip("/"), invocations[inv_id]["history_id"]
101+
)
102+
for inv_id in data
103+
],
104+
"Jobs status": [
105+
", ".join([f"{state_colors[k]}{v} jobs {k}\033[0m" for k, v in inv["states"].items()])
106+
for inv in data.values()
107+
],
108+
}
109+
110+
grouped_invocations = {}
111+
workflows = {}
112+
for inv_id, inv in invocations.items():
113+
wf_id = inv["workflow_id"]
114+
if wf_id not in grouped_invocations:
115+
workflow = gi_client.workflows.show_workflow(workflow_id=wf_id, instance=True)
116+
workflows[wf_id] = (workflow["name"], workflow["id"])
117+
grouped_invocations.setdefault(wf_id, {})[inv_id] = inv
118+
for workflow_id in grouped_invocations:
119+
header = f"Workflow: {workflows[workflow_id][0]} : {profile['galaxy_url'].strip('/')}/workflows/run?id={workflows[workflow_id][1]}"
120+
print(f"\n{header}")
121+
print(len(header) * "=")
122+
print(
123+
tabulate(
124+
generate_column_data((grouped_invocations[workflow_id])),
125+
headers="keys",
126+
)
77127
)
78-
)
79128
else:
80129
error("The tabulate package is not installed, invocations could not be listed correctly.")
81130
print(json.dumps(invocations, indent=4, sort_keys=True))
82-
info(f"{len(invocations)} invocations found.")
131+
if not raw:
132+
info(f"{len(invocations)} invocations found.")
83133
return

planemo/galaxy/api.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,21 @@ def summarize_history(ctx, gi, history_id):
114114
print("|")
115115

116116

117-
def get_invocations(url, key, workflow_id):
118-
inv_gi = gi(None, url, key)
119-
invocations = inv_gi.workflows.get_invocations(workflow_id)
117+
def get_invocations(gi, workflow_id, instance=False, max_items=100, items_per_request=20, offset_items=0):
118+
invocations = []
119+
while len(invocations) < max_items:
120+
if workflow_id:
121+
items = gi.invocations.get_invocations(workflow_id,limit=min(items_per_request, max_items), offset=len(invocations)+offset_items)
122+
else:
123+
items = gi.invocations.get_invocations(instance=instance, limit=min(items_per_request, max_items), offset=len(invocations)+offset_items)
124+
if (items is None) or (len(items) == 0):
125+
break
126+
else:
127+
invocations.extend(items)
120128
return {
121129
invocation["id"]: {
122-
"states": inv_gi.invocations.get_invocation_summary(invocation["id"])["states"],
130+
"states": gi.invocations.get_invocation_summary(invocation["id"])["states"],
131+
"workflow_id": invocation["workflow_id"],
123132
"history_id": invocation["history_id"],
124133
}
125134
for invocation in invocations

tests/test_run.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def test_run_cat_cwltool_more_options(self):
5252
job_path,
5353
]
5454
self._check_exit_code(test_cmd)
55+
5556
assert os.path.exists(os.path.join(f, "tool_test_output.html"))
5657
assert os.path.exists(os.path.join(f, "tool_test_output.json"))
5758

@@ -97,7 +98,7 @@ def test_run_cat(self):
9798
@skip_if_environ("PLANEMO_SKIP_GALAXY_CWL_TESTS")
9899
def test_run_output_directory(self):
99100
with self._isolate() as f:
100-
tool_path = _cwl_file("wc-tool.cwl")
101+
tool_path = _cwl_file("wc-tool1.0.cwl")
101102
job_path = _cwl_file("wc-job.json")
102103
test_cmd = [
103104
"--verbose",
@@ -115,3 +116,34 @@ def test_run_output_directory(self):
115116
assert os.path.exists(output_path)
116117
with open(output_path) as fh:
117118
assert fh.read().startswith(" 16 198 1111")
119+
120+
@skip_if_environ("PLANEMO_SKIP_GALAXY_TESTS")
121+
@skip_if_environ("PLANEMO_SKIP_CWLTOOL_TESTS")
122+
@skip_if_environ("PLANEMO_SKIP_GALAXY_CWL_TESTS")
123+
def test_run_download_output(self):
124+
125+
with self._isolate() as f:
126+
tool_path = _cwl_file("wc-tool1.0.cwl")
127+
job_path = _cwl_file("wc-job.json")
128+
test_cmd = [
129+
"--verbose",
130+
"run",
131+
"--no_dependency_resolution",
132+
"--output_directory",
133+
f,
134+
"--download_outputs",
135+
tool_path,
136+
job_path,
137+
]
138+
self._check_exit_code(test_cmd)
139+
assert os.path.exists(os.path.join(f, "tool_test_output.html"))
140+
assert os.path.exists(os.path.join(f, "tool_test_output.json"))
141+
output_path = os.path.join(f, "output")
142+
assert os.path.exists(output_path)
143+
files = os.listdir(f)
144+
print(files)
145+
assert False, files
146+
assert "tool_test_output.html" in files
147+
assert "tool_test_output.json" in files
148+
with open(output_path) as fh:
149+
assert fh.read().startswith(" 16 198 1111")

0 commit comments

Comments
 (0)