diff options
Diffstat (limited to 'sleekxmpp')
-rw-r--r-- | sleekxmpp/plugins/xep_0004/stanza/field.py | 4 | ||||
-rw-r--r-- | sleekxmpp/plugins/xep_0004/stanza/form.py | 42 | ||||
-rw-r--r-- | sleekxmpp/thirdparty/__init__.py | 1 | ||||
-rw-r--r-- | sleekxmpp/thirdparty/orderedset.py | 89 | ||||
-rw-r--r-- | sleekxmpp/xmlstream/stanzabase.py | 2 |
5 files changed, 123 insertions, 15 deletions
diff --git a/sleekxmpp/plugins/xep_0004/stanza/field.py b/sleekxmpp/plugins/xep_0004/stanza/field.py index 51f85995..73e48758 100644 --- a/sleekxmpp/plugins/xep_0004/stanza/field.py +++ b/sleekxmpp/plugins/xep_0004/stanza/field.py @@ -13,8 +13,9 @@ class FormField(ElementBase): namespace = 'jabber:x:data' name = 'field' plugin_attrib = 'field' + plugin_multi_attrib = 'fields' interfaces = set(('answer', 'desc', 'required', 'value', - 'options', 'label', 'type', 'var')) + 'label', 'type', 'var')) sub_interfaces = set(('desc',)) plugin_tag_map = {} plugin_attrib_map = {} @@ -165,6 +166,7 @@ class FieldOption(ElementBase): plugin_attrib = 'option' interfaces = set(('label', 'value')) sub_interfaces = set(('value',)) + plugin_multi_attrib = 'options' FormField.addOption = FormField.add_option diff --git a/sleekxmpp/plugins/xep_0004/stanza/form.py b/sleekxmpp/plugins/xep_0004/stanza/form.py index 1d733760..3dcc7821 100644 --- a/sleekxmpp/plugins/xep_0004/stanza/form.py +++ b/sleekxmpp/plugins/xep_0004/stanza/form.py @@ -9,7 +9,7 @@ import copy import logging -from sleekxmpp.thirdparty import OrderedDict +from sleekxmpp.thirdparty import OrderedDict, OrderedSet from sleekxmpp.xmlstream import ElementBase, ET from sleekxmpp.plugins.xep_0004.stanza import FormField @@ -22,8 +22,7 @@ class Form(ElementBase): namespace = 'jabber:x:data' name = 'x' plugin_attrib = 'form' - interfaces = set(('fields', 'instructions', 'items', - 'reported', 'title', 'type', 'values')) + interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', )) sub_interfaces = set(('title',)) form_types = set(('cancel', 'form', 'result', 'submit')) @@ -43,12 +42,12 @@ class Form(ElementBase): @property def field(self): - return self['fields'] + return self.get_fields() def set_type(self, ftype): self._set_attr('type', ftype) if ftype == 'submit': - fields = self['fields'] + fields = self.get_fields() for var in fields: field = fields[var] del field['type'] @@ -74,7 +73,8 @@ class Form(ElementBase): field['desc'] = desc field['required'] = required if options is not None: - field['options'] = options + for option in options: + field.add_option(**option) else: del field['type'] self.append(field) @@ -169,7 +169,7 @@ class Form(ElementBase): def get_reported(self): fields = OrderedDict() xml = self.xml.findall('{%s}reported/{%s}field' % (self.namespace, - FormField.namespace)) + FormField.namespace)) for field in xml: field = FormField(xml=field) fields[field['var']] = field @@ -177,7 +177,7 @@ class Form(ElementBase): def get_values(self): values = OrderedDict() - fields = self['fields'] + fields = self.get_fields() for var in fields: values[var] = fields[var]['value'] return values @@ -219,17 +219,33 @@ class Form(ElementBase): self.add_item(item) def set_reported(self, reported): + """ + This either needs a dictionary or dictionaries or a dictionary of form fields. + :param reported: + :return: + """ for var in reported: field = reported[var] - field['var'] = var - self.add_reported(var, **field) + + if isinstance(field, dict): + self.add_reported(**field) + else: + reported = self.xml.find('{%s}reported' % self.namespace) + if reported is None: + reported = ET.Element('{%s}reported' % self.namespace) + self.xml.append(reported) + + fieldXML = ET.Element('{%s}field' % FormField.namespace) + reported.append(fieldXML) + new_field = FormField(xml=fieldXML) + new_field.values = field.values def set_values(self, values): - fields = self['fields'] + fields = self.get_fields() for field in values: - if field not in fields: + if field not in self.get_fields(): fields[field] = self.add_field(var=field) - fields[field]['value'] = values[field] + self.get_fields()[field]['value'] = values[field] def merge(self, other): new = copy.copy(self) diff --git a/sleekxmpp/thirdparty/__init__.py b/sleekxmpp/thirdparty/__init__.py index 2a1db717..337598ac 100644 --- a/sleekxmpp/thirdparty/__init__.py +++ b/sleekxmpp/thirdparty/__init__.py @@ -10,3 +10,4 @@ except: from sleekxmpp.thirdparty import socks from sleekxmpp.thirdparty.mini_dateutil import tzutc, tzoffset, parse_iso +from sleekxmpp.thirdparty.orderedset import OrderedSet diff --git a/sleekxmpp/thirdparty/orderedset.py b/sleekxmpp/thirdparty/orderedset.py new file mode 100644 index 00000000..f6642db3 --- /dev/null +++ b/sleekxmpp/thirdparty/orderedset.py @@ -0,0 +1,89 @@ +# Copyright (c) 2009 Raymond Hettinger +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation files +# (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, +# publish, distribute, sublicense, and/or sell copies of the Software, +# and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +import collections + +class OrderedSet(collections.MutableSet): + + def __init__(self, iterable=None): + self.end = end = [] + end += [None, end, end] # sentinel node for doubly linked list + self.map = {} # key --> [key, prev, next] + if iterable is not None: + self |= iterable + + def __len__(self): + return len(self.map) + + def __contains__(self, key): + return key in self.map + + def add(self, key): + if key not in self.map: + end = self.end + curr = end[1] + curr[2] = end[1] = self.map[key] = [key, curr, end] + + def discard(self, key): + if key in self.map: + key, prev, next = self.map.pop(key) + prev[2] = next + next[1] = prev + + def __iter__(self): + end = self.end + curr = end[2] + while curr is not end: + yield curr[0] + curr = curr[2] + + def __reversed__(self): + end = self.end + curr = end[1] + while curr is not end: + yield curr[0] + curr = curr[1] + + def pop(self, last=True): + if not self: + raise KeyError('set is empty') + key = self.end[1][0] if last else self.end[2][0] + self.discard(key) + return key + + def __repr__(self): + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, list(self)) + + def __eq__(self, other): + if isinstance(other, OrderedSet): + return len(self) == len(other) and list(self) == list(other) + return set(self) == set(other) + + +if __name__ == '__main__': + s = OrderedSet('abracadaba') + t = OrderedSet('simsalabim') + print(s | t) + print(s & t) + print(s - t)
\ No newline at end of file diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index 11c8dd67..c2e0f718 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -563,7 +563,7 @@ class ElementBase(object): .. versionadded:: 1.0-Beta1 """ - values = {} + values = OrderedDict() values['lang'] = self['lang'] for interface in self.interfaces: if isinstance(self[interface], JID): |