Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ supported Python version is always bundled with `nextstrain`.
## Improvements

* `nextstrain setup <pathogen>` and `nextstrain version --pathogens` now list
the available workflows for a pathogen if the pathogen lists the workflows
in the top-level `nextstrain-pathogen.yaml` file.
([#461](https://github.com/nextstrain/cli/pull/461))
the available workflows (e.g. `ingest`, `phylogenetic`) for a pathogen if the
workflows are registered as compatible with `nextstrain run` in the
pathogen's `nextstrain-pathogen.yaml` file.
([#461](https://github.com/nextstrain/cli/pull/461), [#472](https://github.com/nextstrain/cli/pull/472))

* Snakemake's storage support downloaded files (stored in `.snakemake/storage/`)
are now downloaded from AWS Batch builds by default.
Expand Down
7 changes: 4 additions & 3 deletions doc/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ supported Python version is always bundled with `nextstrain`.
### Improvements

* `nextstrain setup <pathogen>` and `nextstrain version --pathogens` now list
the available workflows for a pathogen if the pathogen lists the workflows
in the top-level `nextstrain-pathogen.yaml` file.
([#461](https://github.com/nextstrain/cli/pull/461))
the available workflows (e.g. `ingest`, `phylogenetic`) for a pathogen if the
workflows are registered as compatible with `nextstrain run` in the
pathogen's `nextstrain-pathogen.yaml` file.
([#461](https://github.com/nextstrain/cli/pull/461), [#472](https://github.com/nextstrain/cli/pull/472))

* Snakemake's storage support downloaded files (stored in `.snakemake/storage/`)
are now downloaded from AWS Batch builds by default.
Expand Down
18 changes: 16 additions & 2 deletions nextstrain/cli/command/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from ..errors import UserError
from ..pathogens import PathogenVersion, UnmanagedPathogen
from ..runner import aws_batch, docker, singularity
from ..util import byte_quantity, split_image_name
from ..util import byte_quantity, split_image_name, warn
from ..volume import NamedVolume
from . import build

Expand Down Expand Up @@ -241,7 +241,21 @@ def run(opts):
debug(f"Treating {opts.pathogen!r} as unmanaged pathogen directory")

if opts.workflow not in pathogen.registered_workflows():
print(f"The {opts.workflow!r} workflow is not registered as a compatible workflow, but trying to run anyways.")
warn(cleandoc(f"""
The {opts.workflow!r} workflow is not registered by pathogen {opts.pathogen!r}!

Trying to run it anyways (but it likely won't work)…
"""))
warn()

elif opts.workflow not in pathogen.compatible_workflows("nextstrain run"):
warn(cleandoc(f"""
The {opts.workflow!r} workflow is registered by pathogen {opts.pathogen!r}
but not marked as compatible with `nextstrain run`!

Trying to run it anyways (but it likely won't work)…
"""))
warn()

workflow_directory = pathogen.workflow_path(opts.workflow)

Expand Down
12 changes: 4 additions & 8 deletions nextstrain/cli/command/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,11 @@ def run(opts):
print(" " + name)
for version in versions.values():
is_default = version == defaults.get(name)
print(" " + str(version) + (f"={version.url or ''}" if opts.verbose else ""), "(default)" if is_default else "")
compatible_workflows = version.compatible_workflows("nextstrain run")
print(" " + str(version) + (f"={version.url or ''}" if opts.verbose else "")
+ (" (default)" if is_default else "")
+ (f" {{{', '.join(compatible_workflows)}}}" if compatible_workflows else ""))
if opts.verbose:
print(" " + str(version.path))

if registered_workflows := version.registered_workflows():
print(" " + "Available workflows:")
for workflow in registered_workflows:
print(" " + workflow)
else:
print(" " + "No workflows listed, please refer to pathogen docs.")
else:
print(" (none)")
43 changes: 26 additions & 17 deletions nextstrain/cli/pathogens.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,21 +308,33 @@ def __init__(self, name_version_url: str, new_setup: bool = False):

def registered_workflows(self) -> Dict[str, Dict]:
"""
Parses :attr:`.registration` to return a dict of registered
compatible workflows, where the keys are workflow names.
Parses :attr:`.registration` to return a dict of registered workflows,
where the keys are workflow names.
"""
if self.registration is None:
debug("pathogen does not have a registration")
return {}

workflows = self.registration.get("compatibility", {}).get("nextstrain run")
workflows = self.registration.get("workflows")
if not isinstance(workflows, dict):
debug(f"pathogen registration.compatibility['nextstrain runs'] is not a dict (got a {type(workflows).__name__})")
debug(f"pathogen registration.workflows is not a dict (got a {type(workflows).__name__})")
return {}

return workflows


def compatible_workflows(self, feature: str) -> Dict[str, Dict]:
"""
Filters registered workflows to return a subset of workflows that are
compatible with the provided *feature*.
"""
return {
name: info
for name, info in self.registered_workflows().items()
if isinstance(info, dict) and info.get("compatibility", {}).get(feature)
}


def workflow_path(self, workflow: str) -> Path:
return self.path / workflow

Expand Down Expand Up @@ -498,20 +510,13 @@ def test_compatibility() -> SetupTestResult:
if self.registration is None:
return msg + "\n(couldn't read registration)", False

try:
compatibility = self.registration["compatibility"]["nextstrain run"]
except (KeyError, IndexError, TypeError):
if DEBUGGING:
traceback.print_exc()
return msg + "\n(couldn't find 'compatibility: nextstrain run: …' field)", False

if compatibility:
if workflows := self.registered_workflows():
msg += f"\nAvailable workflows: {list(workflows.keys())}"
else:
msg += f"\nNo workflows listed, please refer to pathogen docs."
if not self.registered_workflows():
return msg + "\n(no workflows registered)", False

return msg, bool(compatibility)
if not self.compatible_workflows("nextstrain run"):
return msg + "\n(no workflows registered as compatible)", False

return msg, True

return [
('downloaded',
Expand All @@ -521,6 +526,9 @@ def test_compatibility() -> SetupTestResult:
self.registration_path.is_file()),

test_compatibility(),

*((f'`nextstrain run` workflow {name!r} exists', self.workflow_path(name).is_dir())
for name in self.compatible_workflows("nextstrain run")),
]


Expand Down Expand Up @@ -690,6 +698,7 @@ def __init__(self, path: str):
self.registration = read_pathogen_registration(self.registration_path)

registered_workflows = PathogenVersion.registered_workflows
compatible_workflows = PathogenVersion.compatible_workflows
workflow_path = PathogenVersion.workflow_path

def __str__(self) -> str:
Expand Down
Loading