Switch to side-by-side view

--- a
+++ b/ReadersWriters/PyConfigParser.py
@@ -0,0 +1,264 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+#
+# Copyright 2017 University of Westminster. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+""" It is an interface for reading and writing configuration file using 'configParser'.
+"""
+
+from typing import Dict, List
+import sys
+import configparser
+import os
+import logging
+
+__author__ = "Mohsen Mesgarpour"
+__copyright__ = "Copyright 2016, https://github.com/mesgarpour"
+__credits__ = ["Mohsen Mesgarpour"]
+__license__ = "GPL"
+__version__ = "1.1"
+__maintainer__ = "Mohsen Mesgarpour"
+__email__ = "mohsen.mesgarpour@gmail.com"
+__status__ = "Release"
+
+
+class PyConfigParser:
+    def __init__(self,
+                 path: str,
+                 app_name: str,
+                 ext: str= ""):
+        """Initialise the objects and constants.
+        :param path: the file path of the configuration file.
+        :param app_name: the application name, which will be used as the log file name.
+        :param ext: the extension of the configuration file (default: 'ini').
+        """
+        self.__logger = logging.getLogger(app_name)
+        self.__logger.debug(__name__)
+        self.__path = os.path.abspath(path + "." + ext)
+        self.__config = None
+        self.refresh()
+
+    def refresh(self):
+        """Refresh the configuration file reader and Reset the constants.
+        """
+        self.__logger.debug("Refresh the Configuration file reader.")
+        try:
+            if not (os.path.exists(self.__path) and os.path.isfile(self.__path)):
+                self.__logger.warning(__name__ + " - Configuration file does not exist: \n" + self.__path)
+                self.reset()
+            else:
+                self.__config = configparser.ConfigParser()
+                self.__config.optionxform = str  # make option case-sensitive
+                self.__config.read(self.__path)
+        except():
+            self.__logger.error(__name__ + " - Error while opening a file: \n" + self.__path)
+            sys.exit()
+
+    def reset(self):
+        """Reset the configuration file reader.
+        """
+        self.__logger.debug("Reset the Configuration file.")
+        try:
+            open(self.__path, 'w').close()
+        except():
+            self.__logger.error(__name__ + " - Could not create the config file: \n" + self.__path)
+            sys.exit()
+
+    def sections(self) -> List:
+        """Get sections in the configuration file.
+        :return: section names.
+        """
+        self.__logger.debug("Get Sections of the Configuration file.")
+        return self.__config.sections()
+
+    def subsections(self,
+                    section: str) -> List:
+        """Get sub-sections under the specified section name.
+        :param section: the section name.
+        :return: the sub-section names
+        """
+        self.__logger.debug("Get Subsections of the Configuration file.")
+        return self.__config.items(section)
+
+    def option(self,
+               section: str,
+               key: str) -> str:
+        """Get the option for the specified key and section.
+        :param section: a section in the configuration.
+        :param key: a key of a section in the configuration.
+        :return: the value (option) of the key.
+        """
+        self.__logger.debug("Read an Option in the Configuration file.")
+        try:
+            value = self.__config.get(section, key)
+        except configparser.NoSectionError:
+            self.__logger.error(__name__ + " - Invalid Section: [Section: " +
+                                str(section) + "; Key:" + str(key) + "]")
+            sys.exit()
+        except configparser.NoOptionError:
+            self.__logger.error(__name__ + " - Invalid Option: [Section: " +
+                                str(section) + "; Key:" + str(key) + "]")
+            sys.exit()
+        except():
+            self.__logger.error(__name__ + " - Invalid Configuration: [Section: " +
+                                str(section) + "; Key:" + str(key) + "]")
+            sys.exit()
+        return value
+
+    def options(self,
+                section: str,
+                keys: List=None) -> Dict:
+        """Get the options for all or the specified keys in the section.
+        :param section: a section in the configuration.
+        :param keys: keys of a section (option) in the configuration.
+        :return: the values (options) of the keys.
+        """
+        self.__logger.debug("Read Section Options in the Configuration file.")
+        values = []
+        try:
+            if keys is None:
+                values = dict(self.subsections(section))
+            else:
+                for k in keys:
+                    values.append(self.__config.get(section, k))
+        except configparser.NoSectionError:
+            self.__logger.error(__name__ + " - Invalid Section: " +
+                                "[Section: " + str(section) + "]")
+            sys.exit()
+        except():
+            self.__logger.error(__name__ + " - Invalid Configuration.")
+            sys.exit()
+        return values
+
+    def read_dict(self,
+                  section: str=None) -> Dict:
+        """Read the configuration and save into dictionary.
+        :param section: the section name
+        :return: the read configuration file
+        """
+        self.__logger.debug("Read into Dictionary.")
+        dic = dict()
+        sections = self.sections()
+
+        if section is None:
+            for section in sections:
+                dic[section] = self.options(section)
+                for k, v in dic[section].items():
+                    dic[section][k] = str(v).split(',')
+        else:
+            if section in set(sections):
+                dic = self.options(section)
+                for k, v in dic.items():
+                    dic[k] = str(v).split(',')
+        return dic
+
+    def write_dict(self,
+                   dic: Dict,
+                   section: str,
+                   append: str=False):
+        """Write from the inputted dictionary into the configuration file.
+        :param dic: the inputted dictionary to write into the configuration file.
+        :param section: the section name.
+        :param append: indicates if the write appends to any existing configuration file.
+        """
+        self.__logger.debug("Write from Dictionary.")
+        # set
+        config = configparser.RawConfigParser()
+        config.optionxform = str  # make option is case-sensitive
+        config.add_section(section)
+        keys = list(dic.keys())
+
+        for key in keys:
+            if isinstance(dic[key], list):
+                config.set(section, key, ','.join(dic[key]))
+            else:
+                config.set(section, key, dic[key])
+
+        # write
+        if append is False:
+            with open(self.__path, 'w') as file:
+                config.write(file)
+        else:
+            with open(self.__path, 'a') as file:
+                config.write(file)
+
+    def write_option(self,
+                     section: str,
+                     option: str,
+                     value: str):
+        """Remove then add the specified option to the configuration file.
+        :param section: the section name.
+        :param option: the option name to be removed then added with new value.
+        :param value: the option value to be removed then added with new value.
+        """
+        self.__logger.debug("Write an Option into the Configuration file.")
+        self.__remove_option(section, option)
+        self.__add_option(section, option, value)
+
+    def __remove_option(self,
+                        section: str,
+                        option: str):
+        """Remove an option from the configuration file.
+        :param section: the section name.
+        :param option: the option name to remove.
+        """
+        self.__logger.debug("Remove an Option from the Configuration file.")
+        section = "[" + section + "]"
+        option += "="
+        match = False
+
+        # read
+        with open(self.__path, 'r') as file:
+            lines = file.readlines()
+
+        # delete
+        with open(self.__path, 'w') as file:
+            # remove
+            for line in lines:
+                if line.strip().startswith(section):
+                    match = True
+                if match is True and line.replace(' ', '').startswith(option):
+                    match = False
+                    continue
+                file.write(line)
+
+    def __add_option(self,
+                     section: str,
+                     option: str,
+                     value: str):
+        """Add an option to the configuration file.
+        :param section: the section name.
+        :param option: the option name to be written.
+        :param value: the option value to be written.
+        """
+        self.__logger.debug("Add an Option to the Configuration file.")
+        section = "[" + section + "]"
+        match = False
+
+        # read
+        with open(self.__path, 'r') as file:
+            lines = file.readlines()
+
+        # append
+        with open(self.__path, 'w') as file:
+            for line in lines:
+                if line.strip().startswith(section):
+                    file.write(line)
+                    file.write(option + " = " + ",".join(value) + "\n")
+                    match = True
+                else:
+                    file.write(line)
+            if match is False:
+                file.write("\n" + section + "\n" + option + " = " + ",".join(value) + "\n")