def __init__(self, parser, name, validate=None, default_dict=None): ''' New Section, used to describe options and validation rules for a configuration section. ''' # Validate validator callback if specified. if validate: _validate_validator(validate) # Populate private attributes from call. self._name = name self._rule_list = list() self._validator = validate # Populate _value_dict from default dictionary, updating with # data parsed from this configuration section. self._value_dict = AttrDict() if default_dict: self._value_dict.update(default_dict.items()) self._value_dict.update(parser.items(name)) return
class Section(object): '''Representation of a configuration section.''' _msg_prefix_all = 'configuration validation error:' _msg_prefix_section = ' '.join((_msg_prefix_all, 'section \'%s\':')) _msg_prefix_option = ' '.join((_msg_prefix_section, 'option \'%s\':')) def _make_option_exception(self, rule, msg): '''Format and return an exception for an option validation error.''' msg = (self._msg_prefix_option + ' %s') % (self.name, rule.option, msg) return Config.ValidationError(msg) def _make_section_exception(self, msg): '''Format and return an exception for an section validation error.''' msg = (self._msg_prefix_section + ' %s') % (self.name, msg) return Config.ValidationError(msg) ##### def __init__(self, parser, name, validate=None, default_dict=None): ''' New Section, used to describe options and validation rules for a configuration section. ''' # Validate validator callback if specified. if validate: _validate_validator(validate) # Populate private attributes from call. self._name = name self._rule_list = list() self._validator = validate # Populate _value_dict from default dictionary, updating with # data parsed from this configuration section. self._value_dict = AttrDict() if default_dict: self._value_dict.update(default_dict.items()) self._value_dict.update(parser.items(name)) return ##### def __getattr__(self, attr): '''Allow Section's value dictionary to be accessed as attribute.''' return self._value_dict[attr.lower()] ##### def __str__(self): return '%s:%x' % (self._name, id(self)) ##### def add_rule(self, rule): ''' Add OptionRule to this section. Returns section object so that multiple invocations of this method call can be chained. ''' # Validate that rule is subclass of expected type. if not isinstance(rule, OptionRule): raise TypeError('wrong type object %s' % str(rule)) # Append rule to internal rule list. self._rule_list.append(rule) return self ##### def get_option(self, option_name): '''Returns option by name.''' return self.__getattr__(option_name) ##### @property def name(self): '''Name of section.''' return self._name ##### def options(self): '''Returns list of configuration options found for this section.''' return sorted(self._value_dict.keys()) ##### def rules(self): '''Returns list of option rules defined for this section.''' return sorted(self._rule_list, key=lambda x : x.option) ##### def validate(self): '''Validate configuration section.''' # List for errors accumulated by validation. error_list = list() # pylint: disable=E1101 logging.debug('validating section \'%s\'', self.name) temp_value_dict = dict() # Iterate over all defined rules. for rule in self._rule_list: # pylint: disable=E1101 logging.debug('validating option \'%s\'', rule.option) # Does section have this attribute? if not hasattr(self, rule.option): # Append error to error list if option doesn't appear in # options for section; skip further processing of this rule. logging.debug('option \'%s\' missing', rule.option) error_list.append(self._make_option_exception(rule, 'required option missing')) continue # If valid rule type specified, perform type conversion. if rule.type: try: value = self._convert_type(rule) temp_value_dict[rule.option.lower()] = value except Config.ValidationError as exc: error_list.append(exc) # pylint: disable=W0703 except Exception as exc: # Append any error produced by type conversion to # error list. log.log_exception() error_list.append \ (self._make_option_exception(rule, 'EXCEPTION: %s' % exc)) # pylint: disable=E1101 logging.debug \ ('option \'%s\' failed to convert to %s', rule.option, rule.type.__name__) continue # pylint: disable=E1101 logging.debug \ ('option \'%s\' converted to %s', rule.option, rule.type.__name__) else: # No type converstion necessary for string option. value = getattr(self, rule.option) # If rule validator callback is specified, call it with # AttrDict consisting of a single rule/value pair. if rule.validator: try: # Call rule validator callback with converted value. self._run_rule_validator(rule, value) except Config.ValidationError as exc: error_list.append(exc) logging.debug('option \'%s\' failed to validate', rule.option) except Exception as exc: # Log exception. log.log_exception() # Append error produced by rule validator to error list. error_list.append(exc) logging.debug('option \'%s\' failed to validate', rule.option) continue logging.debug('option \'%s\' validated', rule.option) # If section validator callback is specified, call it with # AttrDict consisting of a single rule/value pair. if self.validator: try: self._run_section_validator() except Config.ValidationError as exc: error_list.append(exc) except Exception as exc: # Log exception. log.log_exception() # Append error produced by validator callback to error list. error_list.append(exc) else: logging.debug('section \'%s\' failed to validate', self) # Process errors produced by any validation steps. if error_list: raise ConfigError(*error_list) self._value_dict.update(temp_value_dict) return ##### @property def validator(self): '''Validator function reference.''' return self._validator ##### def _convert_type(self, rule): '''Perform requested type conversion on specified rule.''' try: # Retrieve attribute value and perform type conversion. value = rule.convert(getattr(self, rule.option)) except ValueError: raise self._make_option_exception \ (rule, 'type conversion to %s failed' % rule.type.__name__) # Method completed without error; return converted value. return value ##### def _run_rule_validator(self, rule, value): '''Run validator callback on specified rule.''' # pylint: disable=E1101 logging.debug('running rule validator %s for option \'%s\'', rule.validator.__name__, rule.option) try: rule.validator(AttrDict({ rule.option : value })) except Config.ValidationError as exc: raise self._make_option_exception(rule, exc) # Method completed without error. return ##### def _run_section_validator(self): '''Run validator callback on Section.''' # pylint: disable=E1101 logging.debug('running section validator %s', self._validator.__name__) try: self.validator(self) except Config.ValidationError as exc: raise self._make_section_exception(exc) # Method completed without error. return