Mercurial > libervia-backend
diff sat/tools/xml_tools.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 26edcf3a30eb |
children | a55a14c3cbf4 |
line wrap: on
line diff
--- a/sat/tools/xml_tools.py Wed Jun 27 07:51:29 2018 +0200 +++ b/sat/tools/xml_tools.py Wed Jun 27 20:14:46 2018 +0200 @@ -20,6 +20,7 @@ from sat.core.i18n import _ from sat.core.constants import Const as C from sat.core.log import getLogger + log = getLogger(__name__) from xml.dom import minidom, NotFoundErr @@ -37,14 +38,15 @@ SAT_FORM_PREFIX = "SAT_FORM_" SAT_PARAM_SEPARATOR = "_XMLUI_PARAM_" # used to have unique elements names -html_entity_re = re.compile(r'&([a-zA-Z]+?);') -XML_ENTITIES = ('quot', 'amp', 'apos', 'lt', 'gt') +html_entity_re = re.compile(r"&([a-zA-Z]+?);") +XML_ENTITIES = ("quot", "amp", "apos", "lt", "gt") # TODO: move XMLUI stuff in a separate module # TODO: rewrite this with lxml or ElementTree or domish.Element: it's complicated and difficult to maintain with current minidom implementation # Helper functions + def _dataFormField2XMLUIData(field, read_only=False): """Get data needed to create an XMLUI's Widget from Wokkel's data_form's Field. @@ -55,8 +57,8 @@ """ widget_args = [field.value] widget_kwargs = {} - if field.fieldType == 'fixed' or field.fieldType is None: - widget_type = 'text' + if field.fieldType == "fixed" or field.fieldType is None: + widget_type = "text" if field.value is None: if field.label is None: log.warning(_("Fixed field has neither value nor label, ignoring it")) @@ -65,36 +67,40 @@ field.value = field.label field.label = None widget_args[0] = field.value - elif field.fieldType == 'text-single': + elif field.fieldType == "text-single": widget_type = "string" - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'jid-single': + widget_kwargs["read_only"] = read_only + elif field.fieldType == "jid-single": widget_type = "jid_input" - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'text-multi': + widget_kwargs["read_only"] = read_only + elif field.fieldType == "text-multi": widget_type = "textbox" - widget_args[0] = u'\n'.join(field.values) - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'text-private': + widget_args[0] = u"\n".join(field.values) + widget_kwargs["read_only"] = read_only + elif field.fieldType == "text-private": widget_type = "password" - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'boolean': + widget_kwargs["read_only"] = read_only + elif field.fieldType == "boolean": widget_type = "bool" if widget_args[0] is None: - widget_args[0] = 'false' - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'integer': + widget_args[0] = "false" + widget_kwargs["read_only"] = read_only + elif field.fieldType == "integer": widget_type = "integer" - widget_kwargs['read_only'] = read_only - elif field.fieldType == 'list-single': + widget_kwargs["read_only"] = read_only + elif field.fieldType == "list-single": widget_type = "list" - widget_kwargs["options"] = [(option.value, option.label or option.value) for option in field.options] + widget_kwargs["options"] = [ + (option.value, option.label or option.value) for option in field.options + ] widget_kwargs["selected"] = widget_args widget_args = [] else: - log.error(u"FIXME FIXME FIXME: Type [%s] is not managed yet by SàT" % field.fieldType) + log.error( + u"FIXME FIXME FIXME: Type [%s] is not managed yet by SàT" % field.fieldType + ) widget_type = "string" - widget_kwargs['read_only'] = read_only + widget_kwargs["read_only"] = read_only if field.var: widget_kwargs["name"] = field.var @@ -121,7 +127,7 @@ if filters is None: filters = {} if form.instructions: - form_ui.addText('\n'.join(form.instructions), 'instructions') + form_ui.addText("\n".join(form.instructions), "instructions") form_ui.changeContainer("label") @@ -130,13 +136,17 @@ form_ui.addWidget(*widget_args) for field in form.fieldList: - widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field, read_only) + widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData( + field, read_only + ) try: - widget_filter = filters[widget_kwargs['name']] + widget_filter = filters[widget_kwargs["name"]] except KeyError: pass else: - widget_type, widget_args, widget_kwargs = widget_filter(form_ui, widget_type, widget_args, widget_kwargs) + widget_type, widget_args, widget_kwargs = widget_filter( + form_ui, widget_type, widget_args, widget_kwargs + ) label = field.label or field.var if label: form_ui.addLabel(label) @@ -172,27 +182,29 @@ """ headers = OrderedDict() try: - reported_elt = form_xml.elements('jabber:x:data', 'reported').next() + reported_elt = form_xml.elements("jabber:x:data", "reported").next() except StopIteration: - raise exceptions.DataError("Couldn't find expected <reported> tag in %s" % form_xml.toXml()) + raise exceptions.DataError( + "Couldn't find expected <reported> tag in %s" % form_xml.toXml() + ) for elt in reported_elt.elements(): if elt.name != "field": raise exceptions.DataError("Unexpected tag") name = elt["var"] - label = elt.attributes.get('label', '') - type_ = elt.attributes.get('type') + label = elt.attributes.get("label", "") + type_ = elt.attributes.get("type") headers[name] = (label, type_) if not headers: raise exceptions.DataError("No reported fields (see XEP-0004 §3.4)") xmlui_data = [] - item_elts = form_xml.elements('jabber:x:data', 'item') + item_elts = form_xml.elements("jabber:x:data", "item") for item_elt in item_elts: for elt in item_elt.elements(): - if elt.name != 'field': + if elt.name != "field": log.warning(u"Unexpected tag (%s)" % elt.name) continue field = data_form.Field.fromElement(elt) @@ -211,7 +223,9 @@ @param xmlui_data (list[tuple]): list of (widget_type, widget_args, widget_kwargs) @return: the completed XMLUI instance """ - adv_list = AdvancedListContainer(xmlui, headers=headers, columns=len(headers), parent=xmlui.current_container) + adv_list = AdvancedListContainer( + xmlui, headers=headers, columns=len(headers), parent=xmlui.current_container + ) xmlui.changeContainer(adv_list) for widget_type, widget_args, widget_kwargs in xmlui_data: @@ -248,7 +262,10 @@ dataForm2Widgets(xml_ui, parsed_form, read_only=True) return xml_ui -def dataFormResult2XMLUI(result_form, base_form, session_id=None, prepend=None, filters=None): + +def dataFormResult2XMLUI( + result_form, base_form, session_id=None, prepend=None, filters=None +): """Convert data form result to SàT XMLUI. @param result_form (data_form.Form): result form to convert @@ -290,7 +307,11 @@ @param xmlui_data (dict): data returned by frontends for XMLUI form @return: dict of data usable by Wokkel's data form """ - return {key[len(SAT_FORM_PREFIX):]: _cleanValue(value) for key, value in xmlui_data.iteritems() if key.startswith(SAT_FORM_PREFIX)} + return { + key[len(SAT_FORM_PREFIX) :]: _cleanValue(value) + for key, value in xmlui_data.iteritems() + if key.startswith(SAT_FORM_PREFIX) + } def formEscape(name): @@ -308,7 +329,7 @@ @param xmlui_data (dict): data returned by frontends for XMLUI form @return: domish.Element """ - form = data_form.Form('submit') + form = data_form.Form("submit") form.makeFields(XMLUIResult2DataFormResult(xmlui_data)) return form.toElement() @@ -319,7 +340,7 @@ @param values (list): list of tuples @return: data_form.Form """ - form = data_form.Form('submit') + form = data_form.Form("submit") for value in values: field = data_form.Field(var=value[0], value=value[1]) form.addField(field) @@ -334,39 +355,41 @@ @return: XMLUI """ # TODO: refactor params and use Twisted directly to parse XML - params_doc = minidom.parseString(xml.encode('utf-8')) + params_doc = minidom.parseString(xml.encode("utf-8")) top = params_doc.documentElement - if top.nodeName != 'params': - raise exceptions.DataError(_('INTERNAL ERROR: parameters xml not valid')) + if top.nodeName != "params": + raise exceptions.DataError(_("INTERNAL ERROR: parameters xml not valid")) param_ui = XMLUI("param", "tabs") tabs_cont = param_ui.current_container for category in top.getElementsByTagName("category"): - category_name = category.getAttribute('name') - label = category.getAttribute('label') + category_name = category.getAttribute("name") + label = category.getAttribute("label") if not category_name: - raise exceptions.DataError(_('INTERNAL ERROR: params categories must have a name')) + raise exceptions.DataError( + _("INTERNAL ERROR: params categories must have a name") + ) tabs_cont.addTab(category_name, label=label, container=LabelContainer) for param in category.getElementsByTagName("param"): widget_kwargs = {} - param_name = param.getAttribute('name') - param_label = param.getAttribute('label') - type_ = param.getAttribute('type') - if not param_name and type_ != 'text': - raise exceptions.DataError(_('INTERNAL ERROR: params must have a name')) + param_name = param.getAttribute("name") + param_label = param.getAttribute("label") + type_ = param.getAttribute("type") + if not param_name and type_ != "text": + raise exceptions.DataError(_("INTERNAL ERROR: params must have a name")) - value = param.getAttribute('value') or None - callback_id = param.getAttribute('callback_id') or None + value = param.getAttribute("value") or None + callback_id = param.getAttribute("callback_id") or None - if type_ == 'list': + if type_ == "list": options, selected = _paramsGetListOptions(param) - widget_kwargs['options'] = options - widget_kwargs['selected'] = selected - widget_kwargs['styles'] = ['extensible'] - elif type_ == 'jids_list': - widget_kwargs['jids'] = _paramsGetListJids(param) + widget_kwargs["options"] = options + widget_kwargs["selected"] = selected + widget_kwargs["styles"] = ["extensible"] + elif type_ == "jids_list": + widget_kwargs["jids"] = _paramsGetListJids(param) if type_ in ("button", "text"): param_ui.addEmpty() @@ -378,13 +401,20 @@ widget_kwargs["value"] = value if callback_id: - widget_kwargs['callback_id'] = callback_id - others = ["%s%s%s" % (category_name, SAT_PARAM_SEPARATOR, other.getAttribute('name')) - for other in category.getElementsByTagName('param') - if other.getAttribute('type') != 'button'] - widget_kwargs['fields_back'] = others + widget_kwargs["callback_id"] = callback_id + others = [ + "%s%s%s" + % (category_name, SAT_PARAM_SEPARATOR, other.getAttribute("name")) + for other in category.getElementsByTagName("param") + if other.getAttribute("type") != "button" + ] + widget_kwargs["fields_back"] = others - widget_kwargs['name'] = "%s%s%s" % (category_name, SAT_PARAM_SEPARATOR, param_name) + widget_kwargs["name"] = "%s%s%s" % ( + category_name, + SAT_PARAM_SEPARATOR, + param_name, + ) param_ui.addWidget(type_, **widget_kwargs) @@ -399,14 +429,21 @@ @return: a tuple (options, selected_value) """ if len(param.getElementsByTagName("options")) > 0: - raise exceptions.DataError(_("The 'options' tag is not allowed in parameter of type 'list'!")) + raise exceptions.DataError( + _("The 'options' tag is not allowed in parameter of type 'list'!") + ) elems = param.getElementsByTagName("option") if len(elems) == 0: return [] options = [elem.getAttribute("value") for elem in elems] - selected = [elem.getAttribute("value") for elem in elems if elem.getAttribute("selected") == 'true'] + selected = [ + elem.getAttribute("value") + for elem in elems + if elem.getAttribute("selected") == "true" + ] return (options, selected) + def _paramsGetListJids(param): """Retrive jids from a jids_list element. @@ -415,9 +452,11 @@ @return: a list of jids """ elems = param.getElementsByTagName("jid") - jids = [elem.firstChild.data for elem in elems - if elem.firstChild is not None - and elem.firstChild.nodeType == elem.TEXT_NODE] + jids = [ + elem.firstChild.data + for elem in elems + if elem.firstChild is not None and elem.firstChild.nodeType == elem.TEXT_NODE + ] return jids @@ -426,6 +465,7 @@ class Element(object): """ Base XMLUI element """ + type = None def __init__(self, xmlui, parent=None): @@ -436,7 +476,7 @@ """ assert self.type is not None self.children = [] - if not hasattr(self, 'elem'): + if not hasattr(self, "elem"): self.elem = parent.xmlui.doc.createElement(self.type) self.xmlui = xmlui if parent is not None: @@ -457,7 +497,8 @@ class TopElement(Element): """ Main XML Element """ - type = 'top' + + type = "top" def __init__(self, xmlui): self.elem = xmlui.doc.documentElement @@ -466,7 +507,8 @@ class TabElement(Element): """ Used by TabsContainer to give name and label to tabs.""" - type = 'tab' + + type = "tab" def __init__(self, parent, name, label, selected=False): """ @@ -479,8 +521,8 @@ if not isinstance(parent, TabsContainer): raise exceptions.DataError(_("TabElement must be a child of TabsContainer")) super(TabElement, self).__init__(parent.xmlui, parent) - self.elem.setAttribute('name', name) - self.elem.setAttribute('label', label) + self.elem.setAttribute("name", name) + self.elem.setAttribute("label", label) if selected: self.setSelected(selected) @@ -489,31 +531,34 @@ @param selected (bool): set to True to select this tab """ - self.elem.setAttribute('selected', 'true' if selected else 'false') + self.elem.setAttribute("selected", "true" if selected else "false") class FieldBackElement(Element): """ Used by ButtonWidget to indicate which field have to be sent back """ - type = 'field_back' + + type = "field_back" def __init__(self, parent, name): assert isinstance(parent, ButtonWidget) super(FieldBackElement, self).__init__(parent.xmlui, parent) - self.elem.setAttribute('name', name) + self.elem.setAttribute("name", name) class InternalFieldElement(Element): """ Used by internal callbacks to indicate which fields are manipulated """ - type = 'internal_field' + + type = "internal_field" def __init__(self, parent, name): super(InternalFieldElement, self).__init__(parent.xmlui, parent) - self.elem.setAttribute('name', name) + self.elem.setAttribute("name", name) class InternalDataElement(Element): """ Used by internal callbacks to retrieve extra data """ - type = 'internal_data' + + type = "internal_data" def __init__(self, parent, children): super(InternalDataElement, self).__init__(parent.xmlui, parent) @@ -524,7 +569,8 @@ class OptionElement(Element): """" Used by ListWidget to specify options """ - type = 'option' + + type = "option" def __init__(self, parent, option, selected=False): """ @@ -541,15 +587,16 @@ value, label = option else: raise NotImplementedError - self.elem.setAttribute('value', value) - self.elem.setAttribute('label', label) + self.elem.setAttribute("value", value) + self.elem.setAttribute("label", label) if selected: - self.elem.setAttribute('selected', 'true') + self.elem.setAttribute("selected", "true") class JidElement(Element): """" Used by JidsListWidget to specify jids""" - type = 'jid' + + type = "jid" def __init__(self, parent, jid_): """ @@ -569,7 +616,8 @@ class RowElement(Element): """" Used by AdvancedListContainer """ - type = 'row' + + type = "row" def __init__(self, parent): assert isinstance(parent, AdvancedListContainer) @@ -577,13 +625,14 @@ if parent.next_row_idx is not None: if parent.auto_index: raise exceptions.DataError(_("Can't set row index if auto_index is True")) - self.elem.setAttribute('index', parent.next_row_idx) + self.elem.setAttribute("index", parent.next_row_idx) parent.next_row_idx = None class HeaderElement(Element): """" Used by AdvancedListContainer """ - type = 'header' + + type = "header" def __init__(self, parent, name=None, label=None, description=None): """ @@ -595,11 +644,11 @@ assert isinstance(parent, AdvancedListContainer) super(HeaderElement, self).__init__(parent.xmlui, parent) if name: - self.elem.setAttribute('name', name) + self.elem.setAttribute("name", name) if label: - self.elem.setAttribute('label', label) + self.elem.setAttribute("label", label) if description: - self.elem.setAttribute('description', description) + self.elem.setAttribute("description", description) ## Containers ## @@ -607,6 +656,7 @@ class Container(Element): """ And Element which contains other ones and has a layout """ + type = None def __init__(self, xmlui, parent=None): @@ -615,9 +665,9 @@ @param xmlui: XMLUI instance @parent: parent element or None """ - self.elem = xmlui.doc.createElement('container') + self.elem = xmlui.doc.createElement("container") super(Container, self).__init__(xmlui, parent) - self.elem.setAttribute('type', self.type) + self.elem.setAttribute("type", self.type) def getParentContainer(self): """ Return first parent container @@ -625,8 +675,7 @@ @return: parent container or None """ current = self.parent - while(not isinstance(current, (Container)) and - current is not None): + while not isinstance(current, (Container)) and current is not None: current = current.parent return current @@ -676,9 +725,21 @@ class AdvancedListContainer(Container): """A list which can contain other widgets, headers, etc""" + type = "advanced_list" - def __init__(self, xmlui, callback_id=None, name=None, headers=None, items=None, columns=None, selectable='no', auto_index=False, parent=None): + def __init__( + self, + xmlui, + callback_id=None, + name=None, + headers=None, + items=None, + columns=None, + selectable="no", + auto_index=False, + parent=None, + ): """Create an advanced list @param headers: optional headers information @@ -691,7 +752,7 @@ @param auto_index: if True, indexes will be generated by frontends, starting from 0 @return: created element """ - assert selectable in ('no', 'single') + assert selectable in ("no", "single") if not items and columns is None: raise exceptions.DataError(_("either items or columns need do be filled")) if headers is None: @@ -706,17 +767,19 @@ self.current_row = None if headers: if len(headers) != self._columns: - raise exceptions.DataError(_("Headers lenght doesn't correspond to columns")) + raise exceptions.DataError( + _("Headers lenght doesn't correspond to columns") + ) self.addHeaders(headers) if items: self.addItems(items) - self.elem.setAttribute('columns', str(self._columns)) + self.elem.setAttribute("columns", str(self._columns)) if callback_id is not None: - self.elem.setAttribute('callback', callback_id) - self.elem.setAttribute('selectable', selectable) + self.elem.setAttribute("callback", callback_id) + self.elem.setAttribute("selectable", selectable) self.auto_index = auto_index if auto_index: - self.elem.setAttribute('auto_index', 'true') + self.elem.setAttribute("auto_index", "true") self.next_row_idx = None def addHeaders(self, headers): @@ -770,14 +833,18 @@ @param name: name of the element or None @param parent: parent element or None """ - self.elem = xmlui.doc.createElement('widget') + self.elem = xmlui.doc.createElement("widget") super(Widget, self).__init__(xmlui, parent) if name: - self.elem.setAttribute('name', name) + self.elem.setAttribute("name", name) if name in xmlui.named_widgets: - raise exceptions.ConflictError(_(u'A widget with the name "{name}" already exists.').format(name=name)) + raise exceptions.ConflictError( + _(u'A widget with the name "{name}" already exists.').format( + name=name + ) + ) xmlui.named_widgets[name] = self - self.elem.setAttribute('type', self.type) + self.elem.setAttribute("type", self.type) def setInternalCallback(self, callback, fields, data_elts=None): """Set an internal UI callback when the widget value is changed. @@ -797,7 +864,7 @@ @param fields (list): a list of widget names (string) @param data_elts (list[Element]): extra data elements """ - self.elem.setAttribute('internal_callback', callback) + self.elem.setAttribute("internal_callback", callback) if fields: for field in fields: InternalFieldElement(self, field) @@ -807,16 +874,18 @@ class EmptyWidget(Widget): """Place holder widget""" - type = 'empty' + + type = "empty" class TextWidget(Widget): """Used for blob of text""" - type = 'text' + + type = "text" def __init__(self, xmlui, value, name=None, parent=None): super(TextWidget, self).__init__(xmlui, name, parent) - value_elt = self.xmlui.doc.createElement('value') + value_elt = self.xmlui.doc.createElement("value") text = self.xmlui.doc.createTextNode(value) value_elt.appendChild(text) self.elem.appendChild(value_elt) @@ -831,29 +900,31 @@ used most of time to display the desciption or name of the next widget """ - type = 'label' + + type = "label" def __init__(self, xmlui, label, name=None, parent=None): super(LabelWidget, self).__init__(xmlui, name, parent) - self.elem.setAttribute('value', label) + self.elem.setAttribute("value", label) class JidWidget(Widget): """Used to display a Jabber ID, some specific methods can be added""" - type = 'jid' + + type = "jid" def __init__(self, xmlui, jid, name=None, parent=None): super(JidWidget, self).__init__(xmlui, name, parent) try: - self.elem.setAttribute('value', jid.full()) + self.elem.setAttribute("value", jid.full()) except AttributeError: - self.elem.setAttribute('value', unicode(jid)) + self.elem.setAttribute("value", unicode(jid)) class DividerWidget(Widget): - type = 'divider' + type = "divider" - def __init__(self, xmlui, style='line', name=None, parent=None): + def __init__(self, xmlui, style="line", name=None, parent=None): """ Create a divider @param xmlui: XMLUI instance @@ -868,7 +939,7 @@ """ super(DividerWidget, self).__init__(xmlui, name, parent) - self.elem.setAttribute('style', style) + self.elem.setAttribute("style", style) ### Inputs ### @@ -879,19 +950,20 @@ used mainly in forms """ + def __init__(self, xmlui, name=None, parent=None, read_only=False): super(InputWidget, self).__init__(xmlui, name, parent) if read_only: - self.elem.setAttribute('read_only', 'true') + self.elem.setAttribute("read_only", "true") class StringWidget(InputWidget): - type = 'string' + type = "string" def __init__(self, xmlui, value=None, name=None, parent=None, read_only=False): super(StringWidget, self).__init__(xmlui, name, parent, read_only=read_only) if value: - value_elt = self.xmlui.doc.createElement('value') + value_elt = self.xmlui.doc.createElement("value") text = self.xmlui.doc.createTextNode(value) value_elt.appendChild(text) self.elem.appendChild(value_elt) @@ -902,20 +974,20 @@ class PasswordWidget(StringWidget): - type = 'password' + type = "password" class TextBoxWidget(StringWidget): - type = 'textbox' + type = "textbox" class JidInputWidget(StringWidget): - type = 'jid_input' + type = "jid_input" # TODO handle min and max values class IntWidget(StringWidget): - type = 'int' + type = "int" def __init__(self, xmlui, value=0, name=None, parent=None, read_only=False): try: @@ -926,25 +998,27 @@ class BoolWidget(InputWidget): - type = 'bool' + type = "bool" - def __init__(self, xmlui, value='false', name=None, parent=None, read_only=False): + def __init__(self, xmlui, value="false", name=None, parent=None, read_only=False): if isinstance(value, bool): - value = 'true' if value else 'false' - elif value == '0': - value = 'false' - elif value == '1': - value = 'true' - if value not in ('true', 'false'): + value = "true" if value else "false" + elif value == "0": + value = "false" + elif value == "1": + value = "true" + if value not in ("true", "false"): raise exceptions.DataError(_("Value must be 0, 1, false or true")) super(BoolWidget, self).__init__(xmlui, name, parent, read_only=read_only) - self.elem.setAttribute('value', value) + self.elem.setAttribute("value", value) class ButtonWidget(Widget): - type = 'button' + type = "button" - def __init__(self, xmlui, callback_id, value=None, fields_back=None, name=None, parent=None): + def __init__( + self, xmlui, callback_id, value=None, fields_back=None, name=None, parent=None + ): """Add a button @param callback_id: callback which will be called if button is pressed @@ -956,18 +1030,20 @@ if fields_back is None: fields_back = [] super(ButtonWidget, self).__init__(xmlui, name, parent) - self.elem.setAttribute('callback', callback_id) + self.elem.setAttribute("callback", callback_id) if value: - self.elem.setAttribute('value', value) + self.elem.setAttribute("value", value) for field in fields_back: FieldBackElement(self, field) class ListWidget(InputWidget): - type = 'list' - STYLES = (u'multi', u'noselect', u'extensible', u'reducible', u'inline') + type = "list" + STYLES = (u"multi", u"noselect", u"extensible", u"reducible", u"inline") - def __init__(self, xmlui, options, selected=None, styles=None, name=None, parent=None): + def __init__( + self, xmlui, options, selected=None, styles=None, name=None, parent=None + ): """ @param xmlui @@ -991,8 +1067,12 @@ styles = set() else: styles = set(styles) - if u'noselect' in styles and (u'multi' in styles or selected): - raise exceptions.DataError(_(u'"multi" flag and "selected" option are not compatible with "noselect" flag')) + if u"noselect" in styles and (u"multi" in styles or selected): + raise exceptions.DataError( + _( + u'"multi" flag and "selected" option are not compatible with "noselect" flag' + ) + ) if not options: # we can have no options if we get a submitted data form # but we can't use submitted values directly, @@ -1018,7 +1098,7 @@ if not styles.issubset(self.STYLES): raise exceptions.DataError(_(u"invalid styles")) for style in styles: - self.elem.setAttribute(style, 'yes') + self.elem.setAttribute(style, "yes") # TODO: check flags incompatibily (noselect and multi) like in __init__ def setStyle(self, style): @@ -1028,13 +1108,15 @@ def value(self): """Return the value of first selected option""" for child in self.elem.childNodes: - if child.tagName == u'option' and child.getAttribute(u'selected') == u'true': - return child.getAttribute(u'value') - return u'' + if child.tagName == u"option" and child.getAttribute(u"selected") == u"true": + return child.getAttribute(u"value") + return u"" + class JidsListWidget(InputWidget): """A list of text or jids where elements can be added/removed or modified""" - type = 'jids_list' + + type = "jids_list" def __init__(self, xmlui, jids, styles=None, name=None, parent=None): """ @@ -1047,12 +1129,12 @@ """ super(JidsListWidget, self).__init__(xmlui, name, parent) styles = set() if styles is None else set(styles) - if not styles.issubset([]): # TODO + if not styles.issubset([]): # TODO raise exceptions.DataError(_("invalid styles")) for style in styles: - self.elem.setAttribute(style, 'yes') + self.elem.setAttribute(style, "yes") if not jids: - log.debug('empty jids list') + log.debug("empty jids list") else: self.addJids(jids) @@ -1066,11 +1148,14 @@ class DialogElement(Element): """Main dialog element """ - type = 'dialog' + + type = "dialog" def __init__(self, parent, type_, level=None): if not isinstance(parent, TopElement): - raise exceptions.DataError(_("DialogElement must be a direct child of TopElement")) + raise exceptions.DataError( + _("DialogElement must be a direct child of TopElement") + ) super(DialogElement, self).__init__(parent.xmlui, parent) self.elem.setAttribute(C.XMLUI_DATA_TYPE, type_) self.elem.setAttribute(C.XMLUI_DATA_LVL, level or C.XMLUI_DATA_LVL_DEFAULT) @@ -1078,11 +1163,14 @@ class MessageElement(Element): """Element with the instruction message""" + type = C.XMLUI_DATA_MESS def __init__(self, parent, message): if not isinstance(parent, DialogElement): - raise exceptions.DataError(_("MessageElement must be a direct child of DialogElement")) + raise exceptions.DataError( + _("MessageElement must be a direct child of DialogElement") + ) super(MessageElement, self).__init__(parent.xmlui, parent) message_txt = self.xmlui.doc.createTextNode(message) self.elem.appendChild(message_txt) @@ -1090,24 +1178,30 @@ class ButtonsElement(Element): """Buttons element which indicate which set to use""" - type = 'buttons' + + type = "buttons" def __init__(self, parent, set_): if not isinstance(parent, DialogElement): - raise exceptions.DataError(_("ButtonsElement must be a direct child of DialogElement")) + raise exceptions.DataError( + _("ButtonsElement must be a direct child of DialogElement") + ) super(ButtonsElement, self).__init__(parent.xmlui, parent) - self.elem.setAttribute('set', set_) + self.elem.setAttribute("set", set_) class FileElement(Element): """File element used for FileDialog""" - type = 'file' + + type = "file" def __init__(self, parent, type_): if not isinstance(parent, DialogElement): - raise exceptions.DataError(_("FileElement must be a direct child of DialogElement")) + raise exceptions.DataError( + _("FileElement must be a direct child of DialogElement") + ) super(FileElement, self).__init__(parent.xmlui, parent) - self.elem.setAttribute('type', type_) + self.elem.setAttribute("type", type_) ## XMLUI main class @@ -1116,7 +1210,15 @@ class XMLUI(object): """This class is used to create a user interface (form/window/parameters/etc) using SàT XML""" - def __init__(self, panel_type="window", container="vertical", dialog_opt=None, title=None, submit_id=None, session_id=None): + def __init__( + self, + panel_type="window", + container="vertical", + dialog_opt=None, + title=None, + submit_id=None, + session_id=None, + ): """Init SàT XML Panel @param panel_type: one of @@ -1162,15 +1264,23 @@ @param session_id: use to keep a session attached to the dialog, must be returned by frontends @attribute named_widgets(dict): map from name to widget """ - self._introspect() # FIXME: why doing that on each XMLUI ? should be done once - if panel_type not in [C.XMLUI_WINDOW, C.XMLUI_FORM, C.XMLUI_PARAM, C.XMLUI_POPUP, C.XMLUI_DIALOG]: + self._introspect() # FIXME: why doing that on each XMLUI ? should be done once + if panel_type not in [ + C.XMLUI_WINDOW, + C.XMLUI_FORM, + C.XMLUI_PARAM, + C.XMLUI_POPUP, + C.XMLUI_DIALOG, + ]: raise exceptions.DataError(_("Unknown panel type [%s]") % panel_type) if panel_type == C.XMLUI_FORM and submit_id is None: raise exceptions.DataError(_("form XMLUI need a submit_id")) if not isinstance(container, basestring): raise exceptions.DataError(_("container argument must be a string")) if dialog_opt is not None and panel_type != C.XMLUI_DIALOG: - raise exceptions.DataError(_("dialog_opt can only be used with dialog panels")) + raise exceptions.DataError( + _("dialog_opt can only be used with dialog panels") + ) self.type = panel_type impl = minidom.getDOMImplementation() @@ -1197,11 +1307,11 @@ for obj in globals().values(): try: if issubclass(obj, Widget): - if obj.__name__ == 'Widget': + if obj.__name__ == "Widget": continue self._widgets[obj.type] = obj elif issubclass(obj, Container): - if obj.__name__ == 'Container': + if obj.__name__ == "Container": continue self._containers[obj.type] = obj except TypeError: @@ -1211,20 +1321,26 @@ self.doc.unlink() def __getattr__(self, name): - if name.startswith("add") and name not in ('addWidget',): # addWidgetName(...) create an instance of WidgetName + if name.startswith("add") and name not in ( + "addWidget", + ): # addWidgetName(...) create an instance of WidgetName if self.type == C.XMLUI_DIALOG: raise exceptions.InternalError(_("addXXX can't be used with dialogs")) class_name = name[3:] + "Widget" if class_name in globals(): cls = globals()[class_name] if issubclass(cls, Widget): + def createWidget(*args, **kwargs): if "parent" not in kwargs: kwargs["parent"] = self.current_container - if "name" not in kwargs and issubclass(cls, InputWidget): # name can be given as first argument or in keyword arguments for InputWidgets + if "name" not in kwargs and issubclass( + cls, InputWidget + ): # name can be given as first argument or in keyword arguments for InputWidgets args = list(args) kwargs["name"] = args.pop(0) return cls(self, *args, **kwargs) + return createWidget return object.__getattribute__(self, name) @@ -1270,8 +1386,13 @@ def _createDialog(self, dialog_opt): dialog_type = dialog_opt.setdefault(C.XMLUI_DATA_TYPE, C.XMLUI_DIALOG_MESSAGE) - if dialog_type in [C.XMLUI_DIALOG_CONFIRM, C.XMLUI_DIALOG_FILE] and self.submit_id is None: - raise exceptions.InternalError(_("Submit ID must be filled for this kind of dialog")) + if ( + dialog_type in [C.XMLUI_DIALOG_CONFIRM, C.XMLUI_DIALOG_FILE] + and self.submit_id is None + ): + raise exceptions.InternalError( + _("Submit ID must be filled for this kind of dialog") + ) top_element = TopElement(self) level = dialog_opt.get(C.XMLUI_DATA_LVL) dialog_elt = DialogElement(top_element, dialog_type, level) @@ -1309,9 +1430,15 @@ @param container: either container type (container it then created), or an Container instance""" if isinstance(container, basestring): - self.current_container = self._createContainer(container, self.current_container.getParentContainer() or self.main_container, **kwargs) + self.current_container = self._createContainer( + container, + self.current_container.getParentContainer() or self.main_container, + **kwargs + ) else: - self.current_container = self.main_container if container is None else container + self.current_container = ( + self.main_container if container is None else container + ) assert isinstance(self.current_container, Container) return self.current_container @@ -1331,7 +1458,8 @@ # Some sugar for XMLUI dialogs -def note(message, title='', level=C.XMLUI_DATA_LVL_INFO): + +def note(message, title="", level=C.XMLUI_DATA_LVL_INFO): """sugar to easily create a Note Dialog @param message(unicode): body of the note @@ -1339,19 +1467,22 @@ @param level(unicode): one of C.XMLUI_DATA_LVL_* @return(XMLUI): instance of XMLUI """ - note_xmlui = XMLUI(C.XMLUI_DIALOG, dialog_opt={ - C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, - C.XMLUI_DATA_MESS: message, - C.XMLUI_DATA_LVL: level}, - title=title - ) + note_xmlui = XMLUI( + C.XMLUI_DIALOG, + dialog_opt={ + C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, + C.XMLUI_DATA_MESS: message, + C.XMLUI_DATA_LVL: level, + }, + title=title, + ) return note_xmlui -def quickNote(host, client, message, title='', level=C.XMLUI_DATA_LVL_INFO): +def quickNote(host, client, message, title="", level=C.XMLUI_DATA_LVL_INFO): """more sugar to do the whole note process""" note_ui = note(message, title, level) - host.actionNew({'xmlui': note_ui.toXml()}, profile=client.profile) + host.actionNew({"xmlui": note_ui.toXml()}, profile=client.profile) def deferredUI(host, xmlui, chained=False): @@ -1363,7 +1494,7 @@ useful when backend is in a series of dialogs with an ui @return (D(data)): a deferred which fire the data """ - assert xmlui.submit_id == '' + assert xmlui.submit_id == "" xmlui_d = defer.Deferred() def onSubmit(data, profile): @@ -1373,7 +1504,15 @@ xmlui.submit_id = host.registerCallback(onSubmit, with_data=True, one_shot=True) return xmlui_d -def deferXMLUI(host, xmlui, action_extra=None, security_limit=C.NO_SECURITY_LIMIT, chained=False, profile=C.PROF_KEY_NONE): + +def deferXMLUI( + host, + xmlui, + action_extra=None, + security_limit=C.NO_SECURITY_LIMIT, + chained=False, + profile=C.PROF_KEY_NONE, +): """Create a deferred linked to XMLUI @param xmlui(XMLUI): instance of the XMLUI @@ -1387,14 +1526,29 @@ @return (data): a deferred which fire the data """ xmlui_d = deferredUI(host, xmlui, chained) - action_data = {'xmlui': xmlui.toXml()} + action_data = {"xmlui": xmlui.toXml()} if action_extra is not None: action_data.update(action_extra) - host.actionNew(action_data, security_limit=security_limit, keep_id=xmlui.submit_id, profile=profile) + host.actionNew( + action_data, + security_limit=security_limit, + keep_id=xmlui.submit_id, + profile=profile, + ) return xmlui_d -def deferDialog(host, message, title=u'Please confirm', type_=C.XMLUI_DIALOG_CONFIRM, options=None, - action_extra=None, security_limit=C.NO_SECURITY_LIMIT, chained=False, profile=C.PROF_KEY_NONE): + +def deferDialog( + host, + message, + title=u"Please confirm", + type_=C.XMLUI_DIALOG_CONFIRM, + options=None, + action_extra=None, + security_limit=C.NO_SECURITY_LIMIT, + chained=False, + profile=C.PROF_KEY_NONE, +): """Create a submitable dialog and manage it with a deferred @param message(unicode): message to display @@ -1410,22 +1564,26 @@ @return (dict): Deferred dict """ assert profile is not None - dialog_opt = {'type': type_, 'message': message} + dialog_opt = {"type": type_, "message": message} if options is not None: dialog_opt.update(options) - dialog = XMLUI(C.XMLUI_DIALOG, title=title, dialog_opt=dialog_opt, submit_id='') + dialog = XMLUI(C.XMLUI_DIALOG, title=title, dialog_opt=dialog_opt, submit_id="") return deferXMLUI(host, dialog, action_extra, security_limit, chained, profile) + def deferConfirm(*args, **kwargs): """call deferDialog and return a boolean instead of the whole data dict""" d = deferDialog(*args, **kwargs) - d.addCallback(lambda data: C.bool(data['answer'])) + d.addCallback(lambda data: C.bool(data["answer"])) return d + # Misc other funtions + class ElementParser(object): """callable class to parse XML string into Element""" + # XXX: Found at http://stackoverflow.com/questions/2093400/how-to-create-twisted-words-xish-domish-element-entirely-from-raw-xml/2095942#2095942 def _escapeHTML(self, matchobj): @@ -1438,7 +1596,7 @@ return unichr(htmlentitydefs.name2codepoint[entity]) except KeyError: log.warning(u"removing unknown entity {}".format(entity)) - return u'' + return u"" def __call__(self, raw_xml, force_spaces=False, namespace=None): """ @@ -1473,9 +1631,9 @@ parser.DocumentEndEvent = onEnd tmp = domish.Element((None, "s")) if force_spaces: - raw_xml = raw_xml.replace('\n', ' ').replace('\t', ' ') + raw_xml = raw_xml.replace("\n", " ").replace("\t", " ") tmp.addRawXml(raw_xml) - parser.parse(tmp.toXml().encode('utf-8')) + parser.parse(tmp.toXml().encode("utf-8")) top_elt = self.result.firstChildElement() # we now can check if there was a unique element on the top # and remove our wrapping <div/> is this was the case @@ -1497,7 +1655,8 @@ data.append(child.wholeText) return u"".join(data) -def findAll(elt, namespaces=None, names=None, ): + +def findAll(elt, namespaces=None, names=None): """Find child element at any depth matching criteria @param elt(domish.Element): top parent of the elements to find @@ -1508,14 +1667,16 @@ @return ((G)domish.Element): found elements """ if isinstance(namespaces, basestring): - namespaces=tuple((namespaces,)) + namespaces = tuple((namespaces,)) if isinstance(names, basestring): - names=tuple((names,)) + names = tuple((names,)) for child in elt.elements(): - if (domish.IElement.providedBy(child) and - (not names or child.name in names) and - (not namespaces or child.uri in namespaces)): + if ( + domish.IElement.providedBy(child) + and (not names or child.name in names) + and (not namespaces or child.uri in namespaces) + ): yield child for found in findAll(child, namespaces, names): yield found