cengal.file_system.file_settings_manager.config_manager.versions.v_0.config_manager
1#!/usr/bin/env python 2# coding=utf-8 3 4# Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space> 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18import os.path 19from os.path import expanduser 20from cengal.text_processing.help_tools import get_text_in_brackets 21import copy 22from enum import Enum 23from contextlib import contextmanager 24 25""" 26Module Docstring 27Docstrings: http://www.python.org/dev/peps/pep-0257/ 28""" 29 30__author__ = "ButenkoMS <gtalk@butenkoms.space>" 31__copyright__ = "Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>" 32__credits__ = ["ButenkoMS <gtalk@butenkoms.space>", ] 33__license__ = "Apache License, Version 2.0" 34__version__ = "4.4.1" 35__maintainer__ = "ButenkoMS <gtalk@butenkoms.space>" 36__email__ = "gtalk@butenkoms.space" 37# __status__ = "Prototype" 38__status__ = "Development" 39# __status__ = "Production" 40 41 42# RESERVED_SYMBOLS__NAME = {'"', '='} 43RESERVED_SYMBOLS__NAME = {'"'} 44RESERVED_SYMBOLS__DATA = {'\n'} 45RESERVED_SYMBOLS = RESERVED_SYMBOLS__NAME | RESERVED_SYMBOLS__DATA 46 47 48class WrongSymbolInThePropertyName(Exception): 49 pass 50 51 52class WrongSymbolInThePropertyData(Exception): 53 pass 54 55 56class Errors(Enum): 57 ok = 0 58 file_not_found = 1 59 60 61class ConfigManager: 62 def __init__(self, app_tags, base_dir=None, default_content=None, immediate_save=True): 63 """ 64 :param app_tags: ['Cute LLC', 'My App Name', 'configs for a parser'] 65 :param base_dir: User's Home if None 66 :param immediate_save: 67 :return: 68 """ 69 self.app_tags = app_tags 70 self.base_dir = base_dir or os.path.expanduser("~") 71 self.config_path = os.path.join(self.base_dir, *self.app_tags) 72 if not os.path.isdir(self.config_path): 73 os.makedirs(self.config_path) 74 self.default_content = default_content 75 self.immediate_save = immediate_save 76 77 self.files = dict() 78 79 self.predefined_file_name = None 80 81 @staticmethod 82 def _filter_out_disallowed_symbols_from_property_name(property_name): 83 for disallowed in RESERVED_SYMBOLS__NAME: 84 property_name = property_name.replace(disallowed, '') 85 return property_name 86 87 def get_full_dir_path(self): 88 return copy.copy(self.config_path) 89 90 def load(self, file_name, force=None): 91 if self.predefined_file_name is not None: 92 force = file_name 93 file_name = self.predefined_file_name 94 # elif force is None: 95 # raise Exception('"force" property must be provided!') 96 97 if force is None: 98 force = False 99 100 result = Errors.ok 101 file_content = self.files.get(file_name) 102 if (file_content is None) or force: 103 # file_content = None 104 file_path = os.path.join(self.config_path, file_name) 105 file_lines = list() 106 try: 107 with open(file_path, 'r') as file: 108 file_lines = file.readlines() 109 except FileNotFoundError as ex: 110 result = Errors.file_not_found 111 file_content = dict() 112 for another_line in file_lines: 113 another_line += '\n' 114 key = get_text_in_brackets(another_line, '"', '"').strip() 115 data = get_text_in_brackets(another_line, '=', '\n').strip() 116 file_content[key] = data 117 if file_name in self.default_content: 118 file_default_content = self.default_content[file_name] 119 for key, data in file_default_content.items(): 120 if key not in file_content: 121 file_content[key] = data 122 self.files[file_name] = file_content 123 self.save(file_name) 124 return result 125 126 def save(self, file_name=None): 127 if self.predefined_file_name is not None: 128 file_name = self.predefined_file_name 129 elif file_name is None: 130 raise Exception('"file_name" property must be provided!') 131 132 file_content = self.files.get(file_name) 133 if file_content is not None: 134 lines = list() 135 for key, data in file_content.items(): 136 another_line = '"{}" = {}'.format(key, data) 137 lines.append(another_line) 138 new_file_content = '\n'.join(lines) 139 file_path = os.path.join(self.config_path, file_name) 140 with open(file_path, 'w') as file: 141 file.write(new_file_content) 142 143 def get_property(self, file_name, property_name=None): 144 if self.predefined_file_name is not None: 145 property_name = file_name 146 file_name = self.predefined_file_name 147 elif property_name is None: 148 raise Exception('"property_name" property must be provided!') 149 150 result = None 151 self.load(file_name) 152 file_content = self.files[file_name] 153 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 154 result = copy.deepcopy(file_content.get(property_name)) 155 return result 156 157 def set_property(self, file_name, property_name, data=None): 158 """ 159 :param file_name: 160 :param property_name: 161 :param data: set to None to remove property from config 162 :return: 163 """ 164 165 if self.predefined_file_name is not None: 166 data = property_name 167 property_name = file_name 168 file_name = self.predefined_file_name 169 elif data is None: 170 raise Exception('"data" property must be provided!') 171 172 data = copy.deepcopy(data) 173 self.load(file_name) 174 file_content = self.files[file_name] 175 if data is None: 176 if property_name in file_content: 177 del file_content[property_name] 178 else: 179 for disallowed in RESERVED_SYMBOLS__DATA: 180 if disallowed in data: 181 raise WrongSymbolInThePropertyData(data) 182 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 183 file_content[property_name] = copy.copy(data) 184 if self.immediate_save: 185 self.save(file_name) 186 187 def remove_property(self, file_name, property_name=None): 188 if self.predefined_file_name is not None: 189 property_name = file_name 190 file_name = self.predefined_file_name 191 elif property_name is None: 192 raise Exception('"property_name" property must be provided!') 193 194 self.set_property(file_name, property_name, None) 195 196 197@contextmanager 198def conf_file_name(config_manager: ConfigManager, file_name: str): 199 original_file_name = config_manager.predefined_file_name 200 config_manager.predefined_file_name = file_name 201 try: 202 yield config_manager 203 finally: 204 config_manager.predefined_file_name = original_file_name
RESERVED_SYMBOLS__NAME =
{'"'}
RESERVED_SYMBOLS__DATA =
{'\n'}
RESERVED_SYMBOLS =
{'\n', '"'}
class
WrongSymbolInThePropertyName(builtins.Exception):
Common base class for all non-exit exceptions.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
class
WrongSymbolInThePropertyData(builtins.Exception):
Common base class for all non-exit exceptions.
Inherited Members
- builtins.Exception
- Exception
- builtins.BaseException
- with_traceback
- args
class
Errors(enum.Enum):
An enumeration.
ok =
<Errors.ok: 0>
file_not_found =
<Errors.file_not_found: 1>
Inherited Members
- enum.Enum
- name
- value
class
ConfigManager:
62class ConfigManager: 63 def __init__(self, app_tags, base_dir=None, default_content=None, immediate_save=True): 64 """ 65 :param app_tags: ['Cute LLC', 'My App Name', 'configs for a parser'] 66 :param base_dir: User's Home if None 67 :param immediate_save: 68 :return: 69 """ 70 self.app_tags = app_tags 71 self.base_dir = base_dir or os.path.expanduser("~") 72 self.config_path = os.path.join(self.base_dir, *self.app_tags) 73 if not os.path.isdir(self.config_path): 74 os.makedirs(self.config_path) 75 self.default_content = default_content 76 self.immediate_save = immediate_save 77 78 self.files = dict() 79 80 self.predefined_file_name = None 81 82 @staticmethod 83 def _filter_out_disallowed_symbols_from_property_name(property_name): 84 for disallowed in RESERVED_SYMBOLS__NAME: 85 property_name = property_name.replace(disallowed, '') 86 return property_name 87 88 def get_full_dir_path(self): 89 return copy.copy(self.config_path) 90 91 def load(self, file_name, force=None): 92 if self.predefined_file_name is not None: 93 force = file_name 94 file_name = self.predefined_file_name 95 # elif force is None: 96 # raise Exception('"force" property must be provided!') 97 98 if force is None: 99 force = False 100 101 result = Errors.ok 102 file_content = self.files.get(file_name) 103 if (file_content is None) or force: 104 # file_content = None 105 file_path = os.path.join(self.config_path, file_name) 106 file_lines = list() 107 try: 108 with open(file_path, 'r') as file: 109 file_lines = file.readlines() 110 except FileNotFoundError as ex: 111 result = Errors.file_not_found 112 file_content = dict() 113 for another_line in file_lines: 114 another_line += '\n' 115 key = get_text_in_brackets(another_line, '"', '"').strip() 116 data = get_text_in_brackets(another_line, '=', '\n').strip() 117 file_content[key] = data 118 if file_name in self.default_content: 119 file_default_content = self.default_content[file_name] 120 for key, data in file_default_content.items(): 121 if key not in file_content: 122 file_content[key] = data 123 self.files[file_name] = file_content 124 self.save(file_name) 125 return result 126 127 def save(self, file_name=None): 128 if self.predefined_file_name is not None: 129 file_name = self.predefined_file_name 130 elif file_name is None: 131 raise Exception('"file_name" property must be provided!') 132 133 file_content = self.files.get(file_name) 134 if file_content is not None: 135 lines = list() 136 for key, data in file_content.items(): 137 another_line = '"{}" = {}'.format(key, data) 138 lines.append(another_line) 139 new_file_content = '\n'.join(lines) 140 file_path = os.path.join(self.config_path, file_name) 141 with open(file_path, 'w') as file: 142 file.write(new_file_content) 143 144 def get_property(self, file_name, property_name=None): 145 if self.predefined_file_name is not None: 146 property_name = file_name 147 file_name = self.predefined_file_name 148 elif property_name is None: 149 raise Exception('"property_name" property must be provided!') 150 151 result = None 152 self.load(file_name) 153 file_content = self.files[file_name] 154 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 155 result = copy.deepcopy(file_content.get(property_name)) 156 return result 157 158 def set_property(self, file_name, property_name, data=None): 159 """ 160 :param file_name: 161 :param property_name: 162 :param data: set to None to remove property from config 163 :return: 164 """ 165 166 if self.predefined_file_name is not None: 167 data = property_name 168 property_name = file_name 169 file_name = self.predefined_file_name 170 elif data is None: 171 raise Exception('"data" property must be provided!') 172 173 data = copy.deepcopy(data) 174 self.load(file_name) 175 file_content = self.files[file_name] 176 if data is None: 177 if property_name in file_content: 178 del file_content[property_name] 179 else: 180 for disallowed in RESERVED_SYMBOLS__DATA: 181 if disallowed in data: 182 raise WrongSymbolInThePropertyData(data) 183 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 184 file_content[property_name] = copy.copy(data) 185 if self.immediate_save: 186 self.save(file_name) 187 188 def remove_property(self, file_name, property_name=None): 189 if self.predefined_file_name is not None: 190 property_name = file_name 191 file_name = self.predefined_file_name 192 elif property_name is None: 193 raise Exception('"property_name" property must be provided!') 194 195 self.set_property(file_name, property_name, None)
ConfigManager(app_tags, base_dir=None, default_content=None, immediate_save=True)
63 def __init__(self, app_tags, base_dir=None, default_content=None, immediate_save=True): 64 """ 65 :param app_tags: ['Cute LLC', 'My App Name', 'configs for a parser'] 66 :param base_dir: User's Home if None 67 :param immediate_save: 68 :return: 69 """ 70 self.app_tags = app_tags 71 self.base_dir = base_dir or os.path.expanduser("~") 72 self.config_path = os.path.join(self.base_dir, *self.app_tags) 73 if not os.path.isdir(self.config_path): 74 os.makedirs(self.config_path) 75 self.default_content = default_content 76 self.immediate_save = immediate_save 77 78 self.files = dict() 79 80 self.predefined_file_name = None
:param app_tags: ['Cute LLC', 'My App Name', 'configs for a parser'] :param base_dir: User's Home if None :param immediate_save: :return:
def
load(self, file_name, force=None):
91 def load(self, file_name, force=None): 92 if self.predefined_file_name is not None: 93 force = file_name 94 file_name = self.predefined_file_name 95 # elif force is None: 96 # raise Exception('"force" property must be provided!') 97 98 if force is None: 99 force = False 100 101 result = Errors.ok 102 file_content = self.files.get(file_name) 103 if (file_content is None) or force: 104 # file_content = None 105 file_path = os.path.join(self.config_path, file_name) 106 file_lines = list() 107 try: 108 with open(file_path, 'r') as file: 109 file_lines = file.readlines() 110 except FileNotFoundError as ex: 111 result = Errors.file_not_found 112 file_content = dict() 113 for another_line in file_lines: 114 another_line += '\n' 115 key = get_text_in_brackets(another_line, '"', '"').strip() 116 data = get_text_in_brackets(another_line, '=', '\n').strip() 117 file_content[key] = data 118 if file_name in self.default_content: 119 file_default_content = self.default_content[file_name] 120 for key, data in file_default_content.items(): 121 if key not in file_content: 122 file_content[key] = data 123 self.files[file_name] = file_content 124 self.save(file_name) 125 return result
def
save(self, file_name=None):
127 def save(self, file_name=None): 128 if self.predefined_file_name is not None: 129 file_name = self.predefined_file_name 130 elif file_name is None: 131 raise Exception('"file_name" property must be provided!') 132 133 file_content = self.files.get(file_name) 134 if file_content is not None: 135 lines = list() 136 for key, data in file_content.items(): 137 another_line = '"{}" = {}'.format(key, data) 138 lines.append(another_line) 139 new_file_content = '\n'.join(lines) 140 file_path = os.path.join(self.config_path, file_name) 141 with open(file_path, 'w') as file: 142 file.write(new_file_content)
def
get_property(self, file_name, property_name=None):
144 def get_property(self, file_name, property_name=None): 145 if self.predefined_file_name is not None: 146 property_name = file_name 147 file_name = self.predefined_file_name 148 elif property_name is None: 149 raise Exception('"property_name" property must be provided!') 150 151 result = None 152 self.load(file_name) 153 file_content = self.files[file_name] 154 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 155 result = copy.deepcopy(file_content.get(property_name)) 156 return result
def
set_property(self, file_name, property_name, data=None):
158 def set_property(self, file_name, property_name, data=None): 159 """ 160 :param file_name: 161 :param property_name: 162 :param data: set to None to remove property from config 163 :return: 164 """ 165 166 if self.predefined_file_name is not None: 167 data = property_name 168 property_name = file_name 169 file_name = self.predefined_file_name 170 elif data is None: 171 raise Exception('"data" property must be provided!') 172 173 data = copy.deepcopy(data) 174 self.load(file_name) 175 file_content = self.files[file_name] 176 if data is None: 177 if property_name in file_content: 178 del file_content[property_name] 179 else: 180 for disallowed in RESERVED_SYMBOLS__DATA: 181 if disallowed in data: 182 raise WrongSymbolInThePropertyData(data) 183 property_name = self._filter_out_disallowed_symbols_from_property_name(property_name) 184 file_content[property_name] = copy.copy(data) 185 if self.immediate_save: 186 self.save(file_name)
:param file_name: :param property_name: :param data: set to None to remove property from config :return:
def
remove_property(self, file_name, property_name=None):
188 def remove_property(self, file_name, property_name=None): 189 if self.predefined_file_name is not None: 190 property_name = file_name 191 file_name = self.predefined_file_name 192 elif property_name is None: 193 raise Exception('"property_name" property must be provided!') 194 195 self.set_property(file_name, property_name, None)
198@contextmanager 199def conf_file_name(config_manager: ConfigManager, file_name: str): 200 original_file_name = config_manager.predefined_file_name 201 config_manager.predefined_file_name = file_name 202 try: 203 yield config_manager 204 finally: 205 config_manager.predefined_file_name = original_file_name