def state(self): return EnhancedDict(containers=self.containers(), services=self.services(), all_containers=Lazy(self.containers, all=True), all_services=Lazy(self.services, desired_task_state=''), nodes=Lazy(self.nodes))
def test_init(self): lazy = Lazy(str, 6) self.assertEqual(str(lazy), '6') lazy = Lazy(EnhancedDict, key='lazy') self.assertEqual(lazy.key, 'lazy')
def test_enhanced_types(self): lazy = Lazy(lambda: EnhancedDict(key='value')) self.assertEqual(lazy.key, 'value') lazy = Lazy(lambda: EnhancedList([1, 2, 3])) self.assertEqual((lazy.first, lazy[1], lazy.last), (1, 2, 3))
def test_range(self): lazy = Lazy(lambda: range(5)) for i, a in enumerate(lazy): self.assertEqual(a, i) self.assertEqual(len(lazy), 5)
def __init__(self, name, data=None, filter=None): """ :param name: :param data: data from request :param filter: subtree filter for nuci config :type filter: Element :return: """ super(ForisForm, self).__init__(name) if isinstance(data, MultiDict): self._request_data = {} # values from request # convert MultiDict to normal dict with multiple values in lists # if value is suffixed with '[]' (i.e. it is multifield) for key, value in data.iteritems(): if key.endswith("[]"): # we don't want to alter lists in MultiDict instance values = copy.deepcopy(data.getall(key)) logger.debug("%s: %s (%s)", key, values, value) # split value by \r\n - sent by textarea if "\r\n" in value: values = value.split("\r\n") # remove dummy value from hidden field elif len(values) and not values[0]: del values[0] # strip [] suffix self._request_data[key[:-2]] = values else: self._request_data[key] = value else: self._request_data = data or {} self._nuci_data = {} # values fetched from nuci self.defaults = {} # default values from field definitions self.__data_cache = None # cached data self.__form_cache = None self.validated = False # _nuci_config is not required every time, lazy-evaluate it self._nuci_config = Lazy(lambda: client.get(filter)) self.requirement_map = defaultdict( list) # mapping: requirement -> list of required_by self.callbacks = [] self.callback_results = {} # name -> result
def __init__(self, name, data=None, filter=None): """ :param name: :param data: data from request :param filter: subtree filter for nuci config :type filter: Element :return: """ super(ForisForm, self).__init__(name) if isinstance(data, MultiDict): self._request_data = {} # values from request # convert MultiDict to normal dict with multiple values in lists # if value is suffixed with '[]' (i.e. it is multifield) for key, value in data.iteritems(): if key.endswith("[]"): # we don't want to alter lists in MultiDict instance values = copy.deepcopy(data.getall(key)) logger.debug("%s: %s (%s)", key, values, value) # split value by \r\n - sent by textarea if "\r\n" in value: values = value.split("\r\n") # remove dummy value from hidden field elif len(values) and not values[0]: del values[0] # strip [] suffix self._request_data[key[:-2]] = values else: self._request_data[key] = value else: self._request_data = data or {} self._nuci_data = {} # values fetched from nuci self.defaults = {} # default values from field definitions self.__data_cache = None # cached data self.__form_cache = None self.validated = False # _nuci_config is not required every time, lazy-evaluate it self._nuci_config = Lazy(lambda: client.get(filter)) self.requirement_map = defaultdict(list) # mapping: requirement -> list of required_by self.callbacks = [] self.callback_results = {} # name -> result
class ForisForm(ForisFormElement): def __init__(self, name, data=None, filter=None): """ :param name: :param data: data from request :param filter: subtree filter for nuci config :type filter: Element :return: """ super(ForisForm, self).__init__(name) if isinstance(data, MultiDict): self._request_data = {} # values from request # convert MultiDict to normal dict with multiple values in lists # if value is suffixed with '[]' (i.e. it is multifield) for key, value in data.iteritems(): if key.endswith("[]"): # we don't want to alter lists in MultiDict instance values = copy.deepcopy(data.getall(key)) logger.debug("%s: %s (%s)", key, values, value) # split value by \r\n - sent by textarea if "\r\n" in value: values = value.split("\r\n") # remove dummy value from hidden field elif len(values) and not values[0]: del values[0] # strip [] suffix self._request_data[key[:-2]] = values else: self._request_data[key] = value else: self._request_data = data or {} self._nuci_data = {} # values fetched from nuci self.defaults = {} # default values from field definitions self.__data_cache = None # cached data self.__form_cache = None self.validated = False # _nuci_config is not required every time, lazy-evaluate it self._nuci_config = Lazy(lambda: client.get(filter)) self.requirement_map = defaultdict( list) # mapping: requirement -> list of required_by self.callbacks = [] self.callback_results = {} # name -> result @property def nuci_config(self): return self._nuci_config @property def data(self): """ Current data, from defaults, nuci values and request data. Caches the result on the first call. :return: dictionary with the Form's data """ if self.__data_cache is None: self.__data_cache = self.current_data return self.__data_cache @property def current_data(self): """ Current data, from defaults, nuci values and request data. Does not use caching. :return: dictionary with the Form's data """ self._update_nuci_data() data = {} logger.debug("Updating with defaults: %s", self.defaults) data.update(self.defaults) logger.debug("Updating with Nuci data: %s", self._nuci_data) data.update(self._nuci_data) logger.debug("Updating with data: %s", dict(self._request_data)) data.update(self._request_data) if data: data = self.clean_data(data) return data def clean_data(self, data): new_data = {} fields = self._get_all_fields() for field in fields: new_data[field.name] = data[field.name] if field.name in data: if issubclass(field.type, Checkbox): # coerce checkbox values to boolean new_data[field.name] = False if data[ field.name] == "0" else bool(data[field.name]) # get names of active fields according to new_data active_field_names = map(lambda x: x.name, self.get_active_fields(data=new_data)) # get new dict of data of active fields return { k: v for k, v in new_data.iteritems() if k in active_field_names } def invalidate_data(self): self.__data_cache = None @property def _form(self): if self.__form_cache is not None: return self.__form_cache inputs = map(lambda x: x.field, self.get_active_fields()) # TODO: creating the form everytime might by a wrong approach... logger.debug("Creating Form()...") form = Form(*inputs) form.fill(self.data) self.__form_cache = form return form @property def valid(self): return self._form.valid def _get_all_fields(self, element=None, fields=None): element = element or self fields = fields or [] for c in element.children.itervalues(): if c.children: fields = self._get_all_fields(c, fields) if isinstance(c, Field): fields.append(c) return fields def get_active_fields(self, element=None, data=None): """Get all fields that meet their requirements. :param element: :param data: data to check requirements against :return: list of fields """ fields = self._get_all_fields(element) if fields: data = data or self.data return filter(lambda f: f.has_requirements(data), fields) def _update_nuci_data(self): for field in self._get_all_fields(): if field.nuci_path: value = self._nuci_config.find_child(field.nuci_path) if value: if not field.nuci_preproc: preprocessed = value.value else: preprocessed = field.nuci_preproc(value) # update if result is not None if preprocessed is not None: self._nuci_data[field.name] = preprocessed elif field.nuci_preproc: # we have preproc method, but no path - just pass all the data to preproc function preprocessed = field.nuci_preproc(self._nuci_config) # update if result is not None if preprocessed is not None: self._nuci_data[field.name] = preprocessed def add_section(self, *args, **kwargs): """ :param args: :param kwargs: :return: new Section :rtype: Section """ if len(args) and isinstance(args[0], Section): return self._add(args[0]) return self._add(Section(self, *args, **kwargs)) @property def active_fields(self): return self.get_active_fields() @property def errors(self): return self._form.note def render(self): result = "<div class=\"errors\">%s</div>" % self.errors result += "\n".join(c.render() for c in self.children.itervalues()) return result def save(self): self.process_callbacks(self.data) commit() def validate(self): self.validated = True return self._form.validates(self.data) def add_callback(self, cb): """Add callback function. Callback is a function taking argument `data` (contains form data) and returning a tuple `(action, *args)`. Action can be one of following: - edit_config: args is Uci instance - send command for modifying Uci structure - save_result: arg[0] is dict of result_name->result - results are saved to dictionary callback_results (instance attribute) ValueError is raised when two callbacks use same result_name - none: do nothing, everything has been processed in the callback function :param cb: callback function :return: None """ self.callbacks.append(cb) def process_callbacks(self, form_data): logger.debug("Processing callbacks") for cb in self.callbacks: logger.debug("Processing callback: %s", cb) cb_result = cb(form_data) operation = cb_result[0] if operation == "none": pass elif operation == "save_result": for k, v in cb_result[1].iteritems(): if k in self.callback_results: raise ValueError( "save_result callback returned result with duplicate name: '%s'" % k) self.callback_results[k] = v elif operation == "edit_config": data = cb_result[1:] if len(cb_result) > 1 else () add_config_update(*data) else: raise NotImplementedError( "Unsupported callback operation: %s" % operation)
class ForisForm(ForisFormElement): def __init__(self, name, data=None, filter=None): """ :param name: :param data: data from request :param filter: subtree filter for nuci config :type filter: Element :return: """ super(ForisForm, self).__init__(name) if isinstance(data, MultiDict): self._request_data = {} # values from request # convert MultiDict to normal dict with multiple values in lists # if value is suffixed with '[]' (i.e. it is multifield) for key, value in data.iteritems(): if key.endswith("[]"): # we don't want to alter lists in MultiDict instance values = copy.deepcopy(data.getall(key)) logger.debug("%s: %s (%s)", key, values, value) # split value by \r\n - sent by textarea if "\r\n" in value: values = value.split("\r\n") # remove dummy value from hidden field elif len(values) and not values[0]: del values[0] # strip [] suffix self._request_data[key[:-2]] = values else: self._request_data[key] = value else: self._request_data = data or {} self._nuci_data = {} # values fetched from nuci self.defaults = {} # default values from field definitions self.__data_cache = None # cached data self.__form_cache = None self.validated = False # _nuci_config is not required every time, lazy-evaluate it self._nuci_config = Lazy(lambda: client.get(filter)) self.requirement_map = defaultdict(list) # mapping: requirement -> list of required_by self.callbacks = [] self.callback_results = {} # name -> result @property def nuci_config(self): return self._nuci_config @property def data(self): """ Data are union of defaults + nuci values + request data. :return: currently known form data """ if self.__data_cache is not None: return self.__data_cache self._update_nuci_data() data = {} logger.debug("Updating with defaults: %s", self.defaults) data.update(self.defaults) logger.debug("Updating with Nuci data: %s", self._nuci_data) data.update(self._nuci_data) logger.debug("Updating with data: %s", dict(self._request_data)) data.update(self._request_data) if data: data = self.clean_data(data) self.__data_cache = data return data def clean_data(self, data): new_data = {} fields = self._get_all_fields() for field in fields: new_data[field.name] = data[field.name] if field.name in data: if issubclass(field.type, Checkbox): # coerce checkbox values to boolean new_data[field.name] = False if data[field.name] == "0" else bool(data[field.name]) # get names of active fields according to new_data active_field_names = map(lambda x: x.name, self.get_active_fields(data=new_data)) # get new dict of data of active fields return {k: v for k, v in new_data.iteritems() if k in active_field_names} def invalidate_data(self): self.__data_cache = None @property def _form(self): if self.__form_cache is not None: return self.__form_cache inputs = map(lambda x: x.field, self.get_active_fields()) # TODO: creating the form everytime might by a wrong approach... logger.debug("Creating Form()...") form = Form(*inputs) form.fill(self.data) self.__form_cache = form return form @property def valid(self): return self._form.valid def _get_all_fields(self, element=None, fields=None): element = element or self fields = fields or [] for c in element.children.itervalues(): if c.children: fields = self._get_all_fields(c, fields) if isinstance(c, Field): fields.append(c) return fields def get_active_fields(self, element=None, data=None): """Get all fields that meet their requirements. :param element: :param data: data to check requirements against :return: list of fields """ fields = self._get_all_fields(element) if fields: data = data or self.data return filter(lambda f: f.has_requirements(data), fields) def _update_nuci_data(self): for field in self._get_all_fields(): if field.nuci_path: value = self._nuci_config.find_child(field.nuci_path) if value: if not field.nuci_preproc: preprocessed = value.value else: preprocessed = field.nuci_preproc(value) # update if result is not None if preprocessed is not None: self._nuci_data[field.name] = preprocessed elif field.nuci_preproc: # we have preproc method, but no path - just pass all the data to preproc function preprocessed = field.nuci_preproc(self._nuci_config) # update if result is not None if preprocessed is not None: self._nuci_data[field.name] = preprocessed def add_section(self, *args, **kwargs): """ :param args: :param kwargs: :return: new Section :rtype: Section """ if len(args) and isinstance(args[0], Section): return self._add(args[0]) return self._add(Section(self, *args, **kwargs)) @property def active_fields(self): return self.get_active_fields() @property def errors(self): return self._form.note def render(self): result = "<div class=\"errors\">%s</div>" % self.errors result += "\n".join(c.render() for c in self.children.itervalues()) return result def save(self): self.process_callbacks(self.data) commit() def validate(self): self.validated = True return self._form.validates(self.data) def add_callback(self, cb): """Add callback function. Callback is a function taking argument `data` (contains form data) and returning a tuple `(action, *args)`. Action can be one of following: - edit_config: args is Uci instance - send command for modifying Uci structure - save_result: arg[0] is dict of result_name->result - results are saved to dictionary callback_results (instance attribute) ValueError is raised when two callbacks use same result_name - none: do nothing, everything has been processed in the callback function :param cb: callback function :return: None """ self.callbacks.append(cb) def process_callbacks(self, form_data): logger.debug("Processing callbacks") for cb in self.callbacks: logger.debug("Processing callback: %s", cb) cb_result = cb(form_data) operation = cb_result[0] if operation == "none": pass elif operation == "save_result": for k, v in cb_result[1].iteritems(): if k in self.callback_results: raise ValueError("save_result callback returned result with duplicate name: '%s'" % k) self.callback_results[k] = v elif operation == "edit_config": data = cb_result[1:] if len(cb_result) > 1 else () add_config_update(*data) else: raise NotImplementedError("Unsupported callback operation: %s" % operation)
def __init__(self, com_port): self._com_port = com_port self._port = Lazy(self._create_port)
def test_callable(self): lazy = Lazy(lambda: str) self.assertEqual(lazy(0.4), '0.4')
def test_hash(self): lazy = Lazy(lambda: 3) self.assertEqual(hash(lazy), 3)