Açıklama Yok
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 6.9KB

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