Skip to content

Commit

Permalink
5804 Simplify the configparser usage to get parsed attributes easily (#…
Browse files Browse the repository at this point in the history
…5813)

part of #5804.

### Description

This adds a simple attribute access for ConfigParser so

```python
from monai.bundle import ConfigParser
parser = ConfigParser({"a":"b"})
a = parser.get_parsed_content("a")
```
can be rewritten to
```python
from monai.bundle import ConfigParser
parser = ConfigParser({"a":"b"})
a = parser.a
```
This only works for variables/methods that are not included in
ConfigParser so e.g. `parser.config` would still get the whole config.
This PR only supports shallow attribute accesses, since the returned
value will be a `dict` where you need to use `["key"]` to get the
content.

### Types of changes
<!--- Put an `x` in all the boxes that apply, and remove the not
applicable items -->
- [x] Non-breaking change (fix or new feature that would not break
existing functionality).
- [x] New tests added to cover the changes.
- [x] Quick tests passed locally by running `./runtests.sh --quick
--unittests --disttests`.

Signed-off-by: Felix Schnabel <f.schnabel@tum.de>
  • Loading branch information
Shadow-Devil authored Jan 6, 2023
1 parent 2c2de9e commit 9efd54d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/source/bundle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Model Bundle
---------------
.. autoclass:: ConfigParser
:members:
:special-members:

`Scripts`
---------
Expand Down
13 changes: 13 additions & 0 deletions monai/bundle/config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ def __init__(
def __repr__(self):
return f"{self.config}"

def __getattr__(self, id):
"""
Get the parsed result of ``ConfigItem`` with the specified ``id``
with default arguments (e.g. ``lazy=True``, ``instantiate=True`` and ``eval_expr=True``).
Args:
id: id of the ``ConfigItem``.
See also:
:py:meth:`get_parsed_content`
"""
return self.get_parsed_content(id)

def __getitem__(self, id: Union[str, int]):
"""
Get the config by id.
Expand Down
2 changes: 1 addition & 1 deletion tests/test_auto3dseg_ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ def test_ensemble(self) -> None:
builder = AlgoEnsembleBuilder(history, data_src_cfg)
builder.set_ensemble_method(AlgoEnsembleBestN(n_best=1))
ensemble = builder.get_ensemble()
pred_param["network#init_filter"] = 8 # segresnet
pred_param["network#init_filters"] = 8 # segresnet
preds = ensemble(pred_param)
self.assertTupleEqual(preds[0].shape, (2, 24, 24, 24))

Expand Down
16 changes: 16 additions & 0 deletions tests/test_config_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,22 @@ def test_pdb(self):
with self.assertRaisesRegex(RuntimeError, ".*bdb.BdbQuit.*"):
case_pdb()

def test_get_via_attributes(self):
config = {
"A": {"B": {"C": 1}},
"my_dims": 2,
"dims_1": "$@my_dims + 1",
"patch_size": [8, 8],
"transform": {"_target_": "Lambda", "func": "$lambda x: x.reshape((1, *@patch_size))"},
}
parser = ConfigParser(config=config)
self.assertEqual(parser.A, {"B": {"C": 1}})
self.assertEqual(parser.dims_1, 3)

trans = parser.transform
result = trans(np.ones(64))
self.assertTupleEqual(result.shape, (1, 8, 8))


if __name__ == "__main__":
unittest.main()

0 comments on commit 9efd54d

Please sign in to comment.