Merge branch 'refactor_forms' into add_xep_0122
This commit is contained in:
commit
7059400020
5 changed files with 159 additions and 6 deletions
|
@ -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,7 +22,7 @@ class Form(ElementBase):
|
|||
namespace = 'jabber:x:data'
|
||||
name = 'x'
|
||||
plugin_attrib = 'form'
|
||||
interfaces = set(('instructions', 'items', 'reported', 'title', 'type', ))
|
||||
interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', ))
|
||||
sub_interfaces = set(('title',))
|
||||
form_types = set(('cancel', 'form', 'result', 'submit'))
|
||||
|
||||
|
@ -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
|
||||
|
@ -219,10 +219,26 @@ 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.get_fields()
|
||||
|
|
1
sleekxmpp/thirdparty/__init__.py
vendored
1
sleekxmpp/thirdparty/__init__.py
vendored
|
@ -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
|
||||
|
|
89
sleekxmpp/thirdparty/orderedset.py
vendored
Normal file
89
sleekxmpp/thirdparty/orderedset.py
vendored
Normal file
|
@ -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)
|
|
@ -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):
|
||||
|
|
|
@ -197,5 +197,52 @@ class TestDataForms(SleekTest):
|
|||
<x xmlns="jabber:x:data" type="cancel" />
|
||||
""")
|
||||
|
||||
def testReported(self):
|
||||
msg = self.Message()
|
||||
form = msg['form']
|
||||
form['type'] = 'result'
|
||||
|
||||
form.add_reported(var='f1', ftype='text-single', label='Username')
|
||||
|
||||
form.add_item({'f1': 'username@example.org'})
|
||||
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<x xmlns="jabber:x:data" type="result">
|
||||
<reported>
|
||||
<field var="f1" type="text-single" label="Username" />
|
||||
</reported>
|
||||
<item>
|
||||
<field var="f1">
|
||||
<value>username@example.org</value>
|
||||
</field>
|
||||
</item>
|
||||
</x>
|
||||
</message>
|
||||
""")
|
||||
|
||||
def testSetReported(self):
|
||||
msg = self.Message()
|
||||
form = msg['form']
|
||||
form['type'] = 'result'
|
||||
|
||||
reported = {'f1': {
|
||||
'var': 'f1',
|
||||
'type': 'text-single',
|
||||
'label': 'Username'
|
||||
}}
|
||||
|
||||
form.set_reported(reported)
|
||||
|
||||
self.check(msg, """
|
||||
<message>
|
||||
<x xmlns="jabber:x:data" type="result">
|
||||
<reported>
|
||||
<field var="f1" type="text-single" label="Username" />
|
||||
</reported>
|
||||
</x>
|
||||
</message>
|
||||
""")
|
||||
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataForms)
|
||||
|
|
Loading…
Reference in a new issue