1- # mypy: ignore-errors
21"""
32==================================
43The Component Configuration Parser
2221
2322"""
2423
24+ from typing import Union
25+
2526from layered_config_tree .main import LayeredConfigTree
2627
2728from vivarium .framework .utilities import import_by_path
2829
2930from ... import Component
3031from .manager import ComponentConfigError
3132
33+ _NestedDict = dict [str , Union [str , list [str ], "_NestedDict" ]]
34+
3235
3336class ParsingError (ComponentConfigError ):
3437 """Error raised when component configurations are not specified correctly."""
@@ -117,7 +120,7 @@ def parse_component_config(self, component_config: LayeredConfigTree) -> list[Co
117120 return self .process_level (component_config .to_dict (), [])
118121
119122 def process_level (
120- self , level : str | list [str ] | dict [ str , dict | list ] , prefix : list [str ]
123+ self , level : str | list [str ] | _NestedDict , prefix : list [str ]
121124 ) -> list [Component ]:
122125 """Helper function for parsing hierarchical component configuration into a
123126 flat list of Components.
@@ -173,8 +176,8 @@ def process_level(
173176 component_list .extend (components )
174177 elif isinstance (level , list ):
175178 for child in level :
176- component = self .process_level (child , prefix )
177- component_list .extend (component )
179+ component_from_list = self .process_level (child , prefix )
180+ component_list .extend (component_from_list )
178181 elif isinstance (level , str ):
179182 component = self .create_component_from_string ("." .join (prefix + [level ]))
180183 component_list .append (component )
@@ -206,7 +209,7 @@ def create_component_from_string(self, component_string: str) -> Component:
206209 component = self .import_and_instantiate_component (component_path , args )
207210 return component
208211
209- def prep_component (self , component_string : str ) -> tuple [str , tuple ]:
212+ def prep_component (self , component_string : str ) -> tuple [str , tuple [ str , ...] ]:
210213 """Transform component description string into a tuple of component paths
211214 and required arguments.
212215
@@ -224,14 +227,14 @@ def prep_component(self, component_string: str) -> tuple[str, tuple]:
224227 return path , cleaned_args
225228
226229 @staticmethod
227- def _clean_args (args : list , path : str ) -> tuple :
230+ def _clean_args (args : list [ str ] , path : str ) -> tuple [ str , ...] :
228231 """Transform component arguments into a tuple, validating that each argument
229232 is a string.
230233
231234 Parameters
232235 ----------
233236 args
234- List of arguments to the component specified at ``path``.
237+ Tuple of arguments to the component specified at ``path``.
235238 path
236239 Path representing the component for which arguments are being cleaned.
237240
@@ -255,7 +258,9 @@ def _clean_args(args: list, path: str) -> tuple:
255258 return tuple (out )
256259
257260 @staticmethod
258- def import_and_instantiate_component (component_path : str , args : tuple [str ]) -> Component :
261+ def import_and_instantiate_component (
262+ component_path : str , args : tuple [str , ...]
263+ ) -> Component :
259264 """Transform a tuple representing a Component into an actual instantiated
260265 component object.
261266
@@ -271,4 +276,9 @@ def import_and_instantiate_component(component_path: str, args: tuple[str]) -> C
271276 -------
272277 An instantiated component object.
273278 """
274- return import_by_path (component_path )(* args )
279+ component = import_by_path (component_path )(* args )
280+ if not isinstance (component , Component ):
281+ raise ImportError (
282+ f"Attempted to import f{ component_path } , which is not a component."
283+ )
284+ return component
0 commit comments