diff --git a/spock/builder.py b/spock/builder.py index 87063af9..0eba4939 100644 --- a/spock/builder.py +++ b/spock/builder.py @@ -19,8 +19,14 @@ from spock.backend.payload import AttrPayload from spock.backend.saver import AttrSaver from spock.backend.wrappers import Spockspace -from spock.exceptions import _SpockEvolveError -from spock.utils import _C, _T, check_payload_overwrite, deep_payload_update +from spock.exceptions import _SpockEvolveError, _SpockValueError +from spock.utils import ( + _C, + _T, + _is_spock_instance, + check_payload_overwrite, + deep_payload_update, +) class ConfigArgBuilder: @@ -588,6 +594,31 @@ def spockspace_2_dict(self, payload: Spockspace) -> Dict: """ return self._saver_obj.dict_payload(payload) + def obj_2_dict(self, obj: Union[_C, List[_C], Tuple[_C, ...]]) -> Dict[str, Dict]: + """Converts spock classes from a Spockspace into their dictionary representations + + Args: + objs: single spock class or an iterable of spock classes + + Returns: + dictionary where the class names are keys and the values are the dictionary representations + """ + if isinstance(obj, (List, Tuple)): + obj_dict = {} + for val in obj: + if not _is_spock_instance(val): + raise _SpockValueError( + f"Object is not a @spock decorated class object -- currently `{type(val)}`" + ) + obj_dict.update({type(val).__name__: val}) + elif _is_spock_instance(obj): + obj_dict = {type(obj).__name__: obj} + else: + raise _SpockValueError( + f"Object is not a @spock decorated class object -- currently `{type(obj)}`" + ) + return self.spockspace_2_dict(Spockspace(**obj_dict)) + def evolve(self, *args: _C) -> Spockspace: """Function that allows a user to evolve the underlying spock classes with instantiated spock objects diff --git a/tests/base/test_evolve.py b/tests/base/test_evolve.py index 9e02ae99..d83c3a9e 100644 --- a/tests/base/test_evolve.py +++ b/tests/base/test_evolve.py @@ -172,3 +172,6 @@ def test_2_dict(self, arg_builder): # Evolve the class new_class = arg_builder.evolve(evolve_nested_stuff, evolve_type_config) assert isinstance(arg_builder.spockspace_2_dict(new_class), dict) is True + + + diff --git a/tests/base/test_spockspace.py b/tests/base/test_spockspace.py index e8522e3a..e352ced8 100644 --- a/tests/base/test_spockspace.py +++ b/tests/base/test_spockspace.py @@ -5,6 +5,7 @@ from attr.exceptions import FrozenInstanceError from spock.builder import ConfigArgBuilder +from spock.exceptions import _SpockValueError from tests.base.attr_configs_test import * @@ -35,6 +36,49 @@ def test_repr(self, monkeypatch, capsys): assert ("NestedListStuff" in out) and "TypeConfig" in out +class TestToDict: + def test_2_dict(self, monkeypatch): + with monkeypatch.context() as m: + m.setattr(sys, "argv", ["", "--config", "./tests/conf/yaml/test.yaml"]) + config = ConfigArgBuilder( + *all_configs, + desc="Test Builder", + ) + configs = config.generate() + config_dict = config.spockspace_2_dict(configs) + assert isinstance(config_dict, dict) is True + + +class TestClassToDict: + def test_class_2_dict(self, monkeypatch): + with monkeypatch.context() as m: + m.setattr(sys, "argv", ["", "--config", "./tests/conf/yaml/test.yaml"]) + config = ConfigArgBuilder( + *all_configs, + desc="Test Builder", + ) + configs = config.generate() + config_dict = config.obj_2_dict(configs.TypeConfig) + assert isinstance(config_dict, dict) is True + assert isinstance(config_dict['TypeConfig'], dict) is True + configs_dicts = config.obj_2_dict((configs.TypeConfig, configs.NestedStuff)) + assert isinstance(configs_dicts['TypeConfig'], dict) is True + assert isinstance(configs_dicts['NestedStuff'], dict) is True + + def test_raise_incorrect_type(self, monkeypatch): + with monkeypatch.context() as m: + m.setattr(sys, "argv", ["", "--config", "./tests/conf/yaml/test.yaml"]) + config = ConfigArgBuilder( + *all_configs, + desc="Test Builder", + ) + configs = config.generate() + with pytest.raises(_SpockValueError): + config_dict = config.obj_2_dict("foo") + with pytest.raises(_SpockValueError): + config_dict = config.obj_2_dict(("foo", 10)) + + class TestFrozen: """Testing the frozen state of the spock config object"""