Switch to unified view

a b/ReadersWriters/PyConfigParser.py
1
#!/usr/bin/env python
2
# -*- coding: UTF-8 -*-
3
#
4
# Copyright 2017 University of Westminster. All Rights Reserved.
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
# ==============================================================================
18
""" It is an interface for reading and writing configuration file using 'configParser'.
19
"""
20
21
from typing import Dict, List
22
import sys
23
import configparser
24
import os
25
import logging
26
27
__author__ = "Mohsen Mesgarpour"
28
__copyright__ = "Copyright 2016, https://github.com/mesgarpour"
29
__credits__ = ["Mohsen Mesgarpour"]
30
__license__ = "GPL"
31
__version__ = "1.1"
32
__maintainer__ = "Mohsen Mesgarpour"
33
__email__ = "mohsen.mesgarpour@gmail.com"
34
__status__ = "Release"
35
36
37
class PyConfigParser:
38
    def __init__(self,
39
                 path: str,
40
                 app_name: str,
41
                 ext: str= ""):
42
        """Initialise the objects and constants.
43
        :param path: the file path of the configuration file.
44
        :param app_name: the application name, which will be used as the log file name.
45
        :param ext: the extension of the configuration file (default: 'ini').
46
        """
47
        self.__logger = logging.getLogger(app_name)
48
        self.__logger.debug(__name__)
49
        self.__path = os.path.abspath(path + "." + ext)
50
        self.__config = None
51
        self.refresh()
52
53
    def refresh(self):
54
        """Refresh the configuration file reader and Reset the constants.
55
        """
56
        self.__logger.debug("Refresh the Configuration file reader.")
57
        try:
58
            if not (os.path.exists(self.__path) and os.path.isfile(self.__path)):
59
                self.__logger.warning(__name__ + " - Configuration file does not exist: \n" + self.__path)
60
                self.reset()
61
            else:
62
                self.__config = configparser.ConfigParser()
63
                self.__config.optionxform = str  # make option case-sensitive
64
                self.__config.read(self.__path)
65
        except():
66
            self.__logger.error(__name__ + " - Error while opening a file: \n" + self.__path)
67
            sys.exit()
68
69
    def reset(self):
70
        """Reset the configuration file reader.
71
        """
72
        self.__logger.debug("Reset the Configuration file.")
73
        try:
74
            open(self.__path, 'w').close()
75
        except():
76
            self.__logger.error(__name__ + " - Could not create the config file: \n" + self.__path)
77
            sys.exit()
78
79
    def sections(self) -> List:
80
        """Get sections in the configuration file.
81
        :return: section names.
82
        """
83
        self.__logger.debug("Get Sections of the Configuration file.")
84
        return self.__config.sections()
85
86
    def subsections(self,
87
                    section: str) -> List:
88
        """Get sub-sections under the specified section name.
89
        :param section: the section name.
90
        :return: the sub-section names
91
        """
92
        self.__logger.debug("Get Subsections of the Configuration file.")
93
        return self.__config.items(section)
94
95
    def option(self,
96
               section: str,
97
               key: str) -> str:
98
        """Get the option for the specified key and section.
99
        :param section: a section in the configuration.
100
        :param key: a key of a section in the configuration.
101
        :return: the value (option) of the key.
102
        """
103
        self.__logger.debug("Read an Option in the Configuration file.")
104
        try:
105
            value = self.__config.get(section, key)
106
        except configparser.NoSectionError:
107
            self.__logger.error(__name__ + " - Invalid Section: [Section: " +
108
                                str(section) + "; Key:" + str(key) + "]")
109
            sys.exit()
110
        except configparser.NoOptionError:
111
            self.__logger.error(__name__ + " - Invalid Option: [Section: " +
112
                                str(section) + "; Key:" + str(key) + "]")
113
            sys.exit()
114
        except():
115
            self.__logger.error(__name__ + " - Invalid Configuration: [Section: " +
116
                                str(section) + "; Key:" + str(key) + "]")
117
            sys.exit()
118
        return value
119
120
    def options(self,
121
                section: str,
122
                keys: List=None) -> Dict:
123
        """Get the options for all or the specified keys in the section.
124
        :param section: a section in the configuration.
125
        :param keys: keys of a section (option) in the configuration.
126
        :return: the values (options) of the keys.
127
        """
128
        self.__logger.debug("Read Section Options in the Configuration file.")
129
        values = []
130
        try:
131
            if keys is None:
132
                values = dict(self.subsections(section))
133
            else:
134
                for k in keys:
135
                    values.append(self.__config.get(section, k))
136
        except configparser.NoSectionError:
137
            self.__logger.error(__name__ + " - Invalid Section: " +
138
                                "[Section: " + str(section) + "]")
139
            sys.exit()
140
        except():
141
            self.__logger.error(__name__ + " - Invalid Configuration.")
142
            sys.exit()
143
        return values
144
145
    def read_dict(self,
146
                  section: str=None) -> Dict:
147
        """Read the configuration and save into dictionary.
148
        :param section: the section name
149
        :return: the read configuration file
150
        """
151
        self.__logger.debug("Read into Dictionary.")
152
        dic = dict()
153
        sections = self.sections()
154
155
        if section is None:
156
            for section in sections:
157
                dic[section] = self.options(section)
158
                for k, v in dic[section].items():
159
                    dic[section][k] = str(v).split(',')
160
        else:
161
            if section in set(sections):
162
                dic = self.options(section)
163
                for k, v in dic.items():
164
                    dic[k] = str(v).split(',')
165
        return dic
166
167
    def write_dict(self,
168
                   dic: Dict,
169
                   section: str,
170
                   append: str=False):
171
        """Write from the inputted dictionary into the configuration file.
172
        :param dic: the inputted dictionary to write into the configuration file.
173
        :param section: the section name.
174
        :param append: indicates if the write appends to any existing configuration file.
175
        """
176
        self.__logger.debug("Write from Dictionary.")
177
        # set
178
        config = configparser.RawConfigParser()
179
        config.optionxform = str  # make option is case-sensitive
180
        config.add_section(section)
181
        keys = list(dic.keys())
182
183
        for key in keys:
184
            if isinstance(dic[key], list):
185
                config.set(section, key, ','.join(dic[key]))
186
            else:
187
                config.set(section, key, dic[key])
188
189
        # write
190
        if append is False:
191
            with open(self.__path, 'w') as file:
192
                config.write(file)
193
        else:
194
            with open(self.__path, 'a') as file:
195
                config.write(file)
196
197
    def write_option(self,
198
                     section: str,
199
                     option: str,
200
                     value: str):
201
        """Remove then add the specified option to the configuration file.
202
        :param section: the section name.
203
        :param option: the option name to be removed then added with new value.
204
        :param value: the option value to be removed then added with new value.
205
        """
206
        self.__logger.debug("Write an Option into the Configuration file.")
207
        self.__remove_option(section, option)
208
        self.__add_option(section, option, value)
209
210
    def __remove_option(self,
211
                        section: str,
212
                        option: str):
213
        """Remove an option from the configuration file.
214
        :param section: the section name.
215
        :param option: the option name to remove.
216
        """
217
        self.__logger.debug("Remove an Option from the Configuration file.")
218
        section = "[" + section + "]"
219
        option += "="
220
        match = False
221
222
        # read
223
        with open(self.__path, 'r') as file:
224
            lines = file.readlines()
225
226
        # delete
227
        with open(self.__path, 'w') as file:
228
            # remove
229
            for line in lines:
230
                if line.strip().startswith(section):
231
                    match = True
232
                if match is True and line.replace(' ', '').startswith(option):
233
                    match = False
234
                    continue
235
                file.write(line)
236
237
    def __add_option(self,
238
                     section: str,
239
                     option: str,
240
                     value: str):
241
        """Add an option to the configuration file.
242
        :param section: the section name.
243
        :param option: the option name to be written.
244
        :param value: the option value to be written.
245
        """
246
        self.__logger.debug("Add an Option to the Configuration file.")
247
        section = "[" + section + "]"
248
        match = False
249
250
        # read
251
        with open(self.__path, 'r') as file:
252
            lines = file.readlines()
253
254
        # append
255
        with open(self.__path, 'w') as file:
256
            for line in lines:
257
                if line.strip().startswith(section):
258
                    file.write(line)
259
                    file.write(option + " = " + ",".join(value) + "\n")
260
                    match = True
261
                else:
262
                    file.write(line)
263
            if match is False:
264
                file.write("\n" + section + "\n" + option + " = " + ",".join(value) + "\n")