Source code for dhcpkit.common.server.config_elements

"""
The basic configuration objects
"""

import logging

from ZConfig.matcher import SectionValue

logger = logging.getLogger(__name__)


[docs]class ConfigSection: """ Basic configuration section """ name_datatype = None """The datatype of the name of this section. Sections with datatype None cannot have a name""" def __init__(self, section: SectionValue): self.section = section """The `SectionValue` we received as input from the parser""" self.name = self.section.getSectionName() """The parsed value of the section name""" if self.name: if not self.name_datatype: raise ValueError("{} cannot have a name".format(self.__class__.__name__)) # Convert and validate self.name = self.name_datatype(self.name) self.clean_config_section() self.validate_config_section() if self.name_datatype and not self.name: raise ValueError("{} must have {} name".format(self.__class__.__name__, self.name_datatype.__name__)) # noinspection PyMethodMayBeStatic
[docs] def clean_config_section(self): """ Clean up the config, calculating defaults etc. """
# noinspection PyMethodMayBeStatic
[docs] def validate_config_section(self): """ Validate if the information in the config section is acceptable """
def __getattr__(self, item: str): """ Try to resolve non-existent properties from the raw section data :param item: The name of the property :return: The value from the section data """ return getattr(self.section, item) def __str__(self): return self.to_str()
[docs] def to_str(self, indent: int = 0) -> str: """ Return a readable string representation of this element. Because it is not in the real configuration file format we don't attempt to make it look like one. We intentionally make it look different. :param indent: How much indentation at the start of this element :return: The formatted representation """ # Build output in here output = '' # Section type name, or None for the root section_type = self.section.getSectionType() # Opening line, unless this is the root if section_type: name = self.section.getSectionName() if name: output += ' ' * indent + '{} {}:\n'.format(section_type, name) else: output += ' ' * indent + '{}:\n'.format(section_type) indent += 1 # Attributes attributes = self.section.getSectionAttributes() for key in attributes: # Get the value, and always make it a list, even if there is only one value, for easier formatting value = getattr(self.section, key) if isinstance(value, list): values = value else: values = [value] for value in values: if isinstance(value, ConfigSection): # Config sections can format themselves output += value.to_str(indent) else: # For other types we just use their string representation output += ' ' * indent + '{} = {}\n'.format(key, str(value)) return output
[docs]class ConfigElementFactory(ConfigSection): """ Base class for factories to create elements from configuration """ def __init__(self, section: SectionValue): self._element = None super().__init__(section)
[docs] def create(self, *args, **kwargs) -> object: """ Override this method to create the element. :return: The element """ return None
def __call__(self, *args, **kwargs) -> object: """ Create the handler on demand and return it. :return: The option handler """ # Create the handler if we haven't done so yet if self._element is None: self._element = self.create(*args, **kwargs) return self._element