def _update_obj( obj: JsonType, key: str, value: JsonType, params: Dict[str, Any], defs: Dict[str, Def], ) -> None: if not isinstance(obj, dict): raise YATLSyntaxError(f"Cannot add field {key} to non-object") interpolated_key = render_interpolation(key, params) obj[interpolated_key] = render_from_obj(value, params, defs)
def _parse_filename(filename: JsonType, params: Dict[str, Any], load_type: str) -> str: if not isinstance(filename, str): raise YATLSyntaxError( f"{load_type} must be given a string or list of strings: {filename}" ) filename = render_interpolation(filename, params) if not isinstance(filename, str): raise YATLSyntaxError( f"{load_type} directive must be given a string or list of strings: {filename}" ) return filename
def test_render_interpolation(): assert (render_interpolation(".(foo) and .(bar)", { "foo": "abc", "bar": "xyz" }) == "abc and xyz")
def test_render_interpolation_dot(): assert render_interpolation(".", {}) == "."
def test_render_interpolation_incomplete(): with pytest.raises(YATLSyntaxError): render_interpolation(".(", {})
def test_render_interpolation_escape(): assert render_interpolation(r"\.(foo)", {"foo": "abc"}) == r"\.(foo)"
def render_from_obj( # noqa: C901 obj: JsonType, params: Dict[str, Any], defs: Dict[str, Def] ) -> JsonType: if isinstance(obj, dict): defaults_obj: JsonType = None rendered_obj: JsonType = {} last_if = None for key, value in obj.items(): if isinstance(key, str) and key.startswith("."): # Note, elif and else require Python 3.7+ or a custom YAML loader to preserve key order. if _is_if(key): rendered_obj, last_if = _render_if( key, value, params, defs, rendered_obj ) elif _is_elif(key): if last_if is None: raise YATLSyntaxError(f"elif does not follow if: {key}") if last_if is False: rendered_obj, last_if = _render_if( key, value, params, defs, rendered_obj ) elif key == ".else": if last_if is None: raise YATLSyntaxError(f"else does not follow if: {key}") if last_if is False: rendered_obj = _render_else( key, value, params, defs, rendered_obj ) else: last_if = None if key == ".load": rendered_obj = _render_load(value, params, defs, rendered_obj) elif key == ".load_defaults_from": defaults_obj = _load_defaults(value, params, defs) elif _is_for(key): rendered_obj = _render_for( key, value, params, defs, rendered_obj ) elif _is_def(key): _store_def(key, value, defs) elif _is_use(key): rendered_obj = _render_use( key, value, params, defs, rendered_obj ) else: _update_obj(rendered_obj, key, value, params, defs) else: last_if = None _update_obj(rendered_obj, key, value, params, defs) if defaults_obj: rendered_obj = _deep_merge_dicts(defaults_obj, rendered_obj) # type: ignore return rendered_obj elif isinstance(obj, list): rendered_obj = [] for elem in obj: rendered_elem = render_from_obj(elem, params, defs) if _can_extend_list(elem, rendered_elem): # Convert rendered_elem to [] if it's {} rendered_obj.extend(rendered_elem or []) # type: ignore else: rendered_obj.append(rendered_elem) return rendered_obj elif isinstance(obj, str): return render_interpolation(obj, params) else: return obj