|
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") |