From b15ba91d1a9c431410fc4d3fc7d1a6082cc63e7e Mon Sep 17 00:00:00 2001 From: nitin-ebi <79518737+nitin-ebi@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:07:38 +0100 Subject: [PATCH] EVA-3414 add Writable config script (#49) added writable config --- ebi_eva_common_pyutils/config.py | 77 ++++++++++++++++++++++++++++++++ tests/common/test_config.py | 1 - 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/ebi_eva_common_pyutils/config.py b/ebi_eva_common_pyutils/config.py index 6d383de..6702b20 100644 --- a/ebi_eva_common_pyutils/config.py +++ b/ebi_eva_common_pyutils/config.py @@ -73,3 +73,80 @@ def __contains__(self, item): """ Provides a singleton that can be used as a central place for configuration. """ + + + + +class WritableConfig(Configuration): + """Configuration object that allows writes to the config file""" + + def __init__(self, *search_path, version=None): + super().__init__(*search_path) + self.version = version + + def load_config_file(self, *search_path): + try: + super().load_config_file(*search_path) + except FileNotFoundError: + # expected if it's the first time we are creating the config file + # In that case the first search path is set to be the config files + self.config_file = search_path[0] + pass + + def backup(self): + """ + Rename the config file by adding a '.1' at the end. If the '.1' file exists it move it to a '.2' and so on. + """ + if os.path.isfile(self.config_file): + file_name = self.config_file + suffix = 1 + backup_name = f'{file_name}.{suffix}' + while os.path.exists(backup_name): + suffix += 1 + backup_name = f'{file_name}.{suffix}' + + for i in range(suffix, 1, -1): + os.rename(f'{file_name}.{i - 1}', f'{file_name}.{i}') + os.rename(file_name, file_name + '.1') + + def write(self): + if self.config_file and self.content and os.path.isdir(os.path.dirname(self.config_file)): + with open(self.config_file, 'w') as open_config: + yaml.safe_dump(self.content, open_config) + + def set(self, *path, value): + self._set_version() + top_level = self.content + for p in path[:-1]: + if p not in top_level: + top_level[p] = {} + top_level = top_level[p] + top_level[path[-1]] = value + + def pop(self, *path, default=None): + """Recursive dictionary pop with default""" + top_level = self.content + for p in path[:-1]: + if p not in top_level: + return default + top_level = top_level[p] + return top_level.pop(path[-1], default) + + def is_empty(self): + return not self.content + + def clear(self): + self.content = {} + + def _set_version(self): + # If we're starting to fill in an empty config, set the version if available + if self.is_empty() and self.version: + self.content['version'] = self.version + + def __contains__(self, item): + return item in self.content + + def __setitem__(self, item, value): + """Allow dict-style write access, e.g. config['this']='that'.""" + self._set_version() + self.content[item] = value \ No newline at end of file diff --git a/tests/common/test_config.py b/tests/common/test_config.py index d7cc6ae..fe7b63c 100644 --- a/tests/common/test_config.py +++ b/tests/common/test_config.py @@ -1,5 +1,4 @@ import os -from os import environ from os.path import join import pytest