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.plugins = {}
self.iterables = []
self.idx = 0
self._index = 0
if parent is None:
self.parent = None
else:
@ -510,34 +510,78 @@ class ElementBase(object):
# Everything matched.
return True
@property
def attrib(self): #backwards compatibility
return self
def find(self, xpath):
"""
Find an XML object in this stanza given an XPath expression.
def __iter__(self):
self.idx = 0
return self
Exposes ElementTree interface for backwards compatibility.
def __bool__(self): #python 3.x
return True
Note that matching on attribute values is not supported in Python 2.6
or Python 3.1
def __nonzero__(self): #python 2.x
return True
Arguments:
xpath -- An XPath expression matching a single desired element.
"""
return self.xml.find(xpath)
def __next__(self):
self.idx += 1
if self.idx > len(self.iterables):
self.idx = 0
raise StopIteration
return self.iterables[self.idx - 1]
def findall(self, xpath):
"""
Find multiple XML objects in this stanza given an XPath expression.
def next(self):
return self.__next__()
Exposes ElementTree interface for backwards compatibility.
def __len__(self):
return len(self.iterables)
Note that matching on attribute values is not supported in Python 2.6
or Python 3.1.
Arguments:
xpath -- An XPath expression matching multiple desired elements.
"""
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)
@ -547,52 +591,53 @@ class ElementBase(object):
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):
return self.xml.findall(xpath)
def __eq__(self, other):
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 appendxml(self, xml):
"""
Append an XML object to the stanza's XML.
The added XML will not be included in the list of
iterable substanzas.
Arguments:
xml -- The XML object to add to the stanza.
"""
self.xml.append(xml)
return self
def __copy__(self):
return self.__class__(xml=copy.deepcopy(self.xml), parent=self.parent)
def pop(self, index=0):
"""
Remove and return the last substanza in the list of
iterable substanzas.
def __str__(self):
return tostring(self.xml, xmlns='', stanza_ns=self.namespace)
Allows stanza objects to be used like lists.
def __repr__(self):
return self.__str__()
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):
"""
@ -610,10 +655,85 @@ class ElementBase(object):
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):
name = 'stanza'