No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

settings_loader.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #-*- coding: utf-8 -*-
  2. import configparser
  3. import os
  4. import glob
  5. import copy
  6. from lodel.settings.utils import *
  7. from lodel.settings.validator import SettingsValidationError
  8. from lodel.settings.utils import SettingsError, SettingsErrors
  9. ##@brief Merges and loads configuration files
  10. class SettingsLoader(object):
  11. ## To avoid the DEFAULT section whose values are found in all sections, we
  12. # have to give it an unsual name
  13. DEFAULT_SECTION = 'lodel2_default_passaway_tip'
  14. ## @brief Virtual filename when default value is used
  15. DEFAULT_FILENAME = 'default_value'
  16. ##@brief Constructor
  17. # @param conf_path str : conf.d path
  18. def __init__(self,conf_path):
  19. self.__conf_path=conf_path
  20. self.__conf_sv=dict()
  21. self.__conf=self.__merge()
  22. # Stores errors
  23. self.__errors_list = []
  24. ##@brief Lists and merges files in settings_loader.conf_path
  25. # @return dict()
  26. def __merge(self):
  27. conf = dict()
  28. l_dir = glob.glob(self.__conf_path+'/*.ini')
  29. for f_ini in l_dir:
  30. config = configparser.ConfigParser(default_section = self.DEFAULT_SECTION ,interpolation=None)
  31. config.read(f_ini)
  32. for section in [ s for s in config if s != self.DEFAULT_SECTION ]:
  33. if section not in conf:
  34. conf[section] = dict()
  35. for param in config[section]:
  36. if param not in conf[section]:
  37. conf[section][param]=dict()
  38. conf[section][param]['value'] = config[section][param]
  39. conf[section][param]['file'] = f_ini
  40. self.__conf_sv[section + ':' + param]=f_ini
  41. else:
  42. raise SettingsError("Error redeclaration of key %s in section %s. Found in %s and %s" % (
  43. section,
  44. param,
  45. f_ini,
  46. conf[section][param]['file']))
  47. return conf
  48. ##@brief Returns option if exists default_value else and validates
  49. # @param section str : name of the section
  50. # @param keyname str
  51. # @param validator callable : takes one argument value and raises validation fail
  52. # @param default_value *
  53. # @param mandatory bool
  54. # @return the option
  55. def getoption(self,section,keyname,validator,default_value=None,mandatory=False):
  56. conf=self.__conf
  57. if section not in conf:
  58. conf[section] = dict()
  59. sec = conf[section]
  60. if keyname in sec:
  61. result = sec[keyname]['value']
  62. try:
  63. del self.__conf_sv[section + ':' + keyname]
  64. except KeyError: #allready fetched
  65. pass
  66. elif default_value is None and mandatory:
  67. msg = "Default value mandatory for option %s" % keyname
  68. expt = SettingsError( msg = msg,
  69. key_id = section+'.'+keyname,
  70. filename = sec[keyname]['file'])
  71. self.__errors_list.append(expt)
  72. return
  73. else:
  74. sec[keyname]=dict()
  75. sec[keyname]['value'] = default_value
  76. sec[keyname]['file'] = SettingsLoader.DEFAULT_FILENAME
  77. result = default_value
  78. try:
  79. return validator(result)
  80. except Exception as e:
  81. # Generating nice exceptions
  82. if False and sec[keyname]['file'] == SettingsLoader.DEFAULT_FILENAME:
  83. expt = SettingsError( msg = 'Mandatory settings not found',
  84. key_id = section+'.'+keyname)
  85. self.__errors_list.append(expt)
  86. else:
  87. expt = SettingsValidationError(
  88. "For %s.%s : %s" %
  89. (section, keyname,e)
  90. )
  91. expt2 = SettingsError( msg = str(expt),
  92. key_id = section+'.'+keyname,
  93. filename = sec[keyname]['file'])
  94. self.__errors_list.append(expt2)
  95. return
  96. ##@brief Sets option in a config section. Writes in the conf file
  97. # @param section str : name of the section
  98. # @param keyname str
  99. # @param value str
  100. # @param validator callable : takes one argument value and raises validation fail
  101. # @return the option
  102. def setoption(self,section,keyname,value,validator):
  103. f_conf=copy.copy(self.__conf[section][keyname]['file'])
  104. if f_conf == SettingsLoader.DEFAULT_FILENAME:
  105. f_conf = self.__conf_path + '/generated.ini'
  106. conf=self.__conf
  107. conf[section][keyname] = value
  108. config = configparser.ConfigParser()
  109. config.read(f_conf)
  110. if section not in config:
  111. config[section]={}
  112. config[section][keyname] = validator(value)
  113. with open(f_conf, 'w') as configfile:
  114. config.write(configfile)
  115. ##@brief Saves new partial configuration. Writes in the conf files corresponding
  116. # @param sections dict
  117. # @param validators dict of callable : takes one argument value and raises validation fail
  118. def saveconf(self, sections, validators):
  119. for sec in sections:
  120. for kname in sections[sec]:
  121. self.setoption(sec,kname,sections[sec][kname],validators[sec][kname])
  122. ##@brief Returns the section to be configured
  123. # @param section_prefix str
  124. # @param default_section str
  125. # @return the section as dict()
  126. def getsection(self,section_prefix,default_section=None):
  127. conf=copy.copy(self.__conf)
  128. sections=[]
  129. if section_prefix in conf:
  130. sections.append(section_prefix)
  131. for sect_names in conf:
  132. if sect_names in sections:
  133. pass
  134. elif sect_names.startswith(section_prefix + '.'):
  135. sections.append(sect_names)
  136. if sections == [] and default_section:
  137. sections.append(section_prefix + '.' + default_section)
  138. elif sections == []:
  139. raise NameError("Not existing settings section : %s" % section_prefix)
  140. return sections
  141. ##@brief Returns invalid settings
  142. #
  143. # This method returns all the settings that was not fecthed by
  144. # getsection() method. For the Settings object it allows to know
  145. # the list of invalids settings keys
  146. # @return a dict with SECTION_NAME+":"+KEY_NAME as key and the filename
  147. # where the settings was found as value
  148. def getremains(self):
  149. return self.__conf_sv
  150. ##@brief Raise a SettingsErrors exception if some confs remains
  151. #@note typically used at the end of Settings bootstrap
  152. def raise_errors(self):
  153. remains = self.getremains()
  154. err_l = self.__errors_list
  155. for key_id, filename in remains.items():
  156. err_l.append(SettingsError( msg = "Invalid configuration key",
  157. key_id = key_id,
  158. filename = filename))
  159. if len(err_l) > 0:
  160. raise SettingsErrors(err_l)
  161. else:
  162. return