Skip to content

Commit

Permalink
Merge pull request #1076 from simonbray/gxwf-integration
Browse files Browse the repository at this point in the history
Integrate some features from gxwf
  • Loading branch information
jmchilton authored Nov 23, 2020
2 parents 7c13e46 + bcc02f2 commit 1f9fdff
Show file tree
Hide file tree
Showing 21 changed files with 481 additions and 79 deletions.
37 changes: 37 additions & 0 deletions planemo/commands/cmd_create_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Module describing the planemo ``create_alias`` command."""
import click

from planemo import options
from planemo.cli import command_function
from planemo.galaxy import profiles
from planemo.io import info

try:
import namesgenerator
except ImportError:
namesgenerator = None


@click.command('create_alias')
@click.argument(
"obj",
metavar="OBJ",
type=click.STRING,
)
@options.alias_option()
@options.profile_option(required=True)
@command_function
def cli(ctx, alias, obj, profile, **kwds):
"""
Add an alias for a path or a workflow or dataset ID. Aliases are associated with a particular planemo profile.
"""
if not alias:
if not namesgenerator:
raise ImportError(("Random generation of aliases requires installation of the namesgenerator package."
"Either install this, or specify the alias name with --alias."))
alias = namesgenerator.get_random_name()

exit_code = profiles.create_alias(ctx, alias, obj, profile)
info("Alias {} created.".format(alias))
ctx.exit(exit_code)
return
31 changes: 31 additions & 0 deletions planemo/commands/cmd_delete_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Module describing the planemo ``delete_alias`` command."""
import click

from planemo import options
from planemo.cli import command_function
from planemo.galaxy import profiles
from planemo.io import error, info

try:
from tabulate import tabulate
except ImportError:
tabulate = None # type: ignore


@click.command('delete_alias')
@options.alias_option(required=True)
@options.profile_option(required=True)
@command_function
def cli(ctx, alias, profile, **kwds):
"""
List aliases for a path or a workflow or dataset ID. Aliases are associated with a particular planemo profile.
"""
info("Looking for profiles...")
exit_code = profiles.delete_alias(ctx, alias, profile)
if exit_code == 0:
info('Alias {} was successfully deleted from profile {}'.format(alias, profile))
else:
error('Alias {} does not exist, so was not deleted from profile {}'.format(alias, profile))

ctx.exit(exit_code)
return
34 changes: 34 additions & 0 deletions planemo/commands/cmd_list_alias.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""Module describing the planemo ``list_alias`` command."""
import json

import click

from planemo import options
from planemo.cli import command_function
from planemo.galaxy import profiles
from planemo.io import info

try:
from tabulate import tabulate
except ImportError:
tabulate = None # type: ignore


@click.command('list_alias')
@options.profile_option(required=True)
@command_function
def cli(ctx, profile, **kwds):
"""
List aliases for a path or a workflow or dataset ID. Aliases are associated with a particular planemo profile.
"""
info("Looking for profiles...")
aliases = profiles.list_alias(ctx, profile)
if tabulate:
print(tabulate({"Alias": aliases.keys(), "Object": aliases.values()}, headers="keys"))
else:
print(json.dumps(aliases, indent=4, sort_keys=True))

info("{} aliases were found for profile {}.".format(len(aliases), profile))

ctx.exit(0)
return
61 changes: 61 additions & 0 deletions planemo/commands/cmd_list_invocations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Module describing the planemo ``list_invocations`` command."""
import json

import click

from planemo import options
from planemo.cli import command_function
from planemo.galaxy import profiles
from planemo.galaxy.api import get_invocations
from planemo.galaxy.profiles import translate_alias
from planemo.io import error, info

try:
from tabulate import tabulate
except ImportError:
tabulate = None # type: ignore


@click.command('list_invocations')
@click.argument(
"workflow_id",
type=click.STRING,
)
@options.profile_option(required=True)
@command_function
def cli(ctx, workflow_id, **kwds):
"""
Get a list of invocations for a particular workflow ID or alias.
"""
workflow_id = translate_alias(ctx, workflow_id, kwds.get('profile'))
info("Looking for invocations for workflow {}...".format(workflow_id))
workflow_id = profiles.translate_alias(ctx, workflow_id, kwds.get('profile'))
profile = profiles.ensure_profile(ctx, kwds.get('profile'))

invocations = get_invocations(url=profile['galaxy_url'], key=profile['galaxy_admin_key'] or profile['galaxy_user_key'], workflow_id=workflow_id)
if tabulate:
state_colors = {
'ok': '\033[92m', # green
'running': '\033[93m', # yellow
'error': '\033[91m', # red
'paused': '\033[96m', # cyan
'deleted': '\033[95m', # magenta
'deleted_new': '\033[95m', # magenta
'new': '\033[96m', # cyan
'queued': '\033[93m', # yellow
}
print(tabulate({
"Invocation ID": invocations.keys(),
"Jobs status": [', '.join(['{}{} jobs {}\033[0m'.format(state_colors[k], v, k) for k, v in inv['states'].items()]
) for inv in invocations.values()],
"Invocation report URL": ['{}/workflows/invocations/report?id={}'.format(profile['galaxy_url'].strip('/'), inv_id
) for inv_id in invocations],
"History URL": ['{}/histories/view?id={}'.format(profile['galaxy_url'].strip('/'), invocations[inv_id]['history_id']
) for inv_id in invocations]
}, headers="keys"))
else:
error("The tabulate package is not installed, invocations could not be listed correctly.")
print(json.dumps(invocations, indent=4, sort_keys=True))
info("{} invocations found.".format(len(invocations)))

return
3 changes: 3 additions & 0 deletions planemo/commands/cmd_profile_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
@options.profile_database_options()
@options.serve_engine_option()
@options.docker_config_options()
@options.galaxy_url_option()
@options.galaxy_user_key_option()
@options.galaxy_admin_key_option()
@command_function
def cli(ctx, profile_name, **kwds):
"""Create a profile."""
Expand Down
6 changes: 5 additions & 1 deletion planemo/commands/cmd_profile_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@

from planemo.cli import command_function
from planemo.galaxy import profiles
from planemo.io import info


@click.command('profile_list')
@command_function
def cli(ctx, **kwds):
"""List configured profile names."""
info("Looking for profiles...")
profile_names = profiles.list_profiles(ctx, **kwds)
print(profile_names)
for profile in profile_names:
print(profile)
info("{} configured profiles are available.".format(len(profile_names)))
23 changes: 14 additions & 9 deletions planemo/commands/cmd_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
from __future__ import print_function

import json
import os

import click
from galaxy.util import unicodify

from planemo import options
from planemo.cli import command_function
from planemo.engine import engine_context
from planemo.galaxy.profiles import translate_alias
from planemo.io import warn
from planemo.runnable import for_id, for_path
from planemo.tools import uri_to_path


@click.command('run')
@options.required_tool_arg(allow_uris=True)
@options.required_runnable_arg()
@options.required_job_arg()
@options.galaxy_run_options()
@options.galaxy_config_options()
Expand All @@ -24,14 +27,20 @@
@options.run_output_json_option()
@options.engine_options()
@command_function
def cli(ctx, uri, job_path, **kwds):
def cli(ctx, runnable_identifier, job_path, **kwds):
"""Planemo command for running tools and jobs.
\b
% planemo run cat1-tool.cwl cat-job.json
"""
path = uri_to_path(ctx, uri)
# TODO: convert UI to runnable and do a better test of cwl.
runnable_identifier = translate_alias(ctx, runnable_identifier, kwds.get('profile'))
path = uri_to_path(ctx, runnable_identifier)
if os.path.exists(path):
runnable = for_path(path)
else: # assume galaxy workflow id
runnable = for_id(runnable_identifier)

# TODO: do a better test of cwl.
is_cwl = path.endswith(".cwl")
kwds["cwl"] = is_cwl
if kwds.get("engine", None) is None:
Expand All @@ -41,16 +50,12 @@ def cli(ctx, uri, job_path, **kwds):
kwds["engine"] = "external_galaxy"
else:
kwds["engine"] = "galaxy"

with engine_context(ctx, **kwds) as engine:
run_result = engine.run(path, job_path)

run_result = engine.run(runnable, job_path)
if not run_result.was_successful:
warn("Run failed [%s]" % unicodify(run_result))
ctx.exit(1)

outputs_dict = run_result.outputs_dict
print(outputs_dict)
output_json = kwds.get("output_json", None)
if output_json:
with open(output_json, "w") as f:
Expand Down
4 changes: 0 additions & 4 deletions planemo/commands/cmd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@
"instances to limit generated traffic.",
default="0",
)
@click.option(
"--history_name",
help="Name for history (if a history is generated as part of testing.)"
)
@options.galaxy_target_options()
@options.galaxy_config_options()
@options.test_options()
Expand Down
18 changes: 14 additions & 4 deletions planemo/commands/cmd_workflow_edit.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Module describing the planemo ``workflow_edit`` command."""
import os

import click

from planemo import options
Expand All @@ -7,8 +9,10 @@
engine_context,
is_galaxy_engine,
)
from planemo.galaxy.profiles import translate_alias
from planemo.galaxy.serve import sleep_for_serve
from planemo.runnable import (
for_id,
for_path,
)

Expand All @@ -17,17 +21,23 @@
@options.required_workflow_arg()
@options.galaxy_serve_options()
@command_function
def cli(ctx, workflow_path, output=None, force=False, **kwds):
def cli(ctx, workflow_identifier, output=None, force=False, **kwds):
"""Open a synchronized Galaxy workflow editor.
"""
assert is_galaxy_engine(**kwds)

workflow_identifier = translate_alias(ctx, workflow_identifier, kwds.get('profile'))
if os.path.exists(workflow_identifier):
runnable = for_path(workflow_identifier)
else: # assume galaxy workflow id
runnable = for_id(workflow_identifier)

kwds["workflows_from_path"] = True

runnable = for_path(workflow_path)
with engine_context(ctx, **kwds) as galaxy_engine:
with galaxy_engine.ensure_runnables_served([runnable]) as config:
workflow_id = config.workflow_id(workflow_path)
workflow_id = config.workflow_id_for_runnable(runnable)
url = "%s/workflow/editor?id=%s" % (config.galaxy_url, workflow_id)
click.launch(url)
sleep_for_serve()
if kwds["engine"] != "external_galaxy":
sleep_for_serve()
6 changes: 3 additions & 3 deletions planemo/commands/cmd_workflow_job_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@options.force_option()
@options.workflow_output_artifact()
@command_function
def cli(ctx, workflow_path, output=None, **kwds):
def cli(ctx, workflow_identifier, output=None, **kwds):
"""Initialize a Galaxy workflow job description for supplied workflow.
Be sure to your lint your workflow with ``workflow_lint`` before calling this
Expand All @@ -25,9 +25,9 @@ def cli(ctx, workflow_path, output=None, **kwds):
as well so this command may be renamed to to job_init at something along those
lines at some point.
"""
job = job_template(workflow_path)
job = job_template(workflow_identifier)
if output is None:
output = new_workflow_associated_path(workflow_path, suffix="job")
output = new_workflow_associated_path(workflow_identifier, suffix="job")
if not can_write_to_path(output, **kwds):
ctx.exit(1)
with open(output, "w") as f_job:
Expand Down
14 changes: 7 additions & 7 deletions planemo/commands/cmd_workflow_test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,28 @@
@options.workflow_output_artifact()
@options.split_job_and_test()
@command_function
def cli(ctx, workflow_path, output=None, split_test=False, **kwds):
def cli(ctx, workflow_identifier, output=None, split_test=False, **kwds):
"""Initialize a Galaxy workflow test description for supplied workflow.
Be sure to your lint your workflow with ``workflow_lint`` before calling this
to ensure inputs and outputs comply with best practices that make workflow
testing easier.
"""
path_basename = os.path.basename(workflow_path)
job = job_template(workflow_path)
path_basename = os.path.basename(workflow_identifier)
job = job_template(workflow_identifier)
if output is None:
output = new_workflow_associated_path(workflow_path)
job_output = new_workflow_associated_path(workflow_path, suffix="job1")
output = new_workflow_associated_path(workflow_identifier)
job_output = new_workflow_associated_path(workflow_identifier, suffix="job1")
if not can_write_to_path(output, **kwds):
ctx.exit(1)

test_description = [{
'doc': 'Test outline for %s' % path_basename,
'job': job,
'outputs': output_stubs_for_workflow(workflow_path),
'outputs': output_stubs_for_workflow(workflow_identifier),
}]
if split_test:
job_output = new_workflow_associated_path(workflow_path, suffix="job1")
job_output = new_workflow_associated_path(workflow_identifier, suffix="job1")
if not can_write_to_path(job_output, **kwds):
ctx.exit(1)

Expand Down
4 changes: 1 addition & 3 deletions planemo/engine/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from planemo.io import error
from planemo.runnable import (
cases,
for_path,
RunnableType,
)
from planemo.test.results import StructuredData
Expand Down Expand Up @@ -53,9 +52,8 @@ def can_run(self, runnable):
def cleanup(self):
"""Default no-op cleanup method."""

def run(self, path, job_path):
def run(self, runnable, job_path):
"""Run a job using a compatible artifact (workflow or tool)."""
runnable = for_path(path)
self._check_can_run(runnable)
run_response = self._run(runnable, job_path)
return run_response
Expand Down
Loading

0 comments on commit 1f9fdff

Please sign in to comment.