Skip to content

Commit f82c2e8

Browse files
joverlee521tsibley
andcommitted
pathogens: Workflows are registered independent of their nextstrain run compatibility
Workflows are now registered under a top level "workflows" key in the nextstrain-pathogen.yaml file, and each workflow has its own "compatibility" declarations. The only current "compatibility" declaration remains "nextstrain run". This allows for more meta information about each workflow to be registered in one place not under the banner of compatibility. The nextstrain-pathogen.yaml schema changes to a workflow-first structure like: workflows: ingest: compatibility: nextstrain run: yes phylogenetic: compatibility: nextstrain run: no instead of a compatibility-first structure like: compatibility: nextstrain run: ingest: yes phylogenetic: no as previously introduced¹ (but not yet released). As it was never released, don't bother supporting the latter schema at all anymore. Change first arose out of discussion started by @victorlin in a related PR.² Subsequent discussion with @tsibley³ led to dropping support for the unreleased schema. ¹ <#461> ² <#462 (comment)> ³ <#472 (comment)> Co-authored-by: Thomas Sibley <tsibley@fredhutch.org>
1 parent be9fd18 commit f82c2e8

File tree

5 files changed

+49
-28
lines changed

5 files changed

+49
-28
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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ def run(opts):
7272
if opts.verbose:
7373
print(" " + str(version.path))
7474

75-
if registered_workflows := version.registered_workflows():
76-
print(" " + "Available workflows:")
77-
for workflow in registered_workflows:
75+
if compatible_workflows := version.compatible_workflows("nextstrain run"):
76+
print(" " + "Compatible workflows:")
77+
for workflow in compatible_workflows:
7878
print(" " + workflow)
7979
else:
8080
print(" " + "No workflows listed, please refer to pathogen docs.")

nextstrain/cli/pathogens.py

Lines changed: 22 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
515+
516+
if not (compatible_workflows := self.compatible_workflows("nextstrain run")):
517+
return msg + "\n(no workflows registered as compatible)", False
513518

514-
return msg, bool(compatibility)
519+
return msg + f"\nCompatible workflows: {list(compatible_workflows.keys())}", True
515520

516521
return [
517522
('downloaded',

0 commit comments

Comments
 (0)