[lxml-dev] Objectify nodes can't have real attributes

Stefan Behnel stefan_ml at behnel.de
Wed Feb 14 19:33:14 CET 2007


Hi Tres,

Tres Seaver wrote:
> For a project I'm currently working on, I want to create nodes by
> parsing an XML document, and then bind a Zope3 interface to the node, in
> order to allow for compmonent lookup.  With classic elementtree nodes,
> and with lxml.etree nodes, I can.  However, the nodes produced by
> lxml.objectify don't allow this.

I never used zope.interfaces, so maybe I'm not the right person to try an
answer here, but the problem is that lxml.objectify has to do all sorts of
tricks to make an element look like a list and the like. Just like
zope.interfaces does all sorts of tricks (metaclasses and the like) to allow
things like "implements()" in a class body. Both don't seem to work that well
together...

The main problem is that assignments to __provides__ end up in the child
lookup machinery of ObjectifiedElement's __getattr__. Maybe you could try to
override __getattr__ and intercept the assignment?

Anyway, here is a pretty hackish third trick that updates the interfaces
provided by an object once you used "implements()" to assign a first one.

Setting things up as before::

  >>> class MyTreeNode(ObjectifiedElement):
  ...     implements(IFoo)

  >>> lookup = ObjectifyElementClassLookup(tree_class=MyTreeNode)
  >>> parser = XMLParser(remove_blank_text=True)
  >>> parser.setElementClassLookup(lookup)
  >>> node = XML('<node/>', parser)
  >>> node.__provides__
  <implementedBy __builtin__.MyPropertiedTreeNode>
  >>> IFoo.providedBy(node)
  True
  >>> IBar.providedBy(node)
  False
  >>> before = node.__provides__
  >>> list(before)
  [<InterfaceClass __builtin__.IFoo>]

Now, this is true hackery, but at least it looks like it works::

  >>> node.__provides__._Specification__setBases(
  ...       [IBar] + list(node.__provides__))
  >>> after = node.__provides__
  >>> list(after)
  [<InterfaceClass __builtin__.IBar>, <InterfaceClass __builtin__.IFoo>]
  >>> IBar.providedBy(node)
  True

If you prefer, you can wrap it in a function that looks less suspicious. :)

Thanks for the doctest, BTW - without it, I'd be clueless what you were
talking about. One small fix:

>   >>> class MySlottedTreeNode(ObjectifiedElement):
>   ...     __slots__ = ('__provides__',)
>   ...     implements(IFoo)
>   >>> lookup = ObjectifyElementClassLookup(tree_class=MyTreeNode)

Should be "tree_class=MySlottedTreeNode", I assume. But it still wouldn't
work, slots don't seem to help here. Properties/descriptors should make a
difference here, but zope.interfaces already uses them in a couple of places,
so they may be hard to apply.

Stefan



More information about the lxml-dev mailing list