diff options
Diffstat (limited to 'sleekxmpp/xmlstream/stanzabase.py')
-rw-r--r-- | sleekxmpp/xmlstream/stanzabase.py | 273 |
1 files changed, 160 insertions, 113 deletions
diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py index 6851333f..f4d66aa8 100644 --- a/sleekxmpp/xmlstream/stanzabase.py +++ b/sleekxmpp/xmlstream/stanzabase.py @@ -20,7 +20,7 @@ from sleekxmpp.xmlstream.tostring import tostring XML_TYPE = type(ET.Element('xml')) -def registerStanzaPlugin(stanza, plugin): +def register_stanza_plugin(stanza, plugin): """ Associate a stanza object as a plugin for another stanza. @@ -33,6 +33,10 @@ def registerStanzaPlugin(stanza, plugin): stanza.plugin_tag_map[tag] = plugin +# To maintain backwards compatibility for now, preserve the camel case name. +registerStanzaPlugin = register_stanza_plugin + + class ElementBase(object): """ @@ -78,9 +82,9 @@ class ElementBase(object): ... plugin_attrib = "custom" The plugin stanza class must be associated with its intended - container stanza by using registerStanzaPlugin as so: + container stanza by using register_stanza_plugin as so: - >>> registerStanzaPlugin(Message, MessagePlugin) + >>> register_stanza_plugin(Message, MessagePlugin) The plugin may then be accessed as if it were built-in to the parent stanza. @@ -115,38 +119,43 @@ class ElementBase(object): parent -- The parent stanza of this stanza. plugins -- A map of enabled plugin names with the initialized plugin stanza objects. + values -- A dictionary of the stanza's interfaces + and interface values, including plugins. Methods: - setup -- Initialize the stanza's XML contents. - enable -- Instantiate a stanza plugin. Alias for initPlugin. - initPlugin -- Instantiate a stanza plugin. - getStanzaValues -- Return a dictionary of stanza interfaces and - their values. - setStanzaValues -- Set stanza interface values given a dictionary of - interfaces and values. - __getitem__ -- Return the value of a stanza interface. - __setitem__ -- Set the value of a stanza interface. - __delitem__ -- Remove the value of a stanza interface. - _setAttr -- Set an attribute value of the main stanza element. - _delAttr -- Remove an attribute from the main stanza element. - _getAttr -- Return an attribute's value from the main - stanza element. - _getSubText -- Return the text contents of a subelement. - _setSubText -- Set the text contents of a subelement. - _delSub -- Remove a subelement. - match -- Compare the stanza against an XPath expression. - find -- Return subelement matching an XPath expression. - findall -- Return subelements matching an XPath expression. - get -- Return the value of a stanza interface, with an - optional default value. - keys -- Return the set of interface names accepted by - the stanza. - append -- Add XML content or a substanza to the stanza. - appendxml -- Add XML content to the stanza. - pop -- Remove a substanza. - next -- Return the next iterable substanza. - _fix_ns -- Apply the stanza's namespace to non-namespaced - elements in an XPath expression. + setup -- Initialize the stanza's XML contents. + enable -- Instantiate a stanza plugin. + Alias for init_plugin. + init_plugin -- Instantiate a stanza plugin. + _get_stanza_values -- Return a dictionary of stanza interfaces and + their values. + _set_stanza_values -- Set stanza interface values given a dictionary + of interfaces and values. + __getitem__ -- Return the value of a stanza interface. + __setitem__ -- Set the value of a stanza interface. + __delitem__ -- Remove the value of a stanza interface. + _set_attr -- Set an attribute value of the main + stanza element. + _del_attr -- Remove an attribute from the main + stanza element. + _get_attr -- Return an attribute's value from the main + stanza element. + _get_sub_text -- Return the text contents of a subelement. + _set_sub_ext -- Set the text contents of a subelement. + _del_sub -- Remove a subelement. + match -- Compare the stanza against an XPath expression. + find -- Return subelement matching an XPath expression. + findall -- Return subelements matching an XPath expression. + get -- Return the value of a stanza interface, with an + optional default value. + keys -- Return the set of interface names accepted by + the stanza. + append -- Add XML content or a substanza to the stanza. + appendxml -- Add XML content to the stanza. + pop -- Remove a substanza. + next -- Return the next iterable substanza. + _fix_ns -- Apply the stanza's namespace to non-namespaced + elements in an XPath expression. """ name = 'stanza' @@ -167,6 +176,18 @@ class ElementBase(object): xml -- Initialize the stanza with optional existing XML. parent -- Optional stanza object that contains this stanza. """ + # To comply with PEP8, method names now use underscores. + # Deprecated method names are re-mapped for backwards compatibility. + self.initPlugin = self.init_plugin + self._getAttr = self._get_attr + self._setAttr = self._set_attr + self._delAttr = self._del_attr + self._getSubText = self._get_sub_text + self._setSubText = self._set_sub_text + self._delSub = self._del_sub + self.getStanzaValues = self._get_stanza_values + self.setStanzaValues = self._set_stanza_values + self.xml = xml self.plugins = {} self.iterables = [] @@ -176,6 +197,9 @@ class ElementBase(object): else: self.parent = weakref.ref(parent) + ElementBase.values = property(ElementBase._get_stanza_values, + ElementBase._set_stanza_values) + if self.setup(xml): # If we generated our own XML, then everything is ready. return @@ -227,14 +251,14 @@ class ElementBase(object): """ Enable and initialize a stanza plugin. - Alias for initPlugin. + Alias for init_plugin. Arguments: attrib -- The stanza interface for the plugin. """ - return self.initPlugin(attrib) + return self.init_plugin(attrib) - def initPlugin(self, attrib): + def init_plugin(self, attrib): """ Enable and initialize a stanza plugin. @@ -246,7 +270,7 @@ class ElementBase(object): self.plugins[attrib] = plugin_class(parent=self) return self - def getStanzaValues(self): + def _get_stanza_values(self): """ Return a dictionary of the stanza's interface values. @@ -256,18 +280,18 @@ class ElementBase(object): for interface in self.interfaces: values[interface] = self[interface] for plugin, stanza in self.plugins.items(): - values[plugin] = stanza.getStanzaValues() + values[plugin] = stanza._get_stanza_values() if self.iterables: iterables = [] for stanza in self.iterables: - iterables.append(stanza.getStanzaValues()) + iterables.append(stanza._get_stanza_values()) iterables[-1].update({ '__childtag__': "{%s}%s" % (stanza.namespace, stanza.name)}) values['substanzas'] = iterables return values - def setStanzaValues(self, values): + def _set_stanza_values(self, values): """ Set multiple stanza interface values using a dictionary. @@ -287,15 +311,15 @@ class ElementBase(object): subclass.name) if subdict['__childtag__'] == child_tag: sub = subclass(parent=self) - sub.setStanzaValues(subdict) + sub._set_stanza_values(subdict) self.iterables.append(sub) break elif interface in self.interfaces: self[interface] = value elif interface in self.plugin_attrib_map: if interface not in self.plugins: - self.initPlugin(interface) - self.plugins[interface].setStanzaValues(value) + self.init_plugin(interface) + self.plugins[interface]._set_stanza_values(value) return self def __getitem__(self, attrib): @@ -307,17 +331,18 @@ class ElementBase(object): 'Message contents' Stanza interfaces are typically mapped directly to the underlying XML - object, but can be overridden by the presence of a getAttrib method - (or getFoo where the interface is named foo, etc). + object, but can be overridden by the presence of a get_attrib method + (or get_foo where the interface is named foo, etc). The search order for interface value retrieval for an interface named 'foo' is: 1. The list of substanzas. - 2. The result of calling getFoo. - 3. The contents of the foo subelement, if foo is a sub interface. - 4. The value of the foo attribute of the XML object. - 5. The plugin named 'foo' - 6. An empty string. + 2. The result of calling get_foo. + 3. The result of calling getFoo. + 4. The contents of the foo subelement, if foo is a sub interface. + 5. The value of the foo attribute of the XML object. + 6. The plugin named 'foo' + 7. An empty string. Arguments: attrib -- The name of the requested stanza interface. @@ -325,17 +350,20 @@ class ElementBase(object): if attrib == 'substanzas': return self.iterables elif attrib in self.interfaces: - get_method = "get%s" % attrib.title() + get_method = "get_%s" % attrib.lower() + get_method2 = "get%s" % attrib.title() if hasattr(self, get_method): return getattr(self, get_method)() + elif hasattr(self, get_method2): + return getattr(self, get_method2)() else: if attrib in self.sub_interfaces: - return self._getSubText(attrib) + return self._get_sub_text(attrib) else: - return self._getAttr(attrib) + return self._get_attr(attrib) elif attrib in self.plugin_attrib_map: if attrib not in self.plugins: - self.initPlugin(attrib) + self.init_plugin(attrib) return self.plugins[attrib] else: return '' @@ -350,18 +378,19 @@ class ElementBase(object): 'Hi!' Stanza interfaces are typically mapped directly to the underlying XML - object, but can be overridden by the presence of a setAttrib method - (or setFoo where the interface is named foo, etc). + object, but can be overridden by the presence of a set_attrib method + (or set_foo where the interface is named foo, etc). The effect of interface value assignment for an interface named 'foo' will be one of: 1. Delete the interface's contents if the value is None. - 2. Call setFoo, if it exists. - 3. Set the text of a foo element, if foo is in sub_interfaces. - 4. Set the value of a top level XML attribute name foo. - 5. Attempt to pass value to a plugin named foo using the plugin's + 2. Call set_foo, if it exists. + 3. Call setFoo, if it exists. + 4. Set the text of a foo element, if foo is in sub_interfaces. + 5. Set the value of a top level XML attribute name foo. + 6. Attempt to pass value to a plugin named foo using the plugin's foo interface. - 6. Do nothing. + 7. Do nothing. Arguments: attrib -- The name of the stanza interface to modify. @@ -369,19 +398,22 @@ class ElementBase(object): """ if attrib in self.interfaces: if value is not None: - set_method = "set%s" % attrib.title() + set_method = "set_%s" % attrib.lower() + set_method2 = "set%s" % attrib.title() if hasattr(self, set_method): getattr(self, set_method)(value,) + elif hasattr(self, set_method2): + getattr(self, set_method2)(value,) else: if attrib in self.sub_interfaces: - return self._setSubText(attrib, text=value) + return self._set_sub_text(attrib, text=value) else: - self._setAttr(attrib, value) + self._set_attr(attrib, value) else: self.__delitem__(attrib) elif attrib in self.plugin_attrib_map: if attrib not in self.plugins: - self.initPlugin(attrib) + self.init_plugin(attrib) self.plugins[attrib][attrib] = value return self @@ -398,29 +430,33 @@ class ElementBase(object): '' Stanza interfaces are typically mapped directly to the underlyig XML - object, but can be overridden by the presence of a delAttrib method - (or delFoo where the interface is named foo, etc). + object, but can be overridden by the presence of a del_attrib method + (or del_foo where the interface is named foo, etc). The effect of deleting a stanza interface value named foo will be one of: - 1. Call delFoo, if it exists. - 2. Delete foo element, if foo is in sub_interfaces. - 3. Delete top level XML attribute named foo. - 4. Remove the foo plugin, if it was loaded. - 5. Do nothing. + 1. Call del_foo, if it exists. + 2. Call delFoo, if it exists. + 3. Delete foo element, if foo is in sub_interfaces. + 4. Delete top level XML attribute named foo. + 5. Remove the foo plugin, if it was loaded. + 6. Do nothing. Arguments: attrib -- The name of the affected stanza interface. """ if attrib in self.interfaces: - del_method = "del%s" % attrib.title() + del_method = "del_%s" % attrib.lower() + del_method2 = "del%s" % attrib.title() if hasattr(self, del_method): getattr(self, del_method)() + elif hasattr(self, del_method2): + getattr(self, del_method2)() else: if attrib in self.sub_interfaces: - return self._delSub(attrib) + return self._del_sub(attrib) else: - self._delAttr(attrib) + self._del_attr(attrib) elif attrib in self.plugin_attrib_map: if attrib in self.plugins: xml = self.plugins[attrib].xml @@ -428,7 +464,7 @@ class ElementBase(object): self.xml.remove(xml) return self - def _setAttr(self, name, value): + def _set_attr(self, name, value): """ Set the value of a top level attribute of the underlying XML object. @@ -445,7 +481,7 @@ class ElementBase(object): else: self.xml.attrib[name] = value - def _delAttr(self, name): + def _del_attr(self, name): """ Remove a top level attribute of the underlying XML object. @@ -455,7 +491,7 @@ class ElementBase(object): if name in self.xml.attrib: del self.xml.attrib[name] - def _getAttr(self, name, default=''): + def _get_attr(self, name, default=''): """ Return the value of a top level attribute of the underlying XML object. @@ -471,7 +507,7 @@ class ElementBase(object): """ return self.xml.attrib.get(name, default) - def _getSubText(self, name, default=''): + def _get_sub_text(self, name, default=''): """ Return the text contents of a sub element. @@ -491,7 +527,7 @@ class ElementBase(object): else: return stanza.text - def _setSubText(self, name, text=None, keep=False): + def _set_sub_text(self, name, text=None, keep=False): """ Set the text contents of a sub element. @@ -513,7 +549,7 @@ class ElementBase(object): element = self.xml.find(name) if not text and not keep: - return self._delSub(name) + return self._del_sub(name) if element is None: # We need to add the element. If the provided name was @@ -534,7 +570,7 @@ class ElementBase(object): element.text = text return element - def _delSub(self, name, all=False): + def _del_sub(self, name, all=False): """ Remove sub elements that match the given name or XPath. @@ -819,13 +855,13 @@ class ElementBase(object): return False # Check that this stanza is a superset of the other stanza. - values = self.getStanzaValues() + values = self._get_stanza_values() for key in other.keys(): if key not in values or values[key] != other[key]: return False # Check that the other stanza is a superset of this stanza. - values = other.getStanzaValues() + values = other._get_stanza_values() for key in self.keys(): if key not in values or values[key] != self[key]: return False @@ -932,23 +968,23 @@ class StanzaBase(ElementBase): tag -- The namespaced version of the stanza's name. Methods: - setType -- Set the type of the stanza. - getTo -- Return the stanza recipients JID. - setTo -- Set the stanza recipient's JID. - getFrom -- Return the stanza sender's JID. - setFrom -- Set the stanza sender's JID. - getPayload -- Return the stanza's XML contents. - setPayload -- Append to the stanza's XML contents. - delPayload -- Remove the stanza's XML contents. - clear -- Reset the stanza's XML contents. - reply -- Reset the stanza and modify the 'to' and 'from' - attributes to prepare for sending a reply. - error -- Set the stanza's type to 'error'. - unhandled -- Callback for when the stanza is not handled by a - stream handler. - exception -- Callback for if an exception is raised while - handling the stanza. - send -- Send the stanza using the stanza's stream. + set_type -- Set the type of the stanza. + get_to -- Return the stanza recipients JID. + set_to -- Set the stanza recipient's JID. + get_from -- Return the stanza sender's JID. + set_from -- Set the stanza sender's JID. + get_payload -- Return the stanza's XML contents. + set_payload -- Append to the stanza's XML contents. + del_payload -- Remove the stanza's XML contents. + clear -- Reset the stanza's XML contents. + reply -- Reset the stanza and modify the 'to' and 'from' + attributes to prepare for sending a reply. + error -- Set the stanza's type to 'error'. + unhandled -- Callback for when the stanza is not handled by a + stream handler. + exception -- Callback for if an exception is raised while + handling the stanza. + send -- Send the stanza using the stanza's stream. """ name = 'stanza' @@ -970,6 +1006,17 @@ class StanzaBase(ElementBase): sfrom -- Optional string or JID object of the sender's JID. sid -- Optional ID value for the stanza. """ + # To comply with PEP8, method names now use underscores. + # Deprecated method names are re-mapped for backwards compatibility. + self.setType = self.set_type + self.getTo = self.get_to + self.setTo = self.set_to + self.getFrom = self.get_from + self.setFrom = self.set_from + self.getPayload = self.get_payload + self.setPayload = self.set_payload + self.delPayload = self.del_payload + self.stream = stream if stream is not None: self.namespace = stream.default_ns @@ -982,7 +1029,7 @@ class StanzaBase(ElementBase): self['from'] = sfrom self.tag = "{%s}%s" % (self.namespace, self.name) - def setType(self, value): + def set_type(self, value): """ Set the stanza's 'type' attribute. @@ -995,37 +1042,37 @@ class StanzaBase(ElementBase): self.xml.attrib['type'] = value return self - def getTo(self): + def get_to(self): """Return the value of the stanza's 'to' attribute.""" - return JID(self._getAttr('to')) + return JID(self._get_attr('to')) - def setTo(self, value): + def set_to(self, value): """ Set the 'to' attribute of the stanza. Arguments: value -- A string or JID object representing the recipient's JID. """ - return self._setAttr('to', str(value)) + return self._set_attr('to', str(value)) - def getFrom(self): + def get_from(self): """Return the value of the stanza's 'from' attribute.""" - return JID(self._getAttr('from')) + return JID(self._get_attr('from')) - def setFrom(self, value): + def set_from(self, value): """ Set the 'from' attribute of the stanza. Arguments: from -- A string or JID object representing the sender's JID. """ - return self._setAttr('from', str(value)) + return self._set_attr('from', str(value)) - def getPayload(self): + def get_payload(self): """Return a list of XML objects contained in the stanza.""" return self.xml.getchildren() - def setPayload(self, value): + def set_payload(self, value): """ Add XML content to the stanza. @@ -1039,7 +1086,7 @@ class StanzaBase(ElementBase): self.append(val) return self - def delPayload(self): + def del_payload(self): """Remove the XML contents of the stanza.""" self.clear() return self |