diff --git a/libbot/__main__.py b/libbot/__main__.py index 72a72b4..9d95b33 100644 --- a/libbot/__main__.py +++ b/libbot/__main__.py @@ -4,6 +4,8 @@ from typing import Any, Union import aiofiles from ujson import dumps, loads +from libbot.sync import nested_set + async def json_read(path: Union[str, Path]) -> Any: """Read contents of a JSON file @@ -79,14 +81,7 @@ async def config_set( * *path (`str`): Path to the key of the target * config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"` """ - this_dict = await json_read(config_file) - string = "this_dict" - for arg in path: - string += f'["{arg}"]' - if type(value) in [str]: - string += f'["{key}"] = "{value}"' - else: - string += f'["{key}"] = {value}' - exec(string) - await json_write(this_dict, config_file) + await json_write( + nested_set(await json_read(config_file), value, *(*path, key)), config_file + ) return diff --git a/libbot/sync/__init__.py b/libbot/sync/__init__.py index 3fbfbeb..5b89d75 100644 --- a/libbot/sync/__init__.py +++ b/libbot/sync/__init__.py @@ -29,6 +29,31 @@ def json_write(data: Any, path: Union[str, Path]) -> None: f.write(dumps(data, ensure_ascii=False, escape_forward_slashes=False, indent=4)) +def nested_set(target: dict, value: Any, *path: str, create_missing=True) -> dict: + """Set the key by its path to the value + + ### Args: + * target (`dict`): Dictionary to perform modifications on + * value (`Any`): Any data + * *path (`str`): Path to the key of the target + * create_missing (`bool`, *optional*): Create keys on the way if they're missing. Defaults to `True` + + ### Returns: + * `dict`: Changed dictionary + """ + d = target + for key in path[:-1]: + if key in d: + d = d[key] + elif create_missing: + d = d.setdefault(key, {}) + else: + return target + if path[-1] in d or create_missing: + d[path[-1]] = value + return target + + def config_get( key: str, *path: str, config_file: Union[str, Path] = "config.json" ) -> Any: @@ -78,14 +103,5 @@ def config_set( * *path (`str`): Path to the key of the target * config_file (`Union[str, Path]`, *optional*): Path-like object or path as a string of a location of the config file. Defaults to `"config.json"` """ - this_dict = json_read(config_file) - string = "this_dict" - for arg in path: - string += f'["{arg}"]' - if type(value) in [str]: - string += f'["{key}"] = "{value}"' - else: - string += f'["{key}"] = {value}' - exec(string) - json_write(this_dict, config_file) + json_write(nested_set(json_read(config_file), value, *(*path, key)), config_file) return