Repository: Project-MONAI/MONAI

Issue:
Add default return value for `get_parsed_content`
**Is your feature request related to a problem? Please describe.**
Feature request from @holgerroth :
can we add a default return to [get_parsed_content()](https://github.com/Project-MONAI/MONAI/blob/9d23698750f6cc5def10ce66939b4865909009c0/monai/bundle/config_parser.py#L213), similar to how you can do get("key", None) in dictionaries?
I have this use case where I want to parse and instantiate optional filters. So, they might not always exist in the configuration file. Currently, I solve it with try/except blocks [here](https://github.com/Project-MONAI/monai-fl/blob/a7584f720f54543acbcd6403f99c2c429e356b0c/monaifl/monai_algo.py#L67), but using:
```py
self.pre_filters = self.filter_parser.get_parsed_content("pre_filters", default=None) 
```
would be nicer, I think.


Discussion:

Patch:
diff --git a/monai/bundle/config_parser.py b/monai/bundle/config_parser.py
--- a/monai/bundle/config_parser.py
+++ b/monai/bundle/config_parser.py
@@ -226,7 +226,8 @@ def get_parsed_content(self, id: str = "", **kwargs):
             kwargs: additional keyword arguments to be passed to ``_resolve_one_item``.
                 Currently support ``lazy`` (whether to retain the current config cache, default to `True`),
                 ``instantiate`` (whether to instantiate the `ConfigComponent`, default to `True`) and
-                ``eval_expr`` (whether to evaluate the `ConfigExpression`, default to `True`).
+                ``eval_expr`` (whether to evaluate the `ConfigExpression`, default to `True`), ``default``
+                (the default config item if the `id` is not in the config content).
 
         """
         if not self.ref_resolver.is_resolved():
diff --git a/monai/bundle/reference_resolver.py b/monai/bundle/reference_resolver.py
--- a/monai/bundle/reference_resolver.py
+++ b/monai/bundle/reference_resolver.py
@@ -111,14 +111,16 @@ def _resolve_one_item(self, id: str, waiting_list: Optional[Set[str]] = None, **
             waiting_list: set of ids pending to be resolved.
                 It's used to detect circular references such as:
                 `{"name": "A", "dep": "@B"}` and `{"name": "B", "dep": "@A"}`.
-             kwargs: keyword arguments to pass to ``_resolve_one_item()``.
-                Currently support ``instantiate`` and ``eval_expr``. Both are defaulting to True.
+            kwargs: keyword arguments to pass to ``_resolve_one_item()``.
+                Currently support ``instantiate``, ``eval_expr`` and ``default``.
+                `instantiate` and `eval_expr` are defaulting to True, `default` is the target config item
+                if the `id` is not in the config content, must be a `ConfigItem` object.
 
         """
         if id in self.resolved_content:
             return self.resolved_content[id]
         try:
-            item = look_up_option(id, self.items, print_all_options=False)
+            item = look_up_option(id, self.items, print_all_options=False, default=kwargs.get("default", "no_default"))
         except ValueError as err:
             raise KeyError(f"id='{id}' is not found in the config resolver.") from err
         item_config = item.get_config()
@@ -175,8 +177,10 @@ def get_resolved_content(self, id: str, **kwargs):
 
         Args:
             id: id name of the expected item.
-            kwargs: additional keyword arguments to be passed to ``_resolve_one_item``.
-                Currently support ``instantiate`` and ``eval_expr``. Both are defaulting to True.
+            kwargs: keyword arguments to pass to ``_resolve_one_item()``.
+                Currently support ``instantiate``, ``eval_expr`` and ``default``.
+                `instantiate` and `eval_expr` are defaulting to True, `default` is the target config item
+                if the `id` is not in the config content, must be a `ConfigItem` object.
 
         """
         return self._resolve_one_item(id=id, **kwargs)


Test patch:
diff --git a/tests/test_config_parser.py b/tests/test_config_parser.py
--- a/tests/test_config_parser.py
+++ b/tests/test_config_parser.py
@@ -18,6 +18,7 @@
 from parameterized import parameterized
 
 from monai.bundle import ConfigParser, ReferenceResolver
+from monai.bundle.config_item import ConfigItem
 from monai.data import DataLoader, Dataset
 from monai.transforms import Compose, LoadImaged, RandTorchVisiond
 from monai.utils import min_version, optional_import
@@ -129,6 +130,8 @@ def test_parse(self, config, expected_ids, output_types):
         root = parser.get_parsed_content(id="")
         for v, cls in zip(root.values(), [Compose, Dataset, DataLoader]):
             self.assertTrue(isinstance(v, cls))
+        # test default value
+        self.assertEqual(parser.get_parsed_content(id="abc", default=ConfigItem(12345, "abc")), 12345)
 
     @parameterized.expand([TEST_CASE_2])
     def test_function(self, config):