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):
49class WrongSymbolInThePropertyName(Exception):
50    pass

Common base class for all non-exit exceptions.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
class WrongSymbolInThePropertyData(builtins.Exception):
53class WrongSymbolInThePropertyData(Exception):
54    pass

Common base class for all non-exit exceptions.

Inherited Members
builtins.Exception
Exception
builtins.BaseException
with_traceback
args
class Errors(enum.Enum):
57class Errors(Enum):
58    ok = 0
59    file_not_found = 1

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:

app_tags
base_dir
config_path
default_content
immediate_save
files
predefined_file_name
def get_full_dir_path(self):
88    def get_full_dir_path(self):
89        return copy.copy(self.config_path)
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)
@contextmanager
def conf_file_name( config_manager: ConfigManager, file_name: str):
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