prompt: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  make 'meta_file' optional for `monai.bundle run`
  **Is your feature request related to a problem? Please describe.**
  make it possible to instantiate components via CLI without providing a metadata file.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### monai/bundle/scripts.py
  # Copyright (c) MONAI Consortium
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #     http://www.apache.org/licenses/LICENSE-2.0
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import ast
  import pprint
  import re
  from typing import Dict, Optional, Sequence, Tuple, Union
  
  import torch
  
  from monai.apps.utils import download_url, get_logger
  from monai.bundle.config_parser import ConfigParser
  from monai.config import PathLike
  from monai.utils import check_parent_dir, get_equivalent_dtype, optional_import
  
  validate, _ = optional_import("jsonschema", name="validate")
  ValidationError, _ = optional_import("jsonschema.exceptions", name="ValidationError")
  
  logger = get_logger(module_name=__name__)
  
  
  def _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:
      """
      Update the `args` with the input `kwargs`.
      For dict data, recursively update the content based on the keys.
  
      Args:
          args: source args to update.
          ignore_none: whether to ignore input args with None value, default to `True`.
          kwargs: destination args to update.
  
      """
      args_: Dict = args if isinstance(args, dict) else {}  # type: ignore
      if isinstance(args, str):
          # args are defined in a structured file
          args_ = ConfigParser.load_config_file(args)
  
      # recursively update the default args with new args
      for k, v in kwargs.items():
          if ignore_none and v is None:
              continue
          if isinstance(v, dict) and isinstance(args_.get(k), dict):
              args_[k] = _update_args(args_[k], ignore_none, **v)
          else:
              args_[k] = v
      return args_
  
  
  def _log_input_summary(tag, args: Dict):
      logger.info(f"--- input summary of monai.bundle.scripts.{tag} ---")
      for name, val in args.items():
          logger.info(f"> {name}: {pprint.pformat(val)}")
      logger.info("---\n\n")
  
  
  def _get_var_names(expr: str):
      """
      Parse the expression and discover what variables are present in it based on ast module.
  
      Args:
          expr: source expression to parse.
  
      """
      tree = ast.parse(expr)
      return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]
  
  
  def _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:
      """
      Get spatial shape for fake data according to the specified shape pattern.
      It supports `int` number and `string` with formats like: "32", "32 * n", "32 ** p", "32 ** p *n".
  
      Args:
          shape: specified pattern for the spatial shape.
          p: power factor to generate fake data shape if dim of expected shape is "x**p", default to 1.
          p: multiply factor to generate fake data shape if dim of expected shape is "x*n", default to 1.
          any: specified size to generate fake data shape if dim of expected shape is "*", default to 1.
  
      """
      ret = []
      for i in shape:
          if isinstance(i, int):
              ret.append(i)
          elif isinstance(i, str):
              if i == "*":
                  ret.append(any)
              else:
                  for c in _get_var_names(i):
                      if c not in ["p", "n"]:
                          raise ValueError(f"only support variables 'p' and 'n' so far, but got: {c}.")
                  ret.append(eval(i, {"p": p, "n": n}))
          else:
              raise ValueError(f"spatial shape items must be int or string, but got: {type(i)} {i}.")
      return tuple(ret)
  
  
  def run(
      runner_id: Optional[str] = None,
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      config_file: Optional[Union[str, Sequence[str]]] = None,
      args_file: Optional[str] = None,
      **override,
  ):
      """
      Specify `meta_file` and `config_file` to run monai bundle components and workflows.
  
      Typical usage examples:
  
      .. code-block:: bash
  
          # Execute this module as a CLI entry:
          python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>
  
          # Override config values at runtime by specifying the component id and its new value:
          python -m monai.bundle run trainer --net#input_chns 1 ...
  
          # Override config values with another config file `/path/to/another.json`:
          python -m monai.bundle run evaluator --net %/path/to/another.json ...
  
          # Override config values with part content of another config file:
          python -m monai.bundle run trainer --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 <config path>
  
      Args:
          runner_id: ID name of the runner component or workflow, it must have a `run` method.
          meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          config_file: filepath of the config file, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,
              `config_file`, 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``.
  
      """
  
      _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)
      for k in ("meta_file", "config_file"):
          if k not in _args:
              raise ValueError(f"{k} is required for 'monai.bundle run'.\n{run.__doc__}")
      _log_input_summary(tag="run", args=_args)
  
      parser = ConfigParser()
      parser.read_config(f=_args.pop("config_file"))
      parser.read_meta(f=_args.pop("meta_file"))
      id = _args.pop("runner_id", "")
  
      # the rest key-values in the _args are to override config content
      for k, v in _args.items():
          parser[k] = v
  
      workflow = parser.get_parsed_content(id=id)
      if not hasattr(workflow, "run"):
          raise ValueError(f"The parsed workflow {type(workflow)} does not have a `run` method.\n{run.__doc__}")
      workflow.run()
  
  
  def verify_metadata(
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      filepath: Optional[PathLike] = None,
      create_dir: Optional[bool] = None,
      hash_val: Optional[str] = None,
      args_file: Optional[str] = None,
      **kwargs,
  ):
      """
      Verify the provided `metadata` file based on the predefined `schema`.
      `metadata` content must contain the `schema` field for the URL of shcema file to download.
      The schema standard follows: http://json-schema.org/.
  
      Args:
          meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          filepath: file path to store the downloaded schema.
          create_dir: whether to create directories if not existing, default to `True`.
          hash_val: if not None, define the hash value to verify the downloaded schema file.
          args_file: a JSON or YAML file to provide default values for all the args in this function.
              so that the command line inputs can be simplified.
          kwargs: other arguments for `jsonschema.validate()`. for more details:
              https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.
  
      """
  
      _args = _update_args(
          args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs
      )
      _log_input_summary(tag="verify_metadata", args=_args)
  
      filepath_ = _args.pop("filepath")
      create_dir_ = _args.pop("create_dir", True)
      check_parent_dir(path=filepath_, create_dir=create_dir_)
  
      metadata = ConfigParser.load_config_files(files=_args.pop("meta_file"))
      url = metadata.get("schema")
      if url is None:
          raise ValueError("must provide the `schema` field in the metadata for the URL of schema file.")
      download_url(url=url, filepath=filepath_, hash_val=_args.pop("hash_val", None), hash_type="md5", progress=True)
      schema = ConfigParser.load_config_file(filepath=filepath_)
  
      try:
          # the rest key-values in the _args are for `validate` API
          validate(instance=metadata, schema=schema, **_args)
      except ValidationError as e:
          # as the error message is very long, only extract the key information
          logger.info(re.compile(r".*Failed validating", re.S).findall(str(e))[0] + f" against schema `{url}`.")
          return
      logger.info("metadata is verified with no error.")
  
  
  def verify_net_in_out(
      net_id: Optional[str] = None,
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      config_file: Optional[Union[str, Sequence[str]]] = None,
      device: Optional[str] = None,
      p: Optional[int] = None,
      n: Optional[int] = None,
      any: Optional[int] = None,
      args_file: Optional[str] = None,
      **override,
  ):
      """
      Verify the input and output data shape and data type of network defined in the metadata.
      Will test with fake Tensor data according to the required data shape in `metadata`.
  
      Typical usage examples:
  
      .. code-block:: bash
  
          python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>
  
      Args:
          net_id: ID name of the network component to verify, it must be `torch.nn.Module`.
          meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          device: target device to run the network forward computation, if None, prefer to "cuda" if existing.
          p: power factor to generate fake data shape if dim of expected shape is "x**p", default to 1.
          p: multiply factor to generate fake data shape if dim of expected shape is "x*n", default to 1.
          any: specified size to generate fake data shape if dim of expected shape is "*", default to 1.
          args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,
              `net_id` 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. ``--_meta#network_data_format#inputs#image#num_channels 3``.
  
      """
  
      _args = _update_args(
          args=args_file,
          net_id=net_id,
          meta_file=meta_file,
          config_file=config_file,
          device=device,
          p=p,
          n=n,
          any=any,
          **override,
      )
      _log_input_summary(tag="verify_net_in_out", args=_args)
  
      parser = ConfigParser()
      parser.read_config(f=_args.pop("config_file"))
      parser.read_meta(f=_args.pop("meta_file"))
      id = _args.pop("net_id", "")
      device_ = torch.device(_args.pop("device", "cuda:0" if torch.cuda.is_available() else "cpu"))
      p = _args.pop("p", 1)
      n = _args.pop("n", 1)
      any = _args.pop("any", 1)
  
      # the rest key-values in the _args are to override config content
      for k, v in _args.items():
          parser[k] = v
  
      try:
          key: str = id  # mark the full id when KeyError
          net = parser.get_parsed_content(key).to(device_)
          key = "_meta_#network_data_format#inputs#image#num_channels"
          input_channels = parser[key]
          key = "_meta_#network_data_format#inputs#image#spatial_shape"
          input_spatial_shape = tuple(parser[key])
          key = "_meta_#network_data_format#inputs#image#dtype"
          input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)
          key = "_meta_#network_data_format#outputs#pred#num_channels"
          output_channels = parser[key]
          key = "_meta_#network_data_format#outputs#pred#dtype"
          output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)
      except KeyError as e:
          raise KeyError(f"Failed to verify due to missing expected key in the config: {key}.") from e
  
      net.eval()
      with torch.no_grad():
          spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore
          test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)
          output = net(test_data)
          if output.shape[1] != output_channels:
              raise ValueError(f"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.")
          if output.dtype != output_dtype:
              raise ValueError(f"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.")
      logger.info("data shape of network is verified with no error.")
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
instance: {"FAIL_TO_PASS": ["tests/test_integration_bundle_run.py::TestBundleRun::test_tiny"], "PASS_TO_PASS": ["tests/test_integration_bundle_run.py::TestBundleRun::test_shape_0__testbed_tests_testing_data_inference_json", "tests/test_integration_bundle_run.py::TestBundleRun::test_shape_1__testbed_tests_testing_data_inference_yaml", "tests/test_bundle_verify_metadata.py::testing_data_config"], "base_commit": "8e1aacf5ee7f4e62e9f0f25a9e1a3c37a09439ca", "created_at": "2022-03-16T12:11:42Z", "hints_text": "", "instance_id": "Project-MONAI__MONAI-3952", "patch": "diff --git a/monai/bundle/scripts.py b/monai/bundle/scripts.py\n--- a/monai/bundle/scripts.py\n+++ b/monai/bundle/scripts.py\n@@ -133,9 +133,8 @@ def run(\n         python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n \n     Args:\n-        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n-        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n-            if it is a list of file paths, the content of them will be merged.\n+        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``\"\"``.\n+        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.\n         config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n             if it is a list of file paths, the content of them will be merged.\n         args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n@@ -146,14 +145,14 @@ def run(\n     \"\"\"\n \n     _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n-    for k in (\"meta_file\", \"config_file\"):\n-        if k not in _args:\n-            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n+    if \"config_file\" not in _args:\n+        raise ValueError(f\"`config_file` is required for 'monai.bundle run'.\\n{run.__doc__}\")\n     _log_input_summary(tag=\"run\", args=_args)\n \n     parser = ConfigParser()\n     parser.read_config(f=_args.pop(\"config_file\"))\n-    parser.read_meta(f=_args.pop(\"meta_file\"))\n+    if \"meta_file\" in _args:\n+        parser.read_meta(f=_args.pop(\"meta_file\"))\n     id = _args.pop(\"runner_id\", \"\")\n \n     # the rest key-values in the _args are to override config content\n@@ -162,8 +161,8 @@ def run(\n \n     workflow = parser.get_parsed_content(id=id)\n     if not hasattr(workflow, \"run\"):\n-        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n-    workflow.run()\n+        raise ValueError(f\"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\\n{run.__doc__}\")\n+    return workflow.run()\n \n \n def verify_metadata(\n@@ -171,6 +170,7 @@ def verify_metadata(\n     filepath: Optional[PathLike] = None,\n     create_dir: Optional[bool] = None,\n     hash_val: Optional[str] = None,\n+    hash_type: Optional[str] = None,\n     args_file: Optional[str] = None,\n     **kwargs,\n ):\n@@ -185,6 +185,7 @@ def verify_metadata(\n         filepath: file path to store the downloaded schema.\n         create_dir: whether to create directories if not existing, default to `True`.\n         hash_val: if not None, define the hash value to verify the downloaded schema file.\n+        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to \"md5\".\n         args_file: a JSON or YAML file to provide default values for all the args in this function.\n             so that the command line inputs can be simplified.\n         kwargs: other arguments for `jsonschema.validate()`. for more details:\n@@ -193,7 +194,13 @@ def verify_metadata(\n     \"\"\"\n \n     _args = _update_args(\n-        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n+        args=args_file,\n+        meta_file=meta_file,\n+        filepath=filepath,\n+        create_dir=create_dir,\n+        hash_val=hash_val,\n+        hash_type=hash_type,\n+        **kwargs,\n     )\n     _log_input_summary(tag=\"verify_metadata\", args=_args)\n \n@@ -205,7 +212,13 @@ def verify_metadata(\n     url = metadata.get(\"schema\")\n     if url is None:\n         raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n-    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n+    download_url(\n+        url=url,\n+        filepath=filepath_,\n+        hash_val=_args.pop(\"hash_val\", None),\n+        hash_type=_args.pop(\"hash_type\", \"md5\"),\n+        progress=True,\n+    )\n     schema = ConfigParser.load_config_file(filepath=filepath_)\n \n     try:\n", "problem_statement": "make 'meta_file' optional for `monai.bundle run`\n**Is your feature request related to a problem? Please describe.**\r\nmake it possible to instantiate components via CLI without providing a metadata file.\n", "repo": "Project-MONAI/MONAI", "test_patch": "diff --git a/tests/test_bundle_verify_metadata.py b/tests/test_bundle_verify_metadata.py\n--- a/tests/test_bundle_verify_metadata.py\n+++ b/tests/test_bundle_verify_metadata.py\n@@ -20,16 +20,24 @@\n from parameterized import parameterized\n \n from monai.bundle import ConfigParser\n-from tests.utils import skip_if_windows\n+from tests.utils import download_url_or_skip_test, skip_if_windows, testing_data_config\n \n-TEST_CASE_1 = [\n-    os.path.join(os.path.dirname(__file__), \"testing_data\", \"metadata.json\"),\n-    os.path.join(os.path.dirname(__file__), \"testing_data\", \"schema.json\"),\n-]\n+SCHEMA_FILE = os.path.join(os.path.dirname(__file__), \"testing_data\", \"schema.json\")\n+\n+TEST_CASE_1 = [os.path.join(os.path.dirname(__file__), \"testing_data\", \"metadata.json\"), SCHEMA_FILE]\n \n \n @skip_if_windows\n class TestVerifyMetaData(unittest.TestCase):\n+    def setUp(self):\n+        self.config = testing_data_config(\"configs\", \"test_meta_file\")\n+        download_url_or_skip_test(\n+            url=self.config[\"url\"],\n+            filepath=SCHEMA_FILE,\n+            hash_val=self.config.get(\"hash_val\"),\n+            hash_type=self.config.get(\"hash_type\", \"sha256\"),\n+        )\n+\n     @parameterized.expand([TEST_CASE_1])\n     def test_verify(self, meta_file, schema_file):\n         logging.basicConfig(stream=sys.stdout, level=logging.INFO)\n@@ -38,10 +46,8 @@ def test_verify(self, meta_file, schema_file):\n             def_args_file = os.path.join(tempdir, \"def_args.json\")\n             ConfigParser.export_config_file(config=def_args, filepath=def_args_file)\n \n-            hash_val = \"e3a7e23d1113a1f3e6c69f09b6f9ce2c\"\n-\n             cmd = [sys.executable, \"-m\", \"monai.bundle\", \"verify_metadata\", \"--meta_file\", meta_file]\n-            cmd += [\"--filepath\", schema_file, \"--hash_val\", hash_val, \"--args_file\", def_args_file]\n+            cmd += [\"--filepath\", schema_file, \"--hash_val\", self.config[\"hash_val\"], \"--args_file\", def_args_file]\n             ret = subprocess.check_call(cmd)\n             self.assertEqual(ret, 0)\n \n@@ -50,15 +56,9 @@ def test_verify_error(self):\n         with tempfile.TemporaryDirectory() as tempdir:\n             filepath = os.path.join(tempdir, \"schema.json\")\n             metafile = os.path.join(tempdir, \"metadata.json\")\n+            meta_dict = {\"schema\": self.config[\"url\"], \"wrong_meta\": \"wrong content\"}\n             with open(metafile, \"w\") as f:\n-                json.dump(\n-                    {\n-                        \"schema\": \"https://github.com/Project-MONAI/MONAI-extra-test-data/releases/\"\n-                        \"download/0.8.1/meta_schema_202203171008.json\",\n-                        \"wrong_meta\": \"wrong content\",\n-                    },\n-                    f,\n-                )\n+                json.dump(meta_dict, f)\n \n             cmd = [sys.executable, \"-m\", \"monai.bundle\", \"verify_metadata\", metafile, \"--filepath\", filepath]\n             ret = subprocess.check_call(cmd)\ndiff --git a/tests/test_integration_bundle_run.py b/tests/test_integration_bundle_run.py\n--- a/tests/test_integration_bundle_run.py\n+++ b/tests/test_integration_bundle_run.py\n@@ -11,6 +11,7 @@\n \n import json\n import os\n+import shutil\n import subprocess\n import sys\n import tempfile\n@@ -28,57 +29,80 @@\n TEST_CASE_2 = [os.path.join(os.path.dirname(__file__), \"testing_data\", \"inference.yaml\"), (128, 128, 128)]\n \n \n+class _Runnable42:\n+    def __init__(self, val=1):\n+        self.val = val\n+\n+    def run(self):\n+        assert self.val == 42  # defined in `TestBundleRun.test_tiny``\n+        return self.val\n+\n+\n class TestBundleRun(unittest.TestCase):\n+    def setUp(self):\n+        self.data_dir = tempfile.mkdtemp()\n+\n+    def tearDown(self):\n+        shutil.rmtree(self.data_dir)\n+\n+    def test_tiny(self):\n+        config_file = os.path.join(self.data_dir, \"tiny_config.json\")\n+        with open(config_file, \"w\") as f:\n+            json.dump({\"\": {\"_target_\": \"tests.test_integration_bundle_run._Runnable42\", \"val\": 42}}, f)\n+        cmd = [sys.executable, \"-m\", \"monai.bundle\", \"run\", \"--config_file\", config_file]\n+        ret = subprocess.check_call(cmd)\n+        self.assertEqual(ret, 0)\n+\n     @parameterized.expand([TEST_CASE_1, TEST_CASE_2])\n     def test_shape(self, config_file, expected_shape):\n         test_image = np.random.rand(*expected_shape)\n-        with tempfile.TemporaryDirectory() as tempdir:\n-            filename = os.path.join(tempdir, \"image.nii\")\n-            nib.save(nib.Nifti1Image(test_image, np.eye(4)), filename)\n-\n-            # generate default args in a JSON file\n-            def_args = {\"config_file\": \"will be replaced by `config_file` arg\"}\n-            def_args_file = os.path.join(tempdir, \"def_args.json\")\n-            ConfigParser.export_config_file(config=def_args, filepath=def_args_file)\n-\n-            meta = {\"datalist\": [{\"image\": filename}], \"output_dir\": tempdir, \"window\": (96, 96, 96)}\n-            # test YAML file\n-            meta_file = os.path.join(tempdir, \"meta.yaml\")\n-            ConfigParser.export_config_file(config=meta, filepath=meta_file, fmt=\"yaml\")\n-\n-            # test override with file, up case postfix\n-            overridefile1 = os.path.join(tempdir, \"override1.JSON\")\n-            with open(overridefile1, \"w\") as f:\n-                # test override with part of the overriding file\n-                json.dump({\"move_net\": \"$@network_def.to(@device)\"}, f)\n-            os.makedirs(os.path.join(tempdir, \"jsons\"), exist_ok=True)\n-            overridefile2 = os.path.join(tempdir, \"jsons/override2.JSON\")\n-            with open(overridefile2, \"w\") as f:\n-                # test override with the whole overriding file\n-                json.dump(\"Dataset\", f)\n-\n-            saver = LoadImage(image_only=True)\n-\n-            if sys.platform == \"win32\":\n-                override = \"--network $@network_def.to(@device) --dataset#_target_ Dataset\"\n-            else:\n-                override = f\"--network %{overridefile1}#move_net --dataset#_target_ %{overridefile2}\"\n-            # test with `monai.bundle` as CLI entry directly\n-            cmd = f\"-m monai.bundle run evaluator --postprocessing#transforms#2#output_postfix seg {override}\"\n-            la = [f\"{sys.executable}\"] + cmd.split(\" \") + [\"--meta_file\", meta_file] + [\"--config_file\", config_file]\n-            test_env = os.environ.copy()\n-            print(f\"CUDA_VISIBLE_DEVICES in {__file__}\", test_env.get(\"CUDA_VISIBLE_DEVICES\"))\n-            ret = subprocess.check_call(la + [\"--args_file\", def_args_file], env=test_env)\n-            self.assertEqual(ret, 0)\n-            self.assertTupleEqual(saver(os.path.join(tempdir, \"image\", \"image_seg.nii.gz\")).shape, expected_shape)\n-\n-            # here test the script with `google fire` tool as CLI\n-            cmd = \"-m fire monai.bundle.scripts run --runner_id evaluator\"\n-            cmd += f\" --evaluator#amp False {override}\"\n-            la = [f\"{sys.executable}\"] + cmd.split(\" \") + [\"--meta_file\", meta_file] + [\"--config_file\", config_file]\n-            ret = subprocess.check_call(la, env=test_env)\n-            self.assertEqual(ret, 0)\n-            self.assertTupleEqual(saver(os.path.join(tempdir, \"image\", \"image_trans.nii.gz\")).shape, expected_shape)\n+        tempdir = self.data_dir\n+        filename = os.path.join(tempdir, \"image.nii\")\n+        nib.save(nib.Nifti1Image(test_image, np.eye(4)), filename)\n+\n+        # generate default args in a JSON file\n+        def_args = {\"config_file\": \"will be replaced by `config_file` arg\"}\n+        def_args_file = os.path.join(tempdir, \"def_args.json\")\n+        ConfigParser.export_config_file(config=def_args, filepath=def_args_file)\n+\n+        meta = {\"datalist\": [{\"image\": filename}], \"output_dir\": tempdir, \"window\": (96, 96, 96)}\n+        # test YAML file\n+        meta_file = os.path.join(tempdir, \"meta.yaml\")\n+        ConfigParser.export_config_file(config=meta, filepath=meta_file, fmt=\"yaml\")\n+\n+        # test override with file, up case postfix\n+        overridefile1 = os.path.join(tempdir, \"override1.JSON\")\n+        with open(overridefile1, \"w\") as f:\n+            # test override with part of the overriding file\n+            json.dump({\"move_net\": \"$@network_def.to(@device)\"}, f)\n+        os.makedirs(os.path.join(tempdir, \"jsons\"), exist_ok=True)\n+        overridefile2 = os.path.join(tempdir, \"jsons/override2.JSON\")\n+        with open(overridefile2, \"w\") as f:\n+            # test override with the whole overriding file\n+            json.dump(\"Dataset\", f)\n+\n+        saver = LoadImage(image_only=True)\n+\n+        if sys.platform == \"win32\":\n+            override = \"--network $@network_def.to(@device) --dataset#_target_ Dataset\"\n+        else:\n+            override = f\"--network %{overridefile1}#move_net --dataset#_target_ %{overridefile2}\"\n+        # test with `monai.bundle` as CLI entry directly\n+        cmd = f\"-m monai.bundle run evaluator --postprocessing#transforms#2#output_postfix seg {override}\"\n+        la = [f\"{sys.executable}\"] + cmd.split(\" \") + [\"--meta_file\", meta_file] + [\"--config_file\", config_file]\n+        test_env = os.environ.copy()\n+        print(f\"CUDA_VISIBLE_DEVICES in {__file__}\", test_env.get(\"CUDA_VISIBLE_DEVICES\"))\n+        ret = subprocess.check_call(la + [\"--args_file\", def_args_file], env=test_env)\n+        self.assertEqual(ret, 0)\n+        self.assertTupleEqual(saver(os.path.join(tempdir, \"image\", \"image_seg.nii.gz\")).shape, expected_shape)\n+\n+        # here test the script with `google fire` tool as CLI\n+        cmd = \"-m fire monai.bundle.scripts run --runner_id evaluator\"\n+        cmd += f\" --evaluator#amp False {override}\"\n+        la = [f\"{sys.executable}\"] + cmd.split(\" \") + [\"--meta_file\", meta_file] + [\"--config_file\", config_file]\n+        ret = subprocess.check_call(la, env=test_env)\n+        self.assertEqual(ret, 0)\n+        self.assertTupleEqual(saver(os.path.join(tempdir, \"image\", \"image_trans.nii.gz\")).shape, expected_shape)\n \n \n if __name__ == \"__main__\":\ndiff --git a/tests/testing_data/data_config.json b/tests/testing_data/data_config.json\n--- a/tests/testing_data/data_config.json\n+++ b/tests/testing_data/data_config.json\n@@ -67,5 +67,12 @@\n             \"hash_type\": \"sha256\",\n             \"hash_val\": \"a260b3a40f82dfe37c58d26a612bcf7bef0d27c6fed096226b0e4e9fb364168e\"\n         }\n+    },\n+    \"configs\": {\n+        \"test_meta_file\": {\n+            \"url\": \"https://github.com/Project-MONAI/MONAI-extra-test-data/releases/download/0.8.1/meta_schema_202203171008.json\",\n+            \"hash_type\": \"md5\",\n+            \"hash_val\": \"e3a7e23d1113a1f3e6c69f09b6f9ce2c\"\n+        }\n     }\n }\n", "version": "0.8"}
parsed_commit_content: {"file_diffs":[{"old_file_content":"# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport ast\nimport pprint\nimport re\nfrom typing import Dict, Optional, Sequence, Tuple, Union\n\nimport torch\n\nfrom monai.apps.utils import download_url, get_logger\nfrom monai.bundle.config_parser import ConfigParser\nfrom monai.config import PathLike\nfrom monai.utils import check_parent_dir, get_equivalent_dtype, optional_import\n\nvalidate, _ = optional_import(\"jsonschema\", name=\"validate\")\nValidationError, _ = optional_import(\"jsonschema.exceptions\", name=\"ValidationError\")\n\nlogger = get_logger(module_name=__name__)\n\n\ndef _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:\n    \"\"\"\n    Update the `args` with the input `kwargs`.\n    For dict data, recursively update the content based on the keys.\n\n    Args:\n        args: source args to update.\n        ignore_none: whether to ignore input args with None value, default to `True`.\n        kwargs: destination args to update.\n\n    \"\"\"\n    args_: Dict = args if isinstance(args, dict) else {}  # type: ignore\n    if isinstance(args, str):\n        # args are defined in a structured file\n        args_ = ConfigParser.load_config_file(args)\n\n    # recursively update the default args with new args\n    for k, v in kwargs.items():\n        if ignore_none and v is None:\n            continue\n        if isinstance(v, dict) and isinstance(args_.get(k), dict):\n            args_[k] = _update_args(args_[k], ignore_none, **v)\n        else:\n            args_[k] = v\n    return args_\n\n\ndef _log_input_summary(tag, args: Dict):\n    logger.info(f\"--- input summary of monai.bundle.scripts.{tag} ---\")\n    for name, val in args.items():\n        logger.info(f\"> {name}: {pprint.pformat(val)}\")\n    logger.info(\"---\\n\\n\")\n\n\ndef _get_var_names(expr: str):\n    \"\"\"\n    Parse the expression and discover what variables are present in it based on ast module.\n\n    Args:\n        expr: source expression to parse.\n\n    \"\"\"\n    tree = ast.parse(expr)\n    return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]\n\n\ndef _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:\n    \"\"\"\n    Get spatial shape for fake data according to the specified shape pattern.\n    It supports `int` number and `string` with formats like: \"32\", \"32 * n\", \"32 ** p\", \"32 ** p *n\".\n\n    Args:\n        shape: specified pattern for the spatial shape.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n\n    \"\"\"\n    ret = []\n    for i in shape:\n        if isinstance(i, int):\n            ret.append(i)\n        elif isinstance(i, str):\n            if i == \"*\":\n                ret.append(any)\n            else:\n                for c in _get_var_names(i):\n                    if c not in [\"p\", \"n\"]:\n                        raise ValueError(f\"only support variables 'p' and 'n' so far, but got: {c}.\")\n                ret.append(eval(i, {\"p\": p, \"n\": n}))\n        else:\n            raise ValueError(f\"spatial shape items must be int or string, but got: {type(i)} {i}.\")\n    return tuple(ret)\n\n\ndef run(\n    runner_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Specify `meta_file` and `config_file` to run monai bundle components and workflows.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        # Execute this module as a CLI entry:\n        python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>\n\n        # Override config values at runtime by specifying the component id and its new value:\n        python -m monai.bundle run trainer --net#input_chns 1 ...\n\n        # Override config values with another config file `/path/to/another.json`:\n        python -m monai.bundle run evaluator --net %/path/to/another.json ...\n\n        # Override config values with part content of another config file:\n        python -m monai.bundle run trainer --net %/data/other.json#net_arg ...\n\n        # Set default args of `run` in a JSON / YAML file, help to record and simplify the command line.\n        # Other args still can override the default args at runtime:\n        python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n\n    Args:\n        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n            `config_file`, and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--net#input_chns 42``.\n\n    \"\"\"\n\n    _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n    for k in (\"meta_file\", \"config_file\"):\n        if k not in _args:\n            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n    _log_input_summary(tag=\"run\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"runner_id\", \"\")\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    workflow = parser.get_parsed_content(id=id)\n    if not hasattr(workflow, \"run\"):\n        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n    workflow.run()\n\n\ndef verify_metadata(\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    filepath: Optional[PathLike] = None,\n    create_dir: Optional[bool] = None,\n    hash_val: Optional[str] = None,\n    args_file: Optional[str] = None,\n    **kwargs,\n):\n    \"\"\"\n    Verify the provided `metadata` file based on the predefined `schema`.\n    `metadata` content must contain the `schema` field for the URL of shcema file to download.\n    The schema standard follows: http://json-schema.org/.\n\n    Args:\n        meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        filepath: file path to store the downloaded schema.\n        create_dir: whether to create directories if not existing, default to `True`.\n        hash_val: if not None, define the hash value to verify the downloaded schema file.\n        args_file: a JSON or YAML file to provide default values for all the args in this function.\n            so that the command line inputs can be simplified.\n        kwargs: other arguments for `jsonschema.validate()`. for more details:\n            https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n    )\n    _log_input_summary(tag=\"verify_metadata\", args=_args)\n\n    filepath_ = _args.pop(\"filepath\")\n    create_dir_ = _args.pop(\"create_dir\", True)\n    check_parent_dir(path=filepath_, create_dir=create_dir_)\n\n    metadata = ConfigParser.load_config_files(files=_args.pop(\"meta_file\"))\n    url = metadata.get(\"schema\")\n    if url is None:\n        raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n    schema = ConfigParser.load_config_file(filepath=filepath_)\n\n    try:\n        # the rest key-values in the _args are for `validate` API\n        validate(instance=metadata, schema=schema, **_args)\n    except ValidationError as e:\n        # as the error message is very long, only extract the key information\n        logger.info(re.compile(r\".*Failed validating\", re.S).findall(str(e))[0] + f\" against schema `{url}`.\")\n        return\n    logger.info(\"metadata is verified with no error.\")\n\n\ndef verify_net_in_out(\n    net_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    device: Optional[str] = None,\n    p: Optional[int] = None,\n    n: Optional[int] = None,\n    any: Optional[int] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Verify the input and output data shape and data type of network defined in the metadata.\n    Will test with fake Tensor data according to the required data shape in `metadata`.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>\n\n    Args:\n        net_id: ID name of the network component to verify, it must be `torch.nn.Module`.\n        meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        device: target device to run the network forward computation, if None, prefer to \"cuda\" if existing.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n        args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,\n            `net_id` and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--_meta#network_data_format#inputs#image#num_channels 3``.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file,\n        net_id=net_id,\n        meta_file=meta_file,\n        config_file=config_file,\n        device=device,\n        p=p,\n        n=n,\n        any=any,\n        **override,\n    )\n    _log_input_summary(tag=\"verify_net_in_out\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"net_id\", \"\")\n    device_ = torch.device(_args.pop(\"device\", \"cuda:0\" if torch.cuda.is_available() else \"cpu\"))\n    p = _args.pop(\"p\", 1)\n    n = _args.pop(\"n\", 1)\n    any = _args.pop(\"any\", 1)\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    try:\n        key: str = id  # mark the full id when KeyError\n        net = parser.get_parsed_content(key).to(device_)\n        key = \"_meta_#network_data_format#inputs#image#num_channels\"\n        input_channels = parser[key]\n        key = \"_meta_#network_data_format#inputs#image#spatial_shape\"\n        input_spatial_shape = tuple(parser[key])\n        key = \"_meta_#network_data_format#inputs#image#dtype\"\n        input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n        key = \"_meta_#network_data_format#outputs#pred#num_channels\"\n        output_channels = parser[key]\n        key = \"_meta_#network_data_format#outputs#pred#dtype\"\n        output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n    except KeyError as e:\n        raise KeyError(f\"Failed to verify due to missing expected key in the config: {key}.\") from e\n\n    net.eval()\n    with torch.no_grad():\n        spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore\n        test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)\n        output = net(test_data)\n        if output.shape[1] != output_channels:\n            raise ValueError(f\"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.\")\n        if output.dtype != output_dtype:\n            raise ValueError(f\"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.\")\n    logger.info(\"data shape of network is verified with no error.\")\n","new_file_content":"# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport ast\nimport pprint\nimport re\nfrom typing import Dict, Optional, Sequence, Tuple, Union\n\nimport torch\n\nfrom monai.apps.utils import download_url, get_logger\nfrom monai.bundle.config_parser import ConfigParser\nfrom monai.config import PathLike\nfrom monai.utils import check_parent_dir, get_equivalent_dtype, optional_import\n\nvalidate, _ = optional_import(\"jsonschema\", name=\"validate\")\nValidationError, _ = optional_import(\"jsonschema.exceptions\", name=\"ValidationError\")\n\nlogger = get_logger(module_name=__name__)\n\n\ndef _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:\n    \"\"\"\n    Update the `args` with the input `kwargs`.\n    For dict data, recursively update the content based on the keys.\n\n    Args:\n        args: source args to update.\n        ignore_none: whether to ignore input args with None value, default to `True`.\n        kwargs: destination args to update.\n\n    \"\"\"\n    args_: Dict = args if isinstance(args, dict) else {}  # type: ignore\n    if isinstance(args, str):\n        # args are defined in a structured file\n        args_ = ConfigParser.load_config_file(args)\n\n    # recursively update the default args with new args\n    for k, v in kwargs.items():\n        if ignore_none and v is None:\n            continue\n        if isinstance(v, dict) and isinstance(args_.get(k), dict):\n            args_[k] = _update_args(args_[k], ignore_none, **v)\n        else:\n            args_[k] = v\n    return args_\n\n\ndef _log_input_summary(tag, args: Dict):\n    logger.info(f\"--- input summary of monai.bundle.scripts.{tag} ---\")\n    for name, val in args.items():\n        logger.info(f\"> {name}: {pprint.pformat(val)}\")\n    logger.info(\"---\\n\\n\")\n\n\ndef _get_var_names(expr: str):\n    \"\"\"\n    Parse the expression and discover what variables are present in it based on ast module.\n\n    Args:\n        expr: source expression to parse.\n\n    \"\"\"\n    tree = ast.parse(expr)\n    return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]\n\n\ndef _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:\n    \"\"\"\n    Get spatial shape for fake data according to the specified shape pattern.\n    It supports `int` number and `string` with formats like: \"32\", \"32 * n\", \"32 ** p\", \"32 ** p *n\".\n\n    Args:\n        shape: specified pattern for the spatial shape.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n\n    \"\"\"\n    ret = []\n    for i in shape:\n        if isinstance(i, int):\n            ret.append(i)\n        elif isinstance(i, str):\n            if i == \"*\":\n                ret.append(any)\n            else:\n                for c in _get_var_names(i):\n                    if c not in [\"p\", \"n\"]:\n                        raise ValueError(f\"only support variables 'p' and 'n' so far, but got: {c}.\")\n                ret.append(eval(i, {\"p\": p, \"n\": n}))\n        else:\n            raise ValueError(f\"spatial shape items must be int or string, but got: {type(i)} {i}.\")\n    return tuple(ret)\n\n\ndef run(\n    runner_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Specify `meta_file` and `config_file` to run monai bundle components and workflows.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        # Execute this module as a CLI entry:\n        python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>\n\n        # Override config values at runtime by specifying the component id and its new value:\n        python -m monai.bundle run trainer --net#input_chns 1 ...\n\n        # Override config values with another config file `/path/to/another.json`:\n        python -m monai.bundle run evaluator --net %/path/to/another.json ...\n\n        # Override config values with part content of another config file:\n        python -m monai.bundle run trainer --net %/data/other.json#net_arg ...\n\n        # Set default args of `run` in a JSON / YAML file, help to record and simplify the command line.\n        # Other args still can override the default args at runtime:\n        python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n\n    Args:\n        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``\"\"``.\n        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n            `config_file`, and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--net#input_chns 42``.\n\n    \"\"\"\n\n    _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n    if \"config_file\" not in _args:\n        raise ValueError(f\"`config_file` is required for 'monai.bundle run'.\\n{run.__doc__}\")\n    _log_input_summary(tag=\"run\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    if \"meta_file\" in _args:\n        parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"runner_id\", \"\")\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    workflow = parser.get_parsed_content(id=id)\n    if not hasattr(workflow, \"run\"):\n        raise ValueError(f\"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\\n{run.__doc__}\")\n    return workflow.run()\n\n\ndef verify_metadata(\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    filepath: Optional[PathLike] = None,\n    create_dir: Optional[bool] = None,\n    hash_val: Optional[str] = None,\n    hash_type: Optional[str] = None,\n    args_file: Optional[str] = None,\n    **kwargs,\n):\n    \"\"\"\n    Verify the provided `metadata` file based on the predefined `schema`.\n    `metadata` content must contain the `schema` field for the URL of shcema file to download.\n    The schema standard follows: http://json-schema.org/.\n\n    Args:\n        meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        filepath: file path to store the downloaded schema.\n        create_dir: whether to create directories if not existing, default to `True`.\n        hash_val: if not None, define the hash value to verify the downloaded schema file.\n        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to \"md5\".\n        args_file: a JSON or YAML file to provide default values for all the args in this function.\n            so that the command line inputs can be simplified.\n        kwargs: other arguments for `jsonschema.validate()`. for more details:\n            https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file,\n        meta_file=meta_file,\n        filepath=filepath,\n        create_dir=create_dir,\n        hash_val=hash_val,\n        hash_type=hash_type,\n        **kwargs,\n    )\n    _log_input_summary(tag=\"verify_metadata\", args=_args)\n\n    filepath_ = _args.pop(\"filepath\")\n    create_dir_ = _args.pop(\"create_dir\", True)\n    check_parent_dir(path=filepath_, create_dir=create_dir_)\n\n    metadata = ConfigParser.load_config_files(files=_args.pop(\"meta_file\"))\n    url = metadata.get(\"schema\")\n    if url is None:\n        raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n    download_url(\n        url=url,\n        filepath=filepath_,\n        hash_val=_args.pop(\"hash_val\", None),\n        hash_type=_args.pop(\"hash_type\", \"md5\"),\n        progress=True,\n    )\n    schema = ConfigParser.load_config_file(filepath=filepath_)\n\n    try:\n        # the rest key-values in the _args are for `validate` API\n        validate(instance=metadata, schema=schema, **_args)\n    except ValidationError as e:\n        # as the error message is very long, only extract the key information\n        logger.info(re.compile(r\".*Failed validating\", re.S).findall(str(e))[0] + f\" against schema `{url}`.\")\n        return\n    logger.info(\"metadata is verified with no error.\")\n\n\ndef verify_net_in_out(\n    net_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    device: Optional[str] = None,\n    p: Optional[int] = None,\n    n: Optional[int] = None,\n    any: Optional[int] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Verify the input and output data shape and data type of network defined in the metadata.\n    Will test with fake Tensor data according to the required data shape in `metadata`.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>\n\n    Args:\n        net_id: ID name of the network component to verify, it must be `torch.nn.Module`.\n        meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        device: target device to run the network forward computation, if None, prefer to \"cuda\" if existing.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n        args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,\n            `net_id` and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--_meta#network_data_format#inputs#image#num_channels 3``.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file,\n        net_id=net_id,\n        meta_file=meta_file,\n        config_file=config_file,\n        device=device,\n        p=p,\n        n=n,\n        any=any,\n        **override,\n    )\n    _log_input_summary(tag=\"verify_net_in_out\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"net_id\", \"\")\n    device_ = torch.device(_args.pop(\"device\", \"cuda:0\" if torch.cuda.is_available() else \"cpu\"))\n    p = _args.pop(\"p\", 1)\n    n = _args.pop(\"n\", 1)\n    any = _args.pop(\"any\", 1)\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    try:\n        key: str = id  # mark the full id when KeyError\n        net = parser.get_parsed_content(key).to(device_)\n        key = \"_meta_#network_data_format#inputs#image#num_channels\"\n        input_channels = parser[key]\n        key = \"_meta_#network_data_format#inputs#image#spatial_shape\"\n        input_spatial_shape = tuple(parser[key])\n        key = \"_meta_#network_data_format#inputs#image#dtype\"\n        input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n        key = \"_meta_#network_data_format#outputs#pred#num_channels\"\n        output_channels = parser[key]\n        key = \"_meta_#network_data_format#outputs#pred#dtype\"\n        output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n    except KeyError as e:\n        raise KeyError(f\"Failed to verify due to missing expected key in the config: {key}.\") from e\n\n    net.eval()\n    with torch.no_grad():\n        spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore\n        test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)\n        output = net(test_data)\n        if output.shape[1] != output_channels:\n            raise ValueError(f\"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.\")\n        if output.dtype != output_dtype:\n            raise ValueError(f\"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.\")\n    logger.info(\"data shape of network is verified with no error.\")\n","header":{"file":{"path":"monai/bundle/scripts.py"},"misc_line":null},"index_line":null,"is_binary_file":false,"binary_line":null,"minus_file":{"path":"a/monai/bundle/scripts.py"},"plus_file":{"path":"b/monai/bundle/scripts.py"},"hunks":[{"descriptor":{"old_range":{"start":133,"length":9},"new_range":{"start":133,"length":8},"section":"def run("},"line_group":{"all_lines":[{"content":"        python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>","type":"context"},{"content":"","type":"context"},{"content":"    Args:","type":"context"},{"content":"        runner_id: ID name of the runner component or workflow, it must have a `run` method.","type":"deleted"},{"content":"        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.","type":"deleted"},{"content":"            if it is a list of file paths, the content of them will be merged.","type":"deleted"},{"content":"        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``\"\"``.","type":"added"},{"content":"        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.","type":"added"},{"content":"        config_file: filepath of the config file, if `None`, must be provided in `args_file`.","type":"context"},{"content":"            if it is a list of file paths, the content of them will be merged.","type":"context"},{"content":"        args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":146,"length":14},"new_range":{"start":145,"length":14},"section":"def run("},"line_group":{"all_lines":[{"content":"    \"\"\"","type":"context"},{"content":"","type":"context"},{"content":"    _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)","type":"context"},{"content":"    for k in (\"meta_file\", \"config_file\"):","type":"deleted"},{"content":"        if k not in _args:","type":"deleted"},{"content":"            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")","type":"deleted"},{"content":"    if \"config_file\" not in _args:","type":"added"},{"content":"        raise ValueError(f\"`config_file` is required for 'monai.bundle run'.\\n{run.__doc__}\")","type":"added"},{"content":"    _log_input_summary(tag=\"run\", args=_args)","type":"context"},{"content":"","type":"context"},{"content":"    parser = ConfigParser()","type":"context"},{"content":"    parser.read_config(f=_args.pop(\"config_file\"))","type":"context"},{"content":"    parser.read_meta(f=_args.pop(\"meta_file\"))","type":"deleted"},{"content":"    if \"meta_file\" in _args:","type":"added"},{"content":"        parser.read_meta(f=_args.pop(\"meta_file\"))","type":"added"},{"content":"    id = _args.pop(\"runner_id\", \"\")","type":"context"},{"content":"","type":"context"},{"content":"    # the rest key-values in the _args are to override config content","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":162,"length":8},"new_range":{"start":161,"length":8},"section":"def run("},"line_group":{"all_lines":[{"content":"","type":"context"},{"content":"    workflow = parser.get_parsed_content(id=id)","type":"context"},{"content":"    if not hasattr(workflow, \"run\"):","type":"context"},{"content":"        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")","type":"deleted"},{"content":"    workflow.run()","type":"deleted"},{"content":"        raise ValueError(f\"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\\n{run.__doc__}\")","type":"added"},{"content":"    return workflow.run()","type":"added"},{"content":"","type":"context"},{"content":"","type":"context"},{"content":"def verify_metadata(","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":171,"length":6},"new_range":{"start":170,"length":7},"section":"def verify_metadata("},"line_group":{"all_lines":[{"content":"    filepath: Optional[PathLike] = None,","type":"context"},{"content":"    create_dir: Optional[bool] = None,","type":"context"},{"content":"    hash_val: Optional[str] = None,","type":"context"},{"content":"    hash_type: Optional[str] = None,","type":"added"},{"content":"    args_file: Optional[str] = None,","type":"context"},{"content":"    **kwargs,","type":"context"},{"content":"):","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":185,"length":6},"new_range":{"start":185,"length":7},"section":"def verify_metadata("},"line_group":{"all_lines":[{"content":"        filepath: file path to store the downloaded schema.","type":"context"},{"content":"        create_dir: whether to create directories if not existing, default to `True`.","type":"context"},{"content":"        hash_val: if not None, define the hash value to verify the downloaded schema file.","type":"context"},{"content":"        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to \"md5\".","type":"added"},{"content":"        args_file: a JSON or YAML file to provide default values for all the args in this function.","type":"context"},{"content":"            so that the command line inputs can be simplified.","type":"context"},{"content":"        kwargs: other arguments for `jsonschema.validate()`. for more details:","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":193,"length":7},"new_range":{"start":194,"length":13},"section":"def verify_metadata("},"line_group":{"all_lines":[{"content":"    \"\"\"","type":"context"},{"content":"","type":"context"},{"content":"    _args = _update_args(","type":"context"},{"content":"        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs","type":"deleted"},{"content":"        args=args_file,","type":"added"},{"content":"        meta_file=meta_file,","type":"added"},{"content":"        filepath=filepath,","type":"added"},{"content":"        create_dir=create_dir,","type":"added"},{"content":"        hash_val=hash_val,","type":"added"},{"content":"        hash_type=hash_type,","type":"added"},{"content":"        **kwargs,","type":"added"},{"content":"    )","type":"context"},{"content":"    _log_input_summary(tag=\"verify_metadata\", args=_args)","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]},{"descriptor":{"old_range":{"start":205,"length":7},"new_range":{"start":212,"length":13},"section":"def verify_metadata("},"line_group":{"all_lines":[{"content":"    url = metadata.get(\"schema\")","type":"context"},{"content":"    if url is None:","type":"context"},{"content":"        raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")","type":"context"},{"content":"    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)","type":"deleted"},{"content":"    download_url(","type":"added"},{"content":"        url=url,","type":"added"},{"content":"        filepath=filepath_,","type":"added"},{"content":"        hash_val=_args.pop(\"hash_val\", None),","type":"added"},{"content":"        hash_type=_args.pop(\"hash_type\", \"md5\"),","type":"added"},{"content":"        progress=True,","type":"added"},{"content":"    )","type":"added"},{"content":"    schema = ConfigParser.load_config_file(filepath=filepath_)","type":"context"},{"content":"","type":"context"},{"content":"    try:","type":"context"},{"content":"","type":"context"}]},"modified_entities":[],"added_entities":[],"deleted_entities":[]}]}],"old_commit_hash":"8e1aacf5ee7f4e62e9f0f25a9e1a3c37a09439ca","new_commit_hash":"f34604d7daef3723e7cacb483d3b37522f94cbd8","commit_message":"Merge branch 'dev' into 3940-meta-file-optional","commit_date":"2022-03-17T11:19:14Z","metadata":{}}
problem_statement: make 'meta_file' optional for `monai.bundle run`
  **Is your feature request related to a problem? Please describe.**
  make it possible to instantiate components via CLI without providing a metadata file.
  
patch: diff --git a/monai/bundle/scripts.py b/monai/bundle/scripts.py
  --- a/monai/bundle/scripts.py
  +++ b/monai/bundle/scripts.py
  @@ -133,9 +133,8 @@ def run(
           python -m monai.bundle run --args_file "/workspace/data/args.json" --config_file <config path>
   
       Args:
  -        runner_id: ID name of the runner component or workflow, it must have a `run` method.
  -        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.
  -            if it is a list of file paths, the content of them will be merged.
  +        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``""``.
  +        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.
           config_file: filepath of the config file, if `None`, must be provided in `args_file`.
               if it is a list of file paths, the content of them will be merged.
           args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,
  @@ -146,14 +145,14 @@ def run(
       """
   
       _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)
  -    for k in ("meta_file", "config_file"):
  -        if k not in _args:
  -            raise ValueError(f"{k} is required for 'monai.bundle run'.\n{run.__doc__}")
  +    if "config_file" not in _args:
  +        raise ValueError(f"`config_file` is required for 'monai.bundle run'.\n{run.__doc__}")
       _log_input_summary(tag="run", args=_args)
   
       parser = ConfigParser()
       parser.read_config(f=_args.pop("config_file"))
  -    parser.read_meta(f=_args.pop("meta_file"))
  +    if "meta_file" in _args:
  +        parser.read_meta(f=_args.pop("meta_file"))
       id = _args.pop("runner_id", "")
   
       # the rest key-values in the _args are to override config content
  @@ -162,8 +161,8 @@ def run(
   
       workflow = parser.get_parsed_content(id=id)
       if not hasattr(workflow, "run"):
  -        raise ValueError(f"The parsed workflow {type(workflow)} does not have a `run` method.\n{run.__doc__}")
  -    workflow.run()
  +        raise ValueError(f"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\n{run.__doc__}")
  +    return workflow.run()
   
   
   def verify_metadata(
  @@ -171,6 +170,7 @@ def verify_metadata(
       filepath: Optional[PathLike] = None,
       create_dir: Optional[bool] = None,
       hash_val: Optional[str] = None,
  +    hash_type: Optional[str] = None,
       args_file: Optional[str] = None,
       **kwargs,
   ):
  @@ -185,6 +185,7 @@ def verify_metadata(
           filepath: file path to store the downloaded schema.
           create_dir: whether to create directories if not existing, default to `True`.
           hash_val: if not None, define the hash value to verify the downloaded schema file.
  +        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to "md5".
           args_file: a JSON or YAML file to provide default values for all the args in this function.
               so that the command line inputs can be simplified.
           kwargs: other arguments for `jsonschema.validate()`. for more details:
  @@ -193,7 +194,13 @@ def verify_metadata(
       """
   
       _args = _update_args(
  -        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs
  +        args=args_file,
  +        meta_file=meta_file,
  +        filepath=filepath,
  +        create_dir=create_dir,
  +        hash_val=hash_val,
  +        hash_type=hash_type,
  +        **kwargs,
       )
       _log_input_summary(tag="verify_metadata", args=_args)
   
  @@ -205,7 +212,13 @@ def verify_metadata(
       url = metadata.get("schema")
       if url is None:
           raise ValueError("must provide the `schema` field in the metadata for the URL of schema file.")
  -    download_url(url=url, filepath=filepath_, hash_val=_args.pop("hash_val", None), hash_type="md5", progress=True)
  +    download_url(
  +        url=url,
  +        filepath=filepath_,
  +        hash_val=_args.pop("hash_val", None),
  +        hash_type=_args.pop("hash_type", "md5"),
  +        progress=True,
  +    )
       schema = ConfigParser.load_config_file(filepath=filepath_)
   
       try:
   
  
file_context: {"monai/bundle/scripts.py": "# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport ast\nimport pprint\nimport re\nfrom typing import Dict, Optional, Sequence, Tuple, Union\n\nimport torch\n\nfrom monai.apps.utils import download_url, get_logger\nfrom monai.bundle.config_parser import ConfigParser\nfrom monai.config import PathLike\nfrom monai.utils import check_parent_dir, get_equivalent_dtype, optional_import\n\nvalidate, _ = optional_import(\"jsonschema\", name=\"validate\")\nValidationError, _ = optional_import(\"jsonschema.exceptions\", name=\"ValidationError\")\n\nlogger = get_logger(module_name=__name__)\n\n\ndef _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:\n    \"\"\"\n    Update the `args` with the input `kwargs`.\n    For dict data, recursively update the content based on the keys.\n\n    Args:\n        args: source args to update.\n        ignore_none: whether to ignore input args with None value, default to `True`.\n        kwargs: destination args to update.\n\n    \"\"\"\n    args_: Dict = args if isinstance(args, dict) else {}  # type: ignore\n    if isinstance(args, str):\n        # args are defined in a structured file\n        args_ = ConfigParser.load_config_file(args)\n\n    # recursively update the default args with new args\n    for k, v in kwargs.items():\n        if ignore_none and v is None:\n            continue\n        if isinstance(v, dict) and isinstance(args_.get(k), dict):\n            args_[k] = _update_args(args_[k], ignore_none, **v)\n        else:\n            args_[k] = v\n    return args_\n\n\ndef _log_input_summary(tag, args: Dict):\n    logger.info(f\"--- input summary of monai.bundle.scripts.{tag} ---\")\n    for name, val in args.items():\n        logger.info(f\"> {name}: {pprint.pformat(val)}\")\n    logger.info(\"---\\n\\n\")\n\n\ndef _get_var_names(expr: str):\n    \"\"\"\n    Parse the expression and discover what variables are present in it based on ast module.\n\n    Args:\n        expr: source expression to parse.\n\n    \"\"\"\n    tree = ast.parse(expr)\n    return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]\n\n\ndef _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:\n    \"\"\"\n    Get spatial shape for fake data according to the specified shape pattern.\n    It supports `int` number and `string` with formats like: \"32\", \"32 * n\", \"32 ** p\", \"32 ** p *n\".\n\n    Args:\n        shape: specified pattern for the spatial shape.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n\n    \"\"\"\n    ret = []\n    for i in shape:\n        if isinstance(i, int):\n            ret.append(i)\n        elif isinstance(i, str):\n            if i == \"*\":\n                ret.append(any)\n            else:\n                for c in _get_var_names(i):\n                    if c not in [\"p\", \"n\"]:\n                        raise ValueError(f\"only support variables 'p' and 'n' so far, but got: {c}.\")\n                ret.append(eval(i, {\"p\": p, \"n\": n}))\n        else:\n            raise ValueError(f\"spatial shape items must be int or string, but got: {type(i)} {i}.\")\n    return tuple(ret)\n\n\ndef run(\n    runner_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Specify `meta_file` and `config_file` to run monai bundle components and workflows.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        # Execute this module as a CLI entry:\n        python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>\n\n        # Override config values at runtime by specifying the component id and its new value:\n        python -m monai.bundle run trainer --net#input_chns 1 ...\n\n        # Override config values with another config file `/path/to/another.json`:\n        python -m monai.bundle run evaluator --net %/path/to/another.json ...\n\n        # Override config values with part content of another config file:\n        python -m monai.bundle run trainer --net %/data/other.json#net_arg ...\n\n        # Set default args of `run` in a JSON / YAML file, help to record and simplify the command line.\n        # Other args still can override the default args at runtime:\n        python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n\n    Args:\n        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n            `config_file`, and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--net#input_chns 42``.\n\n    \"\"\"\n\n    _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n    for k in (\"meta_file\", \"config_file\"):\n        if k not in _args:\n            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n    _log_input_summary(tag=\"run\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"runner_id\", \"\")\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    workflow = parser.get_parsed_content(id=id)\n    if not hasattr(workflow, \"run\"):\n        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n    workflow.run()\n\n\ndef verify_metadata(\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    filepath: Optional[PathLike] = None,\n    create_dir: Optional[bool] = None,\n    hash_val: Optional[str] = None,\n    args_file: Optional[str] = None,\n    **kwargs,\n):\n    \"\"\"\n    Verify the provided `metadata` file based on the predefined `schema`.\n    `metadata` content must contain the `schema` field for the URL of shcema file to download.\n    The schema standard follows: http://json-schema.org/.\n\n    Args:\n        meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        filepath: file path to store the downloaded schema.\n        create_dir: whether to create directories if not existing, default to `True`.\n        hash_val: if not None, define the hash value to verify the downloaded schema file.\n        args_file: a JSON or YAML file to provide default values for all the args in this function.\n            so that the command line inputs can be simplified.\n        kwargs: other arguments for `jsonschema.validate()`. for more details:\n            https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n    )\n    _log_input_summary(tag=\"verify_metadata\", args=_args)\n\n    filepath_ = _args.pop(\"filepath\")\n    create_dir_ = _args.pop(\"create_dir\", True)\n    check_parent_dir(path=filepath_, create_dir=create_dir_)\n\n    metadata = ConfigParser.load_config_files(files=_args.pop(\"meta_file\"))\n    url = metadata.get(\"schema\")\n    if url is None:\n        raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n    schema = ConfigParser.load_config_file(filepath=filepath_)\n\n    try:\n        # the rest key-values in the _args are for `validate` API\n        validate(instance=metadata, schema=schema, **_args)\n    except ValidationError as e:\n        # as the error message is very long, only extract the key information\n        logger.info(re.compile(r\".*Failed validating\", re.S).findall(str(e))[0] + f\" against schema `{url}`.\")\n        return\n    logger.info(\"metadata is verified with no error.\")\n\n\ndef verify_net_in_out(\n    net_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    device: Optional[str] = None,\n    p: Optional[int] = None,\n    n: Optional[int] = None,\n    any: Optional[int] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Verify the input and output data shape and data type of network defined in the metadata.\n    Will test with fake Tensor data according to the required data shape in `metadata`.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>\n\n    Args:\n        net_id: ID name of the network component to verify, it must be `torch.nn.Module`.\n        meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        device: target device to run the network forward computation, if None, prefer to \"cuda\" if existing.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n        args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,\n            `net_id` and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--_meta#network_data_format#inputs#image#num_channels 3``.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file,\n        net_id=net_id,\n        meta_file=meta_file,\n        config_file=config_file,\n        device=device,\n        p=p,\n        n=n,\n        any=any,\n        **override,\n    )\n    _log_input_summary(tag=\"verify_net_in_out\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"net_id\", \"\")\n    device_ = torch.device(_args.pop(\"device\", \"cuda:0\" if torch.cuda.is_available() else \"cpu\"))\n    p = _args.pop(\"p\", 1)\n    n = _args.pop(\"n\", 1)\n    any = _args.pop(\"any\", 1)\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    try:\n        key: str = id  # mark the full id when KeyError\n        net = parser.get_parsed_content(key).to(device_)\n        key = \"_meta_#network_data_format#inputs#image#num_channels\"\n        input_channels = parser[key]\n        key = \"_meta_#network_data_format#inputs#image#spatial_shape\"\n        input_spatial_shape = tuple(parser[key])\n        key = \"_meta_#network_data_format#inputs#image#dtype\"\n        input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n        key = \"_meta_#network_data_format#outputs#pred#num_channels\"\n        output_channels = parser[key]\n        key = \"_meta_#network_data_format#outputs#pred#dtype\"\n        output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n    except KeyError as e:\n        raise KeyError(f\"Failed to verify due to missing expected key in the config: {key}.\") from e\n\n    net.eval()\n    with torch.no_grad():\n        spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore\n        test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)\n        output = net(test_data)\n        if output.shape[1] != output_channels:\n            raise ValueError(f\"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.\")\n        if output.dtype != output_dtype:\n            raise ValueError(f\"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.\")\n    logger.info(\"data shape of network is verified with no error.\")\n"}
filelevel_patches: {"monai/bundle/scripts.py": "@@ -133,9 +133,8 @@ def run(\n         python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n \n     Args:\n-        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n-        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n-            if it is a list of file paths, the content of them will be merged.\n+        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``\"\"``.\n+        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.\n         config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n             if it is a list of file paths, the content of them will be merged.\n         args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n@@ -146,14 +145,14 @@ def run(\n     \"\"\"\n \n     _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n-    for k in (\"meta_file\", \"config_file\"):\n-        if k not in _args:\n-            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n+    if \"config_file\" not in _args:\n+        raise ValueError(f\"`config_file` is required for 'monai.bundle run'.\\n{run.__doc__}\")\n     _log_input_summary(tag=\"run\", args=_args)\n \n     parser = ConfigParser()\n     parser.read_config(f=_args.pop(\"config_file\"))\n-    parser.read_meta(f=_args.pop(\"meta_file\"))\n+    if \"meta_file\" in _args:\n+        parser.read_meta(f=_args.pop(\"meta_file\"))\n     id = _args.pop(\"runner_id\", \"\")\n \n     # the rest key-values in the _args are to override config content\n@@ -162,8 +161,8 @@ def run(\n \n     workflow = parser.get_parsed_content(id=id)\n     if not hasattr(workflow, \"run\"):\n-        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n-    workflow.run()\n+        raise ValueError(f\"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\\n{run.__doc__}\")\n+    return workflow.run()\n \n \n def verify_metadata(\n@@ -171,6 +170,7 @@ def verify_metadata(\n     filepath: Optional[PathLike] = None,\n     create_dir: Optional[bool] = None,\n     hash_val: Optional[str] = None,\n+    hash_type: Optional[str] = None,\n     args_file: Optional[str] = None,\n     **kwargs,\n ):\n@@ -185,6 +185,7 @@ def verify_metadata(\n         filepath: file path to store the downloaded schema.\n         create_dir: whether to create directories if not existing, default to `True`.\n         hash_val: if not None, define the hash value to verify the downloaded schema file.\n+        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to \"md5\".\n         args_file: a JSON or YAML file to provide default values for all the args in this function.\n             so that the command line inputs can be simplified.\n         kwargs: other arguments for `jsonschema.validate()`. for more details:\n@@ -193,7 +194,13 @@ def verify_metadata(\n     \"\"\"\n \n     _args = _update_args(\n-        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n+        args=args_file,\n+        meta_file=meta_file,\n+        filepath=filepath,\n+        create_dir=create_dir,\n+        hash_val=hash_val,\n+        hash_type=hash_type,\n+        **kwargs,\n     )\n     _log_input_summary(tag=\"verify_metadata\", args=_args)\n@@ -205,7 +212,13 @@ def verify_metadata(\n     url = metadata.get(\"schema\")\n     if url is None:\n         raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n-    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n+    download_url(\n+        url=url,\n+        filepath=filepath_,\n+        hash_val=_args.pop(\"hash_val\", None),\n+        hash_type=_args.pop(\"hash_type\", \"md5\"),\n+        progress=True,\n+    )\n     schema = ConfigParser.load_config_file(filepath=filepath_)\n \n     try:"}
messages.content: 
  We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  make 'meta_file' optional for `monai.bundle run`
  **Is your feature request related to a problem? Please describe.**
  make it possible to instantiate components via CLI without providing a metadata file.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  
  --- BEGIN FILE ---
  ```
  ### monai/bundle/scripts.py
  # Copyright (c) MONAI Consortium
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #     http://www.apache.org/licenses/LICENSE-2.0
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import ast
  import pprint
  import re
  from typing import Dict, Optional, Sequence, Tuple, Union
  
  import torch
  
  from monai.apps.utils import download_url, get_logger
  from monai.bundle.config_parser import ConfigParser
  from monai.config import PathLike
  from monai.utils import check_parent_dir, get_equivalent_dtype, optional_import
  
  validate, _ = optional_import("jsonschema", name="validate")
  ValidationError, _ = optional_import("jsonschema.exceptions", name="ValidationError")
  
  logger = get_logger(module_name=__name__)
  
  
  def _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:
      """
      Update the `args` with the input `kwargs`.
      For dict data, recursively update the content based on the keys.
  
      Args:
          args: source args to update.
          ignore_none: whether to ignore input args with None value, default to `True`.
          kwargs: destination args to update.
  
      """
      args_: Dict = args if isinstance(args, dict) else {}  # type: ignore
      if isinstance(args, str):
          # args are defined in a structured file
          args_ = ConfigParser.load_config_file(args)
  
      # recursively update the default args with new args
      for k, v in kwargs.items():
          if ignore_none and v is None:
              continue
          if isinstance(v, dict) and isinstance(args_.get(k), dict):
              args_[k] = _update_args(args_[k], ignore_none, **v)
          else:
              args_[k] = v
      return args_
  
  
  def _log_input_summary(tag, args: Dict):
      logger.info(f"--- input summary of monai.bundle.scripts.{tag} ---")
      for name, val in args.items():
          logger.info(f"> {name}: {pprint.pformat(val)}")
      logger.info("---\n\n")
  
  
  def _get_var_names(expr: str):
      """
      Parse the expression and discover what variables are present in it based on ast module.
  
      Args:
          expr: source expression to parse.
  
      """
      tree = ast.parse(expr)
      return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]
  
  
  def _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:
      """
      Get spatial shape for fake data according to the specified shape pattern.
      It supports `int` number and `string` with formats like: "32", "32 * n", "32 ** p", "32 ** p *n".
  
      Args:
          shape: specified pattern for the spatial shape.
          p: power factor to generate fake data shape if dim of expected shape is "x**p", default to 1.
          p: multiply factor to generate fake data shape if dim of expected shape is "x*n", default to 1.
          any: specified size to generate fake data shape if dim of expected shape is "*", default to 1.
  
      """
      ret = []
      for i in shape:
          if isinstance(i, int):
              ret.append(i)
          elif isinstance(i, str):
              if i == "*":
                  ret.append(any)
              else:
                  for c in _get_var_names(i):
                      if c not in ["p", "n"]:
                          raise ValueError(f"only support variables 'p' and 'n' so far, but got: {c}.")
                  ret.append(eval(i, {"p": p, "n": n}))
          else:
              raise ValueError(f"spatial shape items must be int or string, but got: {type(i)} {i}.")
      return tuple(ret)
  
  
  def run(
      runner_id: Optional[str] = None,
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      config_file: Optional[Union[str, Sequence[str]]] = None,
      args_file: Optional[str] = None,
      **override,
  ):
      """
      Specify `meta_file` and `config_file` to run monai bundle components and workflows.
  
      Typical usage examples:
  
      .. code-block:: bash
  
          # Execute this module as a CLI entry:
          python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>
  
          # Override config values at runtime by specifying the component id and its new value:
          python -m monai.bundle run trainer --net#input_chns 1 ...
  
          # Override config values with another config file `/path/to/another.json`:
          python -m monai.bundle run evaluator --net %/path/to/another.json ...
  
          # Override config values with part content of another config file:
          python -m monai.bundle run trainer --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 <config path>
  
      Args:
          runner_id: ID name of the runner component or workflow, it must have a `run` method.
          meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          config_file: filepath of the config file, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,
              `config_file`, 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``.
  
      """
  
      _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)
      for k in ("meta_file", "config_file"):
          if k not in _args:
              raise ValueError(f"{k} is required for 'monai.bundle run'.\n{run.__doc__}")
      _log_input_summary(tag="run", args=_args)
  
      parser = ConfigParser()
      parser.read_config(f=_args.pop("config_file"))
      parser.read_meta(f=_args.pop("meta_file"))
      id = _args.pop("runner_id", "")
  
      # the rest key-values in the _args are to override config content
      for k, v in _args.items():
          parser[k] = v
  
      workflow = parser.get_parsed_content(id=id)
      if not hasattr(workflow, "run"):
          raise ValueError(f"The parsed workflow {type(workflow)} does not have a `run` method.\n{run.__doc__}")
      workflow.run()
  
  
  def verify_metadata(
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      filepath: Optional[PathLike] = None,
      create_dir: Optional[bool] = None,
      hash_val: Optional[str] = None,
      args_file: Optional[str] = None,
      **kwargs,
  ):
      """
      Verify the provided `metadata` file based on the predefined `schema`.
      `metadata` content must contain the `schema` field for the URL of shcema file to download.
      The schema standard follows: http://json-schema.org/.
  
      Args:
          meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          filepath: file path to store the downloaded schema.
          create_dir: whether to create directories if not existing, default to `True`.
          hash_val: if not None, define the hash value to verify the downloaded schema file.
          args_file: a JSON or YAML file to provide default values for all the args in this function.
              so that the command line inputs can be simplified.
          kwargs: other arguments for `jsonschema.validate()`. for more details:
              https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.
  
      """
  
      _args = _update_args(
          args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs
      )
      _log_input_summary(tag="verify_metadata", args=_args)
  
      filepath_ = _args.pop("filepath")
      create_dir_ = _args.pop("create_dir", True)
      check_parent_dir(path=filepath_, create_dir=create_dir_)
  
      metadata = ConfigParser.load_config_files(files=_args.pop("meta_file"))
      url = metadata.get("schema")
      if url is None:
          raise ValueError("must provide the `schema` field in the metadata for the URL of schema file.")
      download_url(url=url, filepath=filepath_, hash_val=_args.pop("hash_val", None), hash_type="md5", progress=True)
      schema = ConfigParser.load_config_file(filepath=filepath_)
  
      try:
          # the rest key-values in the _args are for `validate` API
          validate(instance=metadata, schema=schema, **_args)
      except ValidationError as e:
          # as the error message is very long, only extract the key information
          logger.info(re.compile(r".*Failed validating", re.S).findall(str(e))[0] + f" against schema `{url}`.")
          return
      logger.info("metadata is verified with no error.")
  
  
  def verify_net_in_out(
      net_id: Optional[str] = None,
      meta_file: Optional[Union[str, Sequence[str]]] = None,
      config_file: Optional[Union[str, Sequence[str]]] = None,
      device: Optional[str] = None,
      p: Optional[int] = None,
      n: Optional[int] = None,
      any: Optional[int] = None,
      args_file: Optional[str] = None,
      **override,
  ):
      """
      Verify the input and output data shape and data type of network defined in the metadata.
      Will test with fake Tensor data according to the required data shape in `metadata`.
  
      Typical usage examples:
  
      .. code-block:: bash
  
          python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>
  
      Args:
          net_id: ID name of the network component to verify, it must be `torch.nn.Module`.
          meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.
              if it is a list of file paths, the content of them will be merged.
          device: target device to run the network forward computation, if None, prefer to "cuda" if existing.
          p: power factor to generate fake data shape if dim of expected shape is "x**p", default to 1.
          p: multiply factor to generate fake data shape if dim of expected shape is "x*n", default to 1.
          any: specified size to generate fake data shape if dim of expected shape is "*", default to 1.
          args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,
              `net_id` 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. ``--_meta#network_data_format#inputs#image#num_channels 3``.
  
      """
  
      _args = _update_args(
          args=args_file,
          net_id=net_id,
          meta_file=meta_file,
          config_file=config_file,
          device=device,
          p=p,
          n=n,
          any=any,
          **override,
      )
      _log_input_summary(tag="verify_net_in_out", args=_args)
  
      parser = ConfigParser()
      parser.read_config(f=_args.pop("config_file"))
      parser.read_meta(f=_args.pop("meta_file"))
      id = _args.pop("net_id", "")
      device_ = torch.device(_args.pop("device", "cuda:0" if torch.cuda.is_available() else "cpu"))
      p = _args.pop("p", 1)
      n = _args.pop("n", 1)
      any = _args.pop("any", 1)
  
      # the rest key-values in the _args are to override config content
      for k, v in _args.items():
          parser[k] = v
  
      try:
          key: str = id  # mark the full id when KeyError
          net = parser.get_parsed_content(key).to(device_)
          key = "_meta_#network_data_format#inputs#image#num_channels"
          input_channels = parser[key]
          key = "_meta_#network_data_format#inputs#image#spatial_shape"
          input_spatial_shape = tuple(parser[key])
          key = "_meta_#network_data_format#inputs#image#dtype"
          input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)
          key = "_meta_#network_data_format#outputs#pred#num_channels"
          output_channels = parser[key]
          key = "_meta_#network_data_format#outputs#pred#dtype"
          output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)
      except KeyError as e:
          raise KeyError(f"Failed to verify due to missing expected key in the config: {key}.") from e
  
      net.eval()
      with torch.no_grad():
          spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore
          test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)
          output = net(test_data)
          if output.shape[1] != output_channels:
              raise ValueError(f"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.")
          if output.dtype != output_dtype:
              raise ValueError(f"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.")
      logger.info("data shape of network is verified with no error.")
  
  ```
  --- END FILE ---
  
  Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.
  
  Every *SEARCH/REPLACE* edit must use this format:
  1. The file path
  2. The start of search block: <<<<<<< SEARCH
  3. A contiguous chunk of lines to search for in the existing source code
  4. The dividing line: =======
  5. The lines to replace into the source code
  6. The end of the replace block: >>>>>>> REPLACE
  
  Here is an example:
  
  ```python
  ### mathweb/flask/app.py
  <<<<<<< SEARCH
  from flask import Flask
  =======
  import math
  from flask import Flask
  >>>>>>> REPLACE
  ```
  
  Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
  Wrap the *SEARCH/REPLACE* edit in blocks ```python...```.
  
messages.role: user
verification_info: {"file_context": {"monai/bundle/scripts.py": "# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport ast\nimport pprint\nimport re\nfrom typing import Dict, Optional, Sequence, Tuple, Union\n\nimport torch\n\nfrom monai.apps.utils import download_url, get_logger\nfrom monai.bundle.config_parser import ConfigParser\nfrom monai.config import PathLike\nfrom monai.utils import check_parent_dir, get_equivalent_dtype, optional_import\n\nvalidate, _ = optional_import(\"jsonschema\", name=\"validate\")\nValidationError, _ = optional_import(\"jsonschema.exceptions\", name=\"ValidationError\")\n\nlogger = get_logger(module_name=__name__)\n\n\ndef _update_args(args: Optional[Union[str, Dict]] = None, ignore_none: bool = True, **kwargs) -> Dict:\n    \"\"\"\n    Update the `args` with the input `kwargs`.\n    For dict data, recursively update the content based on the keys.\n\n    Args:\n        args: source args to update.\n        ignore_none: whether to ignore input args with None value, default to `True`.\n        kwargs: destination args to update.\n\n    \"\"\"\n    args_: Dict = args if isinstance(args, dict) else {}  # type: ignore\n    if isinstance(args, str):\n        # args are defined in a structured file\n        args_ = ConfigParser.load_config_file(args)\n\n    # recursively update the default args with new args\n    for k, v in kwargs.items():\n        if ignore_none and v is None:\n            continue\n        if isinstance(v, dict) and isinstance(args_.get(k), dict):\n            args_[k] = _update_args(args_[k], ignore_none, **v)\n        else:\n            args_[k] = v\n    return args_\n\n\ndef _log_input_summary(tag, args: Dict):\n    logger.info(f\"--- input summary of monai.bundle.scripts.{tag} ---\")\n    for name, val in args.items():\n        logger.info(f\"> {name}: {pprint.pformat(val)}\")\n    logger.info(\"---\\n\\n\")\n\n\ndef _get_var_names(expr: str):\n    \"\"\"\n    Parse the expression and discover what variables are present in it based on ast module.\n\n    Args:\n        expr: source expression to parse.\n\n    \"\"\"\n    tree = ast.parse(expr)\n    return [m.id for m in ast.walk(tree) if isinstance(m, ast.Name)]\n\n\ndef _get_fake_spatial_shape(shape: Sequence[Union[str, int]], p: int = 1, n: int = 1, any: int = 1) -> Tuple:\n    \"\"\"\n    Get spatial shape for fake data according to the specified shape pattern.\n    It supports `int` number and `string` with formats like: \"32\", \"32 * n\", \"32 ** p\", \"32 ** p *n\".\n\n    Args:\n        shape: specified pattern for the spatial shape.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n\n    \"\"\"\n    ret = []\n    for i in shape:\n        if isinstance(i, int):\n            ret.append(i)\n        elif isinstance(i, str):\n            if i == \"*\":\n                ret.append(any)\n            else:\n                for c in _get_var_names(i):\n                    if c not in [\"p\", \"n\"]:\n                        raise ValueError(f\"only support variables 'p' and 'n' so far, but got: {c}.\")\n                ret.append(eval(i, {\"p\": p, \"n\": n}))\n        else:\n            raise ValueError(f\"spatial shape items must be int or string, but got: {type(i)} {i}.\")\n    return tuple(ret)\n\n\ndef run(\n    runner_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Specify `meta_file` and `config_file` to run monai bundle components and workflows.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        # Execute this module as a CLI entry:\n        python -m monai.bundle run trainer --meta_file <meta path> --config_file <config path>\n\n        # Override config values at runtime by specifying the component id and its new value:\n        python -m monai.bundle run trainer --net#input_chns 1 ...\n\n        # Override config values with another config file `/path/to/another.json`:\n        python -m monai.bundle run evaluator --net %/path/to/another.json ...\n\n        # Override config values with part content of another config file:\n        python -m monai.bundle run trainer --net %/data/other.json#net_arg ...\n\n        # Set default args of `run` in a JSON / YAML file, help to record and simplify the command line.\n        # Other args still can override the default args at runtime:\n        python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n\n    Args:\n        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n            `config_file`, and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--net#input_chns 42``.\n\n    \"\"\"\n\n    _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n    for k in (\"meta_file\", \"config_file\"):\n        if k not in _args:\n            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n    _log_input_summary(tag=\"run\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"runner_id\", \"\")\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    workflow = parser.get_parsed_content(id=id)\n    if not hasattr(workflow, \"run\"):\n        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n    workflow.run()\n\n\ndef verify_metadata(\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    filepath: Optional[PathLike] = None,\n    create_dir: Optional[bool] = None,\n    hash_val: Optional[str] = None,\n    args_file: Optional[str] = None,\n    **kwargs,\n):\n    \"\"\"\n    Verify the provided `metadata` file based on the predefined `schema`.\n    `metadata` content must contain the `schema` field for the URL of shcema file to download.\n    The schema standard follows: http://json-schema.org/.\n\n    Args:\n        meta_file: filepath of the metadata file to verify, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        filepath: file path to store the downloaded schema.\n        create_dir: whether to create directories if not existing, default to `True`.\n        hash_val: if not None, define the hash value to verify the downloaded schema file.\n        args_file: a JSON or YAML file to provide default values for all the args in this function.\n            so that the command line inputs can be simplified.\n        kwargs: other arguments for `jsonschema.validate()`. for more details:\n            https://python-jsonschema.readthedocs.io/en/stable/validate/#jsonschema.validate.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n    )\n    _log_input_summary(tag=\"verify_metadata\", args=_args)\n\n    filepath_ = _args.pop(\"filepath\")\n    create_dir_ = _args.pop(\"create_dir\", True)\n    check_parent_dir(path=filepath_, create_dir=create_dir_)\n\n    metadata = ConfigParser.load_config_files(files=_args.pop(\"meta_file\"))\n    url = metadata.get(\"schema\")\n    if url is None:\n        raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n    schema = ConfigParser.load_config_file(filepath=filepath_)\n\n    try:\n        # the rest key-values in the _args are for `validate` API\n        validate(instance=metadata, schema=schema, **_args)\n    except ValidationError as e:\n        # as the error message is very long, only extract the key information\n        logger.info(re.compile(r\".*Failed validating\", re.S).findall(str(e))[0] + f\" against schema `{url}`.\")\n        return\n    logger.info(\"metadata is verified with no error.\")\n\n\ndef verify_net_in_out(\n    net_id: Optional[str] = None,\n    meta_file: Optional[Union[str, Sequence[str]]] = None,\n    config_file: Optional[Union[str, Sequence[str]]] = None,\n    device: Optional[str] = None,\n    p: Optional[int] = None,\n    n: Optional[int] = None,\n    any: Optional[int] = None,\n    args_file: Optional[str] = None,\n    **override,\n):\n    \"\"\"\n    Verify the input and output data shape and data type of network defined in the metadata.\n    Will test with fake Tensor data according to the required data shape in `metadata`.\n\n    Typical usage examples:\n\n    .. code-block:: bash\n\n        python -m monai.bundle verify_net_in_out network --meta_file <meta path> --config_file <config path>\n\n    Args:\n        net_id: ID name of the network component to verify, it must be `torch.nn.Module`.\n        meta_file: filepath of the metadata file to get network args, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        config_file: filepath of the config file to get network definition, if `None`, must be provided in `args_file`.\n            if it is a list of file paths, the content of them will be merged.\n        device: target device to run the network forward computation, if None, prefer to \"cuda\" if existing.\n        p: power factor to generate fake data shape if dim of expected shape is \"x**p\", default to 1.\n        p: multiply factor to generate fake data shape if dim of expected shape is \"x*n\", default to 1.\n        any: specified size to generate fake data shape if dim of expected shape is \"*\", default to 1.\n        args_file: a JSON or YAML file to provide default values for `meta_file`, `config_file`,\n            `net_id` and override pairs. so that the command line inputs can be simplified.\n        override: id-value pairs to override or add the corresponding config content.\n            e.g. ``--_meta#network_data_format#inputs#image#num_channels 3``.\n\n    \"\"\"\n\n    _args = _update_args(\n        args=args_file,\n        net_id=net_id,\n        meta_file=meta_file,\n        config_file=config_file,\n        device=device,\n        p=p,\n        n=n,\n        any=any,\n        **override,\n    )\n    _log_input_summary(tag=\"verify_net_in_out\", args=_args)\n\n    parser = ConfigParser()\n    parser.read_config(f=_args.pop(\"config_file\"))\n    parser.read_meta(f=_args.pop(\"meta_file\"))\n    id = _args.pop(\"net_id\", \"\")\n    device_ = torch.device(_args.pop(\"device\", \"cuda:0\" if torch.cuda.is_available() else \"cpu\"))\n    p = _args.pop(\"p\", 1)\n    n = _args.pop(\"n\", 1)\n    any = _args.pop(\"any\", 1)\n\n    # the rest key-values in the _args are to override config content\n    for k, v in _args.items():\n        parser[k] = v\n\n    try:\n        key: str = id  # mark the full id when KeyError\n        net = parser.get_parsed_content(key).to(device_)\n        key = \"_meta_#network_data_format#inputs#image#num_channels\"\n        input_channels = parser[key]\n        key = \"_meta_#network_data_format#inputs#image#spatial_shape\"\n        input_spatial_shape = tuple(parser[key])\n        key = \"_meta_#network_data_format#inputs#image#dtype\"\n        input_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n        key = \"_meta_#network_data_format#outputs#pred#num_channels\"\n        output_channels = parser[key]\n        key = \"_meta_#network_data_format#outputs#pred#dtype\"\n        output_dtype = get_equivalent_dtype(parser[key], torch.Tensor)\n    except KeyError as e:\n        raise KeyError(f\"Failed to verify due to missing expected key in the config: {key}.\") from e\n\n    net.eval()\n    with torch.no_grad():\n        spatial_shape = _get_fake_spatial_shape(input_spatial_shape, p=p, n=n, any=any)  # type: ignore\n        test_data = torch.rand(*(1, input_channels, *spatial_shape), dtype=input_dtype, device=device_)\n        output = net(test_data)\n        if output.shape[1] != output_channels:\n            raise ValueError(f\"output channel number `{output.shape[1]}` doesn't match: `{output_channels}`.\")\n        if output.dtype != output_dtype:\n            raise ValueError(f\"dtype of output data `{output.dtype}` doesn't match: {output_dtype}.\")\n    logger.info(\"data shape of network is verified with no error.\")\n"}, "filelevel_patches": {"monai/bundle/scripts.py": "@@ -133,9 +133,8 @@ def run(\n         python -m monai.bundle run --args_file \"/workspace/data/args.json\" --config_file <config path>\n \n     Args:\n-        runner_id: ID name of the runner component or workflow, it must have a `run` method.\n-        meta_file: filepath of the metadata file, if `None`, must be provided in `args_file`.\n-            if it is a list of file paths, the content of them will be merged.\n+        runner_id: ID name of the runner component or workflow, it must have a `run` method. Defaults to ``\"\"``.\n+        meta_file: filepath of the metadata file, if it is a list of file paths, the content of them will be merged.\n         config_file: filepath of the config file, if `None`, must be provided in `args_file`.\n             if it is a list of file paths, the content of them will be merged.\n         args_file: a JSON or YAML file to provide default values for `runner_id`, `meta_file`,\n@@ -146,14 +145,14 @@ def run(\n     \"\"\"\n \n     _args = _update_args(args=args_file, runner_id=runner_id, meta_file=meta_file, config_file=config_file, **override)\n-    for k in (\"meta_file\", \"config_file\"):\n-        if k not in _args:\n-            raise ValueError(f\"{k} is required for 'monai.bundle run'.\\n{run.__doc__}\")\n+    if \"config_file\" not in _args:\n+        raise ValueError(f\"`config_file` is required for 'monai.bundle run'.\\n{run.__doc__}\")\n     _log_input_summary(tag=\"run\", args=_args)\n \n     parser = ConfigParser()\n     parser.read_config(f=_args.pop(\"config_file\"))\n-    parser.read_meta(f=_args.pop(\"meta_file\"))\n+    if \"meta_file\" in _args:\n+        parser.read_meta(f=_args.pop(\"meta_file\"))\n     id = _args.pop(\"runner_id\", \"\")\n \n     # the rest key-values in the _args are to override config content\n@@ -162,8 +161,8 @@ def run(\n \n     workflow = parser.get_parsed_content(id=id)\n     if not hasattr(workflow, \"run\"):\n-        raise ValueError(f\"The parsed workflow {type(workflow)} does not have a `run` method.\\n{run.__doc__}\")\n-    workflow.run()\n+        raise ValueError(f\"The parsed workflow {type(workflow)} (id={id}) does not have a `run` method.\\n{run.__doc__}\")\n+    return workflow.run()\n \n \n def verify_metadata(\n@@ -171,6 +170,7 @@ def verify_metadata(\n     filepath: Optional[PathLike] = None,\n     create_dir: Optional[bool] = None,\n     hash_val: Optional[str] = None,\n+    hash_type: Optional[str] = None,\n     args_file: Optional[str] = None,\n     **kwargs,\n ):\n@@ -185,6 +185,7 @@ def verify_metadata(\n         filepath: file path to store the downloaded schema.\n         create_dir: whether to create directories if not existing, default to `True`.\n         hash_val: if not None, define the hash value to verify the downloaded schema file.\n+        hash_type: if not None, define the hash type to verify the downloaded schema file. Defaults to \"md5\".\n         args_file: a JSON or YAML file to provide default values for all the args in this function.\n             so that the command line inputs can be simplified.\n         kwargs: other arguments for `jsonschema.validate()`. for more details:\n@@ -193,7 +194,13 @@ def verify_metadata(\n     \"\"\"\n \n     _args = _update_args(\n-        args=args_file, meta_file=meta_file, filepath=filepath, create_dir=create_dir, hash_val=hash_val, **kwargs\n+        args=args_file,\n+        meta_file=meta_file,\n+        filepath=filepath,\n+        create_dir=create_dir,\n+        hash_val=hash_val,\n+        hash_type=hash_type,\n+        **kwargs,\n     )\n     _log_input_summary(tag=\"verify_metadata\", args=_args)\n@@ -205,7 +212,13 @@ def verify_metadata(\n     url = metadata.get(\"schema\")\n     if url is None:\n         raise ValueError(\"must provide the `schema` field in the metadata for the URL of schema file.\")\n-    download_url(url=url, filepath=filepath_, hash_val=_args.pop(\"hash_val\", None), hash_type=\"md5\", progress=True)\n+    download_url(\n+        url=url,\n+        filepath=filepath_,\n+        hash_val=_args.pop(\"hash_val\", None),\n+        hash_type=_args.pop(\"hash_type\", \"md5\"),\n+        progress=True,\n+    )\n     schema = ConfigParser.load_config_file(filepath=filepath_)\n \n     try:"}}