Skip to content
This repository has been archived by the owner on Jan 14, 2024. It is now read-only.

Commit

Permalink
change aioxmpp.xso.Collector to be an etree rather than a list
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianriese committed Dec 11, 2017
1 parent 95c0a64 commit 642ef89
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 23 deletions.
35 changes: 21 additions & 14 deletions aioxmpp/xso/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,17 @@ def to_sax(self, instance, dest):
class Collector(_PropBase):
"""
When assigned to a class’ attribute, it collects all children which are not
known to any other descriptor into a list of XML subtrees.
known to any other descriptor into a XML trees. The root node has the tag
of the XSO class it pertains to.
The default is fixed at an empty list.
The default is fixed to the emtpy root node.
.. verisonchanged:: 0.10
Before the subtrees where collected in a list. This was changed to an
ElementTree to allow using XPath over all collected elements.
Assignment is now forbidden.
.. automethod:: from_events
Expand All @@ -630,12 +638,15 @@ def __get__(self, instance, type_):
xso_query.GetSequenceDescriptor,
)

return instance._xso_contents.setdefault(self, [])
try:
return instance._xso_contents[self]
except KeyError:
res = etree.Element(tag_to_str(instance.TAG))
instance._xso_contents[self] = res
return res

def _set(self, instance, value):
if not isinstance(value, list):
raise TypeError("expected list, but found {}".format(type(value)))
return super()._set(instance, value)
raise AttributeError("Collector attribute cannot be assigned to")

def from_events(self, instance, ev_args, ctx):
"""
Expand All @@ -650,16 +661,14 @@ def from_events(self, instance, ev_args, ctx):
# the start-ev_args in a lxml.etree.Element.

def make_from_args(ev_args, parent):
if parent is not None:
el = etree.SubElement(parent,
tag_to_str((ev_args[0], ev_args[1])))
else:
el = etree.Element(tag_to_str((ev_args[0], ev_args[1])))
el = etree.SubElement(parent,
tag_to_str((ev_args[0], ev_args[1])))
for key, value in ev_args[2].items():
el.set(tag_to_str(key), value)
return el

root_el = make_from_args(ev_args, None)
root_el = make_from_args(ev_args,
self.__get__(instance, type(instance)))
# create an element stack
stack = [root_el]
while stack:
Expand All @@ -684,8 +693,6 @@ def make_from_args(ev_args, parent):
# not in coverage -- this is more like an assertion
raise ValueError(ev_type)

self.__get__(instance, type(instance)).append(root_el)

def to_sax(self, instance, dest):
for node in self.__get__(instance, type(instance)):
lxml.sax.saxify(node, _CollectorContentHandlerFilter(dest))
Expand Down
7 changes: 7 additions & 0 deletions docs/api/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,13 @@ Version 0.10

* :meth:`aioxmpp.structs.LanguageMap.any`

* *Possibly breaking change*: The type of the value of
:class:`aioxmpp.xso.Collector` descriptors was changed from
:class:`list` to :class:`lxml.etree.Element`.

* **Breaking change**: Assignment to :class:`aioxmpp.xso.Collector`
descriptors is now forbidden.

.. _api-changelog-0.9:

Version 0.9
Expand Down
15 changes: 6 additions & 9 deletions tests/xso/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3176,21 +3176,18 @@ def test_from_events(self):
subtree,
result)

def test_assign_enforces_list(self):
def test_assign_raises(self):
class Cls(xso.XSO):
TAG = ("foo", "bar")
children = xso.Collector()

obj = Cls()
with self.assertRaises(TypeError):
with self.assertRaises(AttributeError):
obj.children = 123
with self.assertRaises(TypeError):
with self.assertRaises(AttributeError):
obj.children = "foo"
l = []
obj.children = l
self.assertIs(
l,
obj.children
)
with self.assertRaises(AttributeError):
obj.children = []

def test_to_node(self):
prop = xso.Collector()
Expand Down

0 comments on commit 642ef89

Please sign in to comment.