diff --git a/monai/bundle/__init__.py b/monai/bundle/__init__.py
index fa139bb6017..b550dc8c93b 100644
--- a/monai/bundle/__init__.py
+++ b/monai/bundle/__init__.py
@@ -24,6 +24,7 @@
init_bundle,
load,
run,
+ run_workflow,
trt_export,
verify_metadata,
verify_net_in_out,
diff --git a/monai/bundle/__main__.py b/monai/bundle/__main__.py
index aa0ed20ef5a..e143a5c7edd 100644
--- a/monai/bundle/__main__.py
+++ b/monai/bundle/__main__.py
@@ -11,7 +11,16 @@
from __future__ import annotations
-from monai.bundle.scripts import ckpt_export, download, init_bundle, run, trt_export, verify_metadata, verify_net_in_out
+from monai.bundle.scripts import (
+ ckpt_export,
+ download,
+ init_bundle,
+ run,
+ run_workflow,
+ trt_export,
+ verify_metadata,
+ verify_net_in_out,
+)
if __name__ == "__main__":
from monai.utils import optional_import
diff --git a/monai/bundle/scripts.py b/monai/bundle/scripts.py
index af2419a9a97..6a607a28365 100644
--- a/monai/bundle/scripts.py
+++ b/monai/bundle/scripts.py
@@ -636,7 +636,7 @@ def run(
args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,
`config_file`, `logging`, and override pairs. so that the command line inputs can be simplified.
override: id-value pairs to override or add the corresponding config content.
- e.g. ``--net#input_chns 42``.
+ e.g. ``--net#input_chns 42``, ``--net %/data/other.json#net_arg``.
"""
@@ -664,7 +664,8 @@ def run(
logging_file="configs/logging.conf",
tracking=None,
)
- workflow = ConfigWorkflow(
+ run_workflow(
+ workflow=ConfigWorkflow,
config_file=config_file_,
meta_file=meta_file_,
logging_file=logging_file_,
@@ -674,9 +675,6 @@ def run(
tracking=tracking_,
**_args,
)
- workflow.initialize()
- workflow.run()
- workflow.finalize()
def run_workflow(workflow: str | BundleWorkflow | None = None, args_file: str | None = None, **kwargs: Any) -> None:
@@ -688,23 +686,10 @@ def run_workflow(workflow: str | BundleWorkflow | None = None, args_file: str |
.. code-block:: bash
# Execute this module as a CLI entry with default ConfigWorkflow:
- python -m monai.bundle run --meta_file --config_file
-
- # Override config values at runtime by specifying the component id and its new value:
- python -m monai.bundle run --net#input_chns 1 ...
-
- # Override config values with another config file `/path/to/another.json`:
- python -m monai.bundle run --net %/path/to/another.json ...
-
- # Override config values with part content of another config file:
- python -m monai.bundle run --net %/data/other.json#net_arg ...
-
- # Set default args of `run` in a JSON / YAML file, help to record and simplify the command line.
- # Other args still can override the default args at runtime:
- python -m monai.bundle run --args_file "/workspace/data/args.json" --config_file
+ python -m monai.bundle run_workflow --meta_file --config_file
# Set the workflow to other customized BundleWorkflow subclass:
- python -m monai.bundle run --workflow CustomizedWorkflow ...
+ python -m monai.bundle run_workflow --workflow CustomizedWorkflow ...
Args:
workflow: specified bundle workflow name, should be a string or class, default to "ConfigWorkflow".
@@ -716,17 +701,17 @@ def run_workflow(workflow: str | BundleWorkflow | None = None, args_file: str |
_args = _update_args(args=args_file, workflow=workflow, **kwargs)
_log_input_summary(tag="run", args=_args)
- (workflow_name,) = _pop_args(_args, workflow=ConfigWorkflow)
+ (workflow_name,) = _pop_args(_args, workflow=ConfigWorkflow) # the default workflow name is "ConfigWorkflow"
if isinstance(workflow_name, str):
workflow_class, has_built_in = optional_import("monai.bundle", name=f"{workflow_name}") # search built-in
if not has_built_in:
workflow_class = locate(f"{workflow_name}") # search dotted path
if workflow_class is None:
- raise ValueError(f"can not locate specified workflow class: {workflow_name}.")
+ raise ValueError(f"cannot locate specified workflow class: {workflow_name}.")
elif issubclass(workflow_name, BundleWorkflow):
workflow_class = workflow_name
else:
- raise ValueError(f"`workflow` must be the bundle workflow class name, but got: {workflow_name}.")
+ raise ValueError(f"argument `workflow` must be the bundle workflow class name or type, got: {workflow_name}.")
workflow_ = workflow_class(**_args)
workflow_.initialize()
diff --git a/tests/test_integration_bundle_run.py b/tests/test_integration_bundle_run.py
index 1bb06046cd9..8287d4aeb24 100644
--- a/tests/test_integration_bundle_run.py
+++ b/tests/test_integration_bundle_run.py
@@ -62,8 +62,9 @@ def test_tiny(self):
},
f,
)
- cmd = ["coverage", "run", "-m", "monai.bundle", "run", "--run_id", "training", "--config_file", config_file]
- command_line_tests(cmd)
+ cmd = ["coverage", "run", "-m", "monai.bundle"]
+ command_line_tests(cmd + ["run", "training", "--config_file", config_file])
+ command_line_tests(cmd + ["run_workflow", "--run_id", "training", "--config_file", config_file])
@parameterized.expand([TEST_CASE_1, TEST_CASE_2])
def test_shape(self, config_file, expected_shape):
@@ -136,13 +137,13 @@ def test_shape(self, config_file, expected_shape):
# test the saved execution configs
self.assertTrue(len(glob(f"{tempdir}/config_*.json")), 2)
- def test_customize_workflow(self):
+ def test_customized_workflow(self):
expected_shape = (64, 64, 64)
test_image = np.random.rand(*expected_shape)
filename = os.path.join(self.data_dir, "image.nii")
nib.save(nib.Nifti1Image(test_image, np.eye(4)), filename)
- cmd = "-m fire monai.bundle.scripts run --workflow tests.nonconfig_workflow.NonConfigWorkflow"
+ cmd = "-m fire monai.bundle.scripts run_workflow --workflow tests.nonconfig_workflow.NonConfigWorkflow"
cmd += f" --filename {filename} --output_dir {self.data_dir}"
command_line_tests(["coverage", "run"] + cmd.split(" "))
loader = LoadImage(image_only=True)