Source code for webmacs.variables

VARIABLES = {}


[docs]class VariableConditionError(Exception): "Raised when a variable condition is not fulfilled"
def condition(func, doc): def _condition(value): if not func(value): assert False, doc _condition.__doc__ = doc return _condition class Variable(object): __slots__ = ("name", "doc", "value", "conditions", "callbacks", "type") def __init__(self, name, doc, value, conditions=(), callbacks=(), type=None): self.name = name self.doc = doc self.conditions = conditions assert isinstance(type, Type) self.type = type self.validate(value) self.value = value self.callbacks = callbacks def validate(self, value): self.type.validate(value) for cond in self.conditions: try: cond(value) except Exception as exc: raise VariableConditionError( "Condition failed for variable {} with value {}: {}" .format(self.name, repr(value), exc) ) from None def set_value(self, value): if value != self.value: self.validate(value) self.value = value for callback in self.callbacks: callback(self) def add_callback(self, callback): if not isinstance(self.callbacks, list): self.callbacks = list(self.callbacks) self.callbacks.append(callback) class Type(object): def validate(self, value): pass def _describe(self, result): pass def type_name(self): return "" def describe(self): result = [self.type_name(), []] self._describe(result[1]) return result class ChoiceMixin(object): def __init__(self, choices=None, **kwargs): super().__init__(**kwargs) self.choices = choices def validate(self, value): super().validate(value) if self.choices and value not in self.choices: raise VariableConditionError("Must be one of %r" % (tuple(self.choices),)) def _describe(self, result): if self.choices: result.append("one of %r" % (tuple(self.choices),)) super()._describe(result) class RangeMixin(object): def __init__(self, min=None, max=None, **kwargs): super().__init__(**kwargs) self.min = min self.max = max def validate(self, value): super().validate(value) if self.min is not None and value < self.min: raise VariableConditionError( "Must be greater or equal to %s" % self.min ) if self.max is not None and value > self.max: raise VariableConditionError( "Must be lesser or equal to %s" % self.max ) def _describe(self, result): if self.min is not None: result.append(">= %s" % self.min) if self.max is not None: result.append("<= %s" % self.max) super()._describe(result) class String(ChoiceMixin, Type): def validate(self, value): if not isinstance(value, str): raise VariableConditionError("Must be a string") super().validate(value) def type_name(self): return "String" class Int(ChoiceMixin, RangeMixin, Type): def validate(self, value): if not isinstance(value, int): raise VariableConditionError("Must be an integer") super().validate(value) def type_name(self): return "Int" class Float(ChoiceMixin, RangeMixin, Type): def validate(self, value): if not isinstance(value, float): raise VariableConditionError("Must be a float") super().validate(value) def type_name(self): return "Float" class Bool(Type): def validate(self, value): if not isinstance(value, bool): raise VariableConditionError("Must be True or False") def type_name(self): return "Bool" class List(Type): def __init__(self, type): self.type = type def validate(self, value): if not isinstance(value, (tuple, list)): raise VariableConditionError("Must be a list") for i, v in enumerate(value): try: self.type.validate(v) except VariableConditionError as exc: raise VariableConditionError("List at position %d: %s" % (i, exc)) from None def type_name(self): return "List" def describe(self): result = super().describe() result.append({"of": self.type.describe()}) return result class Tuple(Type): def __init__(self, *types): self.types = types def validate(self, value): if not (isinstance(value, (tuple, list)) and len(self.types) == len(value)): raise VariableConditionError("Must be a tuple of size %d" % len(self.types)) for i, v in enumerate(value): try: self.types[i].validate(value[i]) except VariableConditionError as exc: raise VariableConditionError("Tuple at position %d: %s" % (i, exc)) from None def type_name(self): return "Tuple" def describe(self): result = super().describe() for i, t in enumerate(self.types): result.append({"at index %i" % i: t.describe()}) return result class Dict(Type): def __init__(self, key_type, value_type): self.key_type = key_type self.value_type = value_type def validate(self, value): if not (isinstance(value, dict)): raise VariableConditionError("Must be a dict") for k, v in value.items(): try: self.key_type.validate(k) except VariableConditionError as exc: raise VariableConditionError("Key %r: %s" % (k, exc)) try: self.value_type.validate(v) except VariableConditionError as exc: raise VariableConditionError("Value for key %r: %s" % (k, exc)) def type_name(self): return "Dict" def describe(self): result = super().describe() result.append({"key": self.key_type.describe()}) result.append({"value": self.key_type.describe()}) return result def define_variable(name, doc, value, **kwargs): var = Variable(name, doc, value, **kwargs) VARIABLES[name] = var return var def get_variable(name): try: return VARIABLES[name] except KeyError: raise KeyError("No such variable %s" % name)
[docs]def get(name): """ Returns the variable value. :param name: the name of the variable. """ return get_variable(name).value
[docs]def set(name, value): """ Set a value for a variable. :param name: the name of the variable. :param value: the new value. :raises: KeyError if the variable does not exists, or :class:`VariableConditionError` if the value is incorrect. """ get_variable(name).set_value(value)
define_variable( "home-page", "Defines the url to use when webmacs starts. If set to the empty" " string, the last session will be loaded. You can set it to" " 'about:blank' if you want an empty page.", "", type=String(), ) define_variable( "home-page-in-new-window", "Use the home page when creating a new window with *make-window*." " Default to False.", False, type=Bool() )