/src/googlecl/config/parser.py

http://googlecl.googlecode.com/ · Python · 173 lines · 80 code · 14 blank · 79 comment · 20 complexity · 929661103924e9a4ba82d36b5295627f MD5 · raw file

  1. # Copyright (C) 2010 Google Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Enhanced configuration file parser."""
  15. from __future__ import with_statement
  16. import logging
  17. import os.path
  18. LOGGER_NAME = __name__
  19. LOG = logging.getLogger(LOGGER_NAME)
  20. class ConfigParser(object):
  21. def __init__(self, config_parser_class):
  22. """Initializes the object.
  23. Args:
  24. config_parser: Class that acts as a configuration file parser.
  25. """
  26. self.parser = config_parser_class()
  27. try: # Because default ConfigParser converts to lower case
  28. self.parser.optionxform = str
  29. except:
  30. pass
  31. self.path = None
  32. def associate(self, config_file_path):
  33. """Associates parser with a config file.
  34. Config file is read from config_file_path as well.
  35. """
  36. if os.path.exists(config_file_path):
  37. LOG.debug('Reading configuration from %s', config_file_path)
  38. self.parser.read(config_file_path)
  39. else:
  40. LOG.debug('Config file does not exist, starting with empty parser')
  41. self.path = config_file_path
  42. def ensure_basic_options(self, basic_options):
  43. """Sets options if they are missing.
  44. Args:
  45. basic_options: Nested dictionary in the form of
  46. {section header: {option: value, option: value},
  47. section_header: {option: value, option: value}
  48. ...}
  49. Returns:
  50. True if some of the options in basic_options were not set already, False
  51. otherwise.
  52. """
  53. made_changes = False
  54. for section_name, section_options in basic_options.iteritems():
  55. if not self.parser.has_section(section_name):
  56. self.parser.add_section(section_name)
  57. missing_options = (set(section_options.keys()) -
  58. set(self.parser.options(section_name)))
  59. for option in missing_options:
  60. self.set(section_name, option, section_options[option])
  61. if missing_options and not made_changes:
  62. made_changes = True
  63. return made_changes
  64. def get(self, section, option):
  65. """Returns option in section.
  66. No backup sections or defaults are returned by this function. If the section
  67. or option does not exist, the config parser will raise an error.
  68. Returns:
  69. String from config file.
  70. """
  71. return self.parser.get(section, option)
  72. def lazy_get(self, section, option, default=None, option_type=None,
  73. backup_section='GENERAL'):
  74. """Returns option from config file.
  75. Tries to retrieve <option> from the given section. If that fails, tries to
  76. retrieve the same option from the backup section. If that fails,
  77. returns value of <default> parameter.
  78. Args:
  79. section: Name of the section to initially try to retrieve the option from.
  80. option: Name of the option to retrieve.
  81. default: Value to return if the option does not exist in a searched
  82. section.
  83. option_type: Conversion function to use on the string, or None to leave as
  84. string. For example, if you want an integer value returned, this
  85. should be set to int. Not applied to the <default> parameter.
  86. backup_section: Section to check if option does not exist in given
  87. section. Default 'GENERAL'.
  88. Returns:
  89. Value of the option if it exists in the config file, or value of "default"
  90. if option does not exist.
  91. """
  92. value = self.safe_get(section, option)
  93. if value is None:
  94. value = self.safe_get(backup_section, option)
  95. if value is None:
  96. return default
  97. if option_type:
  98. # bool() function doesn't actually do what we wanted, so intercept it
  99. # and replace with comparison
  100. if option_type == bool:
  101. return value.lower() == 'true'
  102. else:
  103. return option_type(value)
  104. else:
  105. return value
  106. def safe_get(self, section, option):
  107. """Returns option if section and option exist, None if they do not."""
  108. if (self.parser.has_section(section) and
  109. self.parser.has_option(section, option)):
  110. return self.parser.get(section, option)
  111. else:
  112. return None
  113. def set(self, section, option, value):
  114. """Sets option in a section."""
  115. return self.parser.set(section, option, value)
  116. def set_missing_default(self, section, option, value):
  117. """Sets the option for a section if not defined already.
  118. If the section does not exist, it is created.
  119. Args:
  120. section: Title of the section to set the option in.
  121. option: Option to set.
  122. value: Value to give the option.
  123. config_path: Path to the configuration file.
  124. Default None to use the default path defined in this module.
  125. """
  126. if type(value) not in [unicode, str]:
  127. value = unicode(value)
  128. existing_value = self.safe_get(section, option)
  129. if existing_value is None:
  130. if not self.parser.has_section(section):
  131. self.parser.add_section(section)
  132. self.set(section, option, value)
  133. def write_out_parser(self, path=None):
  134. """Writes options in config parser to file.
  135. Args:
  136. path: Path to write to. Default None for path associated with instance.
  137. Raises:
  138. IOError: No path given and instance is not associated with a path.
  139. """
  140. if not path:
  141. if self.path:
  142. path = self.path
  143. else:
  144. raise IOError('No path given or associated')
  145. with open(path, 'w') as config_file:
  146. self.parser.write(config_file)