Skip to content

Commit 159faf0

Browse files
committed
Merge branch 'workflow-compatibility'
2 parents be9fd18 + 20c99d4 commit 159faf0

File tree

5 files changed

+54
-33
lines changed

5 files changed

+54
-33
lines changed

CHANGES.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ supported Python version is always bundled with `nextstrain`.
2727
## Improvements
2828

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

3435
* Snakemake's storage support downloaded files (stored in `.snakemake/storage/`)
3536
are now downloaded from AWS Batch builds by default.

doc/changes.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ supported Python version is always bundled with `nextstrain`.
3131
### Improvements
3232

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

3839
* Snakemake's storage support downloaded files (stored in `.snakemake/storage/`)
3940
are now downloaded from AWS Batch builds by default.

nextstrain/cli/command/run.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from ..errors import UserError
3434
from ..pathogens import PathogenVersion, UnmanagedPathogen
3535
from ..runner import aws_batch, docker, singularity
36-
from ..util import byte_quantity, split_image_name
36+
from ..util import byte_quantity, split_image_name, warn
3737
from ..volume import NamedVolume
3838
from . import build
3939

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

243243
if opts.workflow not in pathogen.registered_workflows():
244-
print(f"The {opts.workflow!r} workflow is not registered as a compatible workflow, but trying to run anyways.")
244+
warn(cleandoc(f"""
245+
The {opts.workflow!r} workflow is not registered by pathogen {opts.pathogen!r}!
246+
247+
Trying to run it anyways (but it likely won't work)…
248+
"""))
249+
warn()
250+
251+
elif opts.workflow not in pathogen.compatible_workflows("nextstrain run"):
252+
warn(cleandoc(f"""
253+
The {opts.workflow!r} workflow is registered by pathogen {opts.pathogen!r}
254+
but not marked as compatible with `nextstrain run`!
255+
256+
Trying to run it anyways (but it likely won't work)…
257+
"""))
258+
warn()
245259

246260
workflow_directory = pathogen.workflow_path(opts.workflow)
247261

nextstrain/cli/command/version.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,11 @@ def run(opts):
6868
print(" " + name)
6969
for version in versions.values():
7070
is_default = version == defaults.get(name)
71-
print(" " + str(version) + (f"={version.url or ''}" if opts.verbose else ""), "(default)" if is_default else "")
71+
compatible_workflows = version.compatible_workflows("nextstrain run")
72+
print(" " + str(version) + (f"={version.url or ''}" if opts.verbose else "")
73+
+ (" (default)" if is_default else "")
74+
+ (f" {{{', '.join(compatible_workflows)}}}" if compatible_workflows else ""))
7275
if opts.verbose:
7376
print(" " + str(version.path))
74-
75-
if registered_workflows := version.registered_workflows():
76-
print(" " + "Available workflows:")
77-
for workflow in registered_workflows:
78-
print(" " + workflow)
79-
else:
80-
print(" " + "No workflows listed, please refer to pathogen docs.")
8177
else:
8278
print(" (none)")

nextstrain/cli/pathogens.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,33 @@ def __init__(self, name_version_url: str, new_setup: bool = False):
308308

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

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

323323
return workflows
324324

325325

326+
def compatible_workflows(self, feature: str) -> Dict[str, Dict]:
327+
"""
328+
Filters registered workflows to return a subset of workflows that are
329+
compatible with the provided *feature*.
330+
"""
331+
return {
332+
name: info
333+
for name, info in self.registered_workflows().items()
334+
if isinstance(info, dict) and info.get("compatibility", {}).get(feature)
335+
}
336+
337+
326338
def workflow_path(self, workflow: str) -> Path:
327339
return self.path / workflow
328340

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

501-
try:
502-
compatibility = self.registration["compatibility"]["nextstrain run"]
503-
except (KeyError, IndexError, TypeError):
504-
if DEBUGGING:
505-
traceback.print_exc()
506-
return msg + "\n(couldn't find 'compatibility: nextstrain run: …' field)", False
507-
508-
if compatibility:
509-
if workflows := self.registered_workflows():
510-
msg += f"\nAvailable workflows: {list(workflows.keys())}"
511-
else:
512-
msg += f"\nNo workflows listed, please refer to pathogen docs."
513+
if not self.registered_workflows():
514+
return msg + "\n(no workflows registered)", False
513515

514-
return msg, bool(compatibility)
516+
if not self.compatible_workflows("nextstrain run"):
517+
return msg + "\n(no workflows registered as compatible)", False
518+
519+
return msg, True
515520

516521
return [
517522
('downloaded',
@@ -521,6 +526,9 @@ def test_compatibility() -> SetupTestResult:
521526
self.registration_path.is_file()),
522527

523528
test_compatibility(),
529+
530+
*((f'`nextstrain run` workflow {name!r} exists', self.workflow_path(name).is_dir())
531+
for name in self.compatible_workflows("nextstrain run")),
524532
]
525533

526534

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

692700
registered_workflows = PathogenVersion.registered_workflows
701+
compatible_workflows = PathogenVersion.compatible_workflows
693702
workflow_path = PathogenVersion.workflow_path
694703

695704
def __str__(self) -> str:

0 commit comments

Comments
 (0)