Source code for glorpen.config.fields.base

'''
.. moduleauthor:: Arkadiusz Dzięgiel <arkadiusz.dziegiel@glorpen.pl>
'''
import contextlib
from collections import OrderedDict
from glorpen.config import exceptions
from glorpen.config.translators.base import Help, ContainerHelp

class Value(object):
    packed = None

    def __init__(self, field):
        super().__init__()

        if not isinstance(field, (Field,)):
            raise exceptions.ConfigException("Value %r passed as field is not a field" % field)
        
        self.field = field

class ContainerValue(Value):
    def __init__(self, values, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.values = OrderedDict(values)

class SingleValue(Value):
    def __init__(self, value, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.value = value

[docs]class Field(object): """Single field in configuration file. Custom fields should implement own normalizer/interpolation by overriding corresponding methods. To add custom validation based on whole config object use :meth:`.validator`. """ # used by Optional wrapper default_value = None help_class = Help def __init__(self, validators=None): super().__init__() self._validators = list(validators) if validators else [] self.help_config = self.help_class() def is_value_supported(self, raw_value) -> bool: raise NotImplementedError() def normalize(self, raw_value) -> Value: raise NotImplementedError()
[docs] def get_dependencies(self, normalized_value): """ Find parts that can be interpolated and return required deps. Should check only own data, no nested fields. """ return []
[docs] def interpolate(self, normalized_value, values) -> None: """ Should replace data in normalized_value with interpolated one. Called only when ``get_dependencies`` finds something. """ raise NotImplementedError()
def create_packed_value(self, normalized_value): raise NotImplementedError() def pack(self, interpolated_value): packed = self.create_packed_value(interpolated_value) interpolated_value.packed = packed return packed def validator(self, cb): self._validators.append(cb) return self def validate(self, packed_value, packed_tree): for cb in self._validators: cb(packed_value, packed_tree) def help(self, **kwargs): self.help_config.set(**kwargs) return self
class Unset(): pass class Optional(Field): help_class = ContainerHelp """Field wrapper for nullable fields with defaults.""" def __init__(self, field, default=Unset): super().__init__() self.field = field if default is Unset: default = field.default_value self.default = default self.help_config.set_children(self.field.help_config) self.help_config.set_value(self.default) def is_value_supported(self, raw_value): return raw_value is None or self.field.is_value_supported(raw_value) def normalize(self, raw_value): if raw_value is None: return SingleValue(Unset, self) return self.field.normalize(raw_value) def get_dependencies(self, normalized_value): try: if normalized_value.value is Unset: return [] except AttributeError: pass return self.field.get_dependencies(normalized_value) def interpolate(self, normalized_value, values): self.field.interpolate(normalized_value, values) def create_packed_value(self, normalized_value): # when we use default value but self.field is a list or dict # we know that we should use default value # if SingleValue is used by self.field then we should check # if given value is default try: if normalized_value.value is Unset: return self.default except AttributeError: pass return self.field.create_packed_value(normalized_value) def is_optional(field): return isinstance(field, Optional)