PageRenderTime 25ms CodeModel.GetById 17ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/src/googlecl/config/parser.py

http://googlecl.googlecode.com/
Python | 173 lines | 80 code | 14 blank | 79 comment | 21 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
 16from __future__ import with_statement
 17
 18import logging
 19import os.path
 20
 21LOGGER_NAME = __name__
 22LOG = logging.getLogger(LOGGER_NAME)
 23
 24
 25class ConfigParser(object):
 26  def __init__(self, config_parser_class):
 27    """Initializes the object.
 28
 29    Args:
 30      config_parser: Class that acts as a configuration file parser.
 31    """
 32    self.parser = config_parser_class()
 33    try: # Because default ConfigParser converts to lower case
 34      self.parser.optionxform = str
 35    except:
 36      pass
 37    self.path = None
 38
 39  def associate(self, config_file_path):
 40    """Associates parser with a config file.
 41
 42    Config file is read from config_file_path as well.
 43    """
 44    if os.path.exists(config_file_path):
 45      LOG.debug('Reading configuration from %s', config_file_path)
 46      self.parser.read(config_file_path)
 47    else:
 48      LOG.debug('Config file does not exist, starting with empty parser')
 49    self.path = config_file_path
 50
 51  def ensure_basic_options(self, basic_options):
 52    """Sets options if they are missing.
 53
 54    Args:
 55      basic_options: Nested dictionary in the form of
 56          {section header: {option: value, option: value},
 57           section_header: {option: value, option: value}
 58           ...}
 59    Returns:
 60      True if some of the options in basic_options were not set already, False
 61      otherwise.
 62    """
 63    made_changes = False
 64    for section_name, section_options in basic_options.iteritems():
 65      if not self.parser.has_section(section_name):
 66        self.parser.add_section(section_name)
 67      missing_options = (set(section_options.keys()) -
 68                         set(self.parser.options(section_name)))
 69      for option in missing_options:
 70        self.set(section_name, option, section_options[option])
 71      if missing_options and not made_changes:
 72        made_changes = True
 73    return made_changes
 74
 75  def get(self, section, option):
 76    """Returns option in section.
 77
 78    No backup sections or defaults are returned by this function. If the section
 79    or option does not exist, the config parser will raise an error.
 80
 81    Returns:
 82      String from config file.
 83    """
 84    return self.parser.get(section, option)
 85
 86  def lazy_get(self, section, option, default=None, option_type=None,
 87               backup_section='GENERAL'):
 88    """Returns option from config file.
 89
 90    Tries to retrieve <option> from the given section. If that fails, tries to
 91    retrieve the same option from the backup section. If that fails,
 92    returns value of <default> parameter.
 93
 94    Args:
 95      section: Name of the section to initially try to retrieve the option from.
 96      option: Name of the option to retrieve.
 97      default: Value to return if the option does not exist in a searched
 98          section.
 99      option_type: Conversion function to use on the string, or None to leave as
100          string. For example, if you want an integer value returned, this
101          should be set to int. Not applied to the <default> parameter.
102      backup_section: Section to check if option does not exist in given
103          section. Default 'GENERAL'.
104
105    Returns:
106      Value of the option if it exists in the config file, or value of "default"
107      if option does not exist.
108    """
109    value = self.safe_get(section, option)
110    if value is None:
111      value = self.safe_get(backup_section, option)
112    if value is None:
113      return default
114
115    if option_type:
116      # bool() function doesn't actually do what we wanted, so intercept it
117      # and replace with comparison
118      if option_type == bool:
119        return value.lower() == 'true'
120      else:
121        return option_type(value)
122    else:
123      return value
124
125  def safe_get(self, section, option):
126    """Returns option if section and option exist, None if they do not."""
127    if (self.parser.has_section(section) and
128        self.parser.has_option(section, option)):
129      return self.parser.get(section, option)
130    else:
131      return None
132
133  def set(self, section, option, value):
134    """Sets option in a section."""
135    return self.parser.set(section, option, value)
136
137  def set_missing_default(self, section, option, value):
138    """Sets the option for a section if not defined already.
139
140    If the section does not exist, it is created.
141
142    Args:
143      section: Title of the section to set the option in.
144      option: Option to set.
145      value: Value to give the option.
146      config_path: Path to the configuration file.
147          Default None to use the default path defined in this module.
148    """
149    if type(value) not in [unicode, str]:
150      value = unicode(value)
151    existing_value = self.safe_get(section, option)
152
153    if existing_value is None:
154      if not self.parser.has_section(section):
155        self.parser.add_section(section)
156      self.set(section, option, value)
157
158  def write_out_parser(self, path=None):
159    """Writes options in config parser to file.
160
161    Args:
162      path: Path to write to. Default None for path associated with instance.
163
164    Raises:
165      IOError: No path given and instance is not associated with a path.
166    """
167    if not path:
168      if self.path:
169        path = self.path
170      else:
171        raise IOError('No path given or associated')
172    with open(path, 'w') as config_file:
173      self.parser.write(config_file)