Updated the remaining ElementBase methods.

Remaining ElementBase todos:
    Write the class documentation for ElementBase.
    Write unit tests for the __magic__ methods.
This commit is contained in:
Lance Stout 2010-08-26 10:08:22 -04:00
parent a3580dcef9
commit 10298a6eab

View file

@ -55,7 +55,7 @@ class ElementBase(object):
self.xml = xml self.xml = xml
self.plugins = {} self.plugins = {}
self.iterables = [] self.iterables = []
self.idx = 0 self._index = 0
if parent is None: if parent is None:
self.parent = None self.parent = None
else: else:
@ -510,89 +510,134 @@ class ElementBase(object):
# Everything matched. # Everything matched.
return True return True
@property def find(self, xpath):
def attrib(self): #backwards compatibility """
return self Find an XML object in this stanza given an XPath expression.
def __iter__(self): Exposes ElementTree interface for backwards compatibility.
self.idx = 0
return self
def __bool__(self): #python 3.x Note that matching on attribute values is not supported in Python 2.6
return True or Python 3.1
def __nonzero__(self): #python 2.x Arguments:
return True xpath -- An XPath expression matching a single desired element.
"""
def __next__(self): return self.xml.find(xpath)
self.idx += 1
if self.idx > len(self.iterables):
self.idx = 0
raise StopIteration
return self.iterables[self.idx - 1]
def next(self):
return self.__next__()
def __len__(self):
return len(self.iterables)
def append(self, item):
if not isinstance(item, ElementBase):
if type(item) == XML_TYPE:
return self.appendxml(item)
else:
raise TypeError
self.xml.append(item.xml)
self.iterables.append(item)
return self
def pop(self, idx=0):
aff = self.iterables.pop(idx)
self.xml.remove(aff.xml)
return aff
def get(self, key, defaultvalue=None):
value = self[key]
if value is None or value == '':
return defaultvalue
return value
def keys(self):
out = []
out += [x for x in self.interfaces]
out += [x for x in self.plugins]
if self.iterables:
out.append('substanzas')
return tuple(out)
def find(self, xpath): # for backwards compatiblity, expose elementtree interface
return self.xml.find(xpath)
def findall(self, xpath): def findall(self, xpath):
return self.xml.findall(xpath) """
Find multiple XML objects in this stanza given an XPath expression.
def __eq__(self, other): Exposes ElementTree interface for backwards compatibility.
if not isinstance(other, ElementBase):
return False Note that matching on attribute values is not supported in Python 2.6
values = self.getStanzaValues() or Python 3.1.
for key in other:
if key not in values or values[key] != other[key]: Arguments:
return False xpath -- An XPath expression matching multiple desired elements.
return True """
return self.xml.findall(xpath)
def get(self, key, default=None):
"""
Return the value of a stanza interface. If the found value is None
or an empty string, return the supplied default value.
Allows stanza objects to be used like dictionaries.
Arguments:
key -- The name of the stanza interface to check.
default -- Value to return if the stanza interface has a value
of None or "". Will default to returning None.
"""
value = self[key]
if value is None or value == '':
return default
return value
def keys(self):
"""
Return the names of all stanza interfaces provided by the
stanza object.
Allows stanza objects to be used like dictionaries.
"""
out = []
out += [x for x in self.interfaces]
out += [x for x in self.plugins]
if self.iterables:
out.append('substanzas')
return tuple(out)
def append(self, item):
"""
Append either an XML object or a substanza to this stanza object.
If a substanza object is appended, it will be added to the list
of iterable stanzas.
Allows stanza objects to be used like lists.
Arguments:
item -- Either an XML object or a stanza object to add to
this stanza's contents.
"""
if not isinstance(item, ElementBase):
if type(item) == XML_TYPE:
return self.appendxml(item)
else:
raise TypeError
self.xml.append(item.xml)
self.iterables.append(item)
return self
def appendxml(self, xml): def appendxml(self, xml):
self.xml.append(xml) """
return self Append an XML object to the stanza's XML.
def __copy__(self): The added XML will not be included in the list of
return self.__class__(xml=copy.deepcopy(self.xml), parent=self.parent) iterable substanzas.
def __str__(self): Arguments:
return tostring(self.xml, xmlns='', stanza_ns=self.namespace) xml -- The XML object to add to the stanza.
"""
self.xml.append(xml)
return self
def __repr__(self): def pop(self, index=0):
return self.__str__() """
Remove and return the last substanza in the list of
iterable substanzas.
Allows stanza objects to be used like lists.
Arguments:
index -- The index of the substanza to remove.
"""
substanza = self.iterables.pop(index)
self.xml.remove(substanza.xml)
return substanza
def next(self):
"""
Return the next iterable substanza.
"""
return self.__next__()
@property
def attrib(self):
"""
DEPRECATED
For backwards compatibility, stanza.attrib returns the stanza itself.
Older implementations of stanza objects used XML objects directly,
requiring the use of .attrib to access attribute values.
Use of the dictionary syntax with the stanza object itself for
accessing stanza interfaces is preferred.
"""
return self
def _fix_ns(self, xpath): def _fix_ns(self, xpath):
""" """
@ -610,10 +655,85 @@ class ElementBase(object):
return "/".join(map(fix_ns, xpath.split("/"))) return "/".join(map(fix_ns, xpath.split("/")))
def __eq__(self, other):
"""
Compare the stanza object with another to test for equality.
Stanzas are equal if their interfaces return the same values,
and if they are both instances of ElementBase.
Arguments:
other -- The stanza object to compare against.
"""
if not isinstance(other, ElementBase):
return False
values = self.getStanzaValues()
for key in other:
if key not in values or values[key] != other[key]:
return False
return True
def __bool__(self):
"""
Stanza objects should be treated as True in boolean contexts.
Python 3.x version.
"""
return True
def __nonzero__(self):
"""
Stanza objects should be treated as True in boolean contexts.
Python 2.x version.
"""
return True
def __len__(self):
"""
Return the number of iterable substanzas contained in this stanza.
"""
return len(self.iterables)
def __iter__(self):
"""
Return an iterator object for iterating over the stanza's substanzas.
The iterator is the stanza object itself. Attempting to use two
iterators on the same stanza at the same time is discouraged.
"""
self._index = 0
return self
def __next__(self):
"""
Return the next iterable substanza.
"""
self._index += 1
if self._index > len(self.iterables):
self._index = 0
raise StopIteration
return self.iterables[self._index - 1]
def __copy__(self):
"""
Return a copy of the stanza object that does not share the same
underlying XML object.
"""
return self.__class__(xml=copy.deepcopy(self.xml), parent=self.parent)
def __str__(self):
"""
Return a string serialization of the underlying XML object.
"""
return tostring(self.xml, xmlns='', stanza_ns=self.namespace)
def __repr__(self):
"""
Use the stanza's serialized XML as its representation.
"""
return self.__str__()
#def __del__(self): #prevents garbage collection of reference cycle
# if self.parent is not None:
# self.parent.xml.remove(self.xml)
class StanzaBase(ElementBase): class StanzaBase(ElementBase):
name = 'stanza' name = 'stanza'