Ordering of fields with schema interface subclassing
Hi, Suppose I have an interface IDerived that's derived from an interface IBase, overriding a field from it.
from zope.interface import Interface from zope.schema import TextLine
class IBase(Interface): ... a = TextLine(title=u"a") ... b = TextLine(title=u"b") ... c = TextLine(title=u"c")
class IDerived(IBase): ... b = TextLine(title=u"b", default=u"B")
In this case, the field ordering of zope.schema means that I'll get something like this:
from zope.schema import getFieldNamesInOrder getFieldNamesInOrder(IDerived) ['a', 'c', 'b']
I had rather expected the order to be ['a', 'b', 'c']. That is, I would expect a field that overrides a field from a base interface, to retain the base interface's order. One way to fix this is to do:
IDerived['b'].order = IBase['b'].order
Now both will have the same order, of course. So, I'm wondering: - Is it harmful to have two fields with the same order like this when they share a name? - Should this be the default behavior when deriving interfaces from one another like this? If the latter is desirable, I'd be willing to help find a way to implement it. The field order is just an ever-increasing int that's set in Field.__init__(), so we'd probably need some after-the-fact fixing up of fields. One way to do that would be to fire an event at the end of InterfaceClass.__init__() and have an event handler to fix the order, though that'd make zope.interface dependent on zope.event which is probably not desirable. We could simulate the event handler in another way, of course, e.g. by having the interface initialiser loop over its attributes and see if they support e.g. an IOrderAware interface and call a method on it, and have Field implement this. What do you think? Martin
On Sun, 2008-07-20 at 18:22 +0100, Martin Aspeli wrote:
Hi,
Suppose I have an interface IDerived that's derived from an interface IBase, overriding a field from it.
from zope.interface import Interface from zope.schema import TextLine
class IBase(Interface): ... a = TextLine(title=u"a") ... b = TextLine(title=u"b") ... c = TextLine(title=u"c")
class IDerived(IBase): ... b = TextLine(title=u"b", default=u"B")
In this case, the field ordering of zope.schema means that I'll get something like this:
from zope.schema import getFieldNamesInOrder getFieldNamesInOrder(IDerived) ['a', 'c', 'b']
I had rather expected the order to be ['a', 'b', 'c']. That is, I would expect a field that overrides a field from a base interface, to retain the base interface's order.
One way to fix this is to do:
IDerived['b'].order = IBase['b'].order
Now both will have the same order, of course.
So, I'm wondering:
- Is it harmful to have two fields with the same order like this when they share a name?
"Sharing" a name sounds weird. The attribute get's overriden and the field from the base class isn't considered anymore.
- Should this be the default behavior when deriving interfaces from one another like this?
I'm not sure about that. IIRC the general issue here is that there's a *global* counter involved when determining the order of fields.
If the latter is desirable, I'd be willing to help find a way to implement it. The field order is just an ever-increasing int that's set in Field.__init__(), so we'd probably need some after-the-fact fixing up of fields.
Ah. Sounds like my memories are right.
One way to do that would be to fire an event at the end of InterfaceClass.__init__() and have an event handler to fix the order, though that'd make zope.interface dependent on zope.event which is probably not desirable.
We could simulate the event handler in another way, of course, e.g. by having the interface initialiser loop over its attributes and see if they support e.g. an IOrderAware interface and call a method on it, and have Field implement this.
Another way to to that would be to derive the `order` attribute of a using the MRO (is that the mechanism relevant here?) of the class it belongs to find inheritance ancestors and use their `order` attribute instead. That behaviour could also easily be controlled using a flag of the field. Christian -- Christian Theune · ct@gocept.com gocept gmbh & co. kg · forsterstraße 29 · 06112 halle (saale) · germany http://gocept.com · tel +49 345 1229889 7 · fax +49 345 1229889 1 Zope and Plone consulting and development
Hi Christian,
So, I'm wondering:
- Is it harmful to have two fields with the same order like this when they share a name?
"Sharing" a name sounds weird. The attribute get's overriden and the field from the base class isn't considered anymore.
Right, that's what I meant. Except that if you access IBase['b'].order it will be equal to IDerived['b'].order, though I don't think this is necessarily a problem.
- Should this be the default behavior when deriving interfaces from one another like this?
I'm not sure about that. IIRC the general issue here is that there's a *global* counter involved when determining the order of fields.
Right, but I think the end result is counter-intuitive in the case I'm describing. I don't know if the global (non-thread-safe) was just the easiest implementation or a deliberate choice.
One way to do that would be to fire an event at the end of InterfaceClass.__init__() and have an event handler to fix the order, though that'd make zope.interface dependent on zope.event which is probably not desirable.
We could simulate the event handler in another way, of course, e.g. by having the interface initialiser loop over its attributes and see if they support e.g. an IOrderAware interface and call a method on it, and have Field implement this.
Another way to to that would be to derive the `order` attribute of a using the MRO (is that the mechanism relevant here?) of the class it belongs to find inheritance ancestors and use their `order` attribute instead. That behaviour could also easily be controlled using a flag of the field.
Yes, this could be an option. So, 'order' becomes a property and looks up (any maybe caches) the order from its base interfaces - loop through base interface in MRO, look for field with same name, if so, return its 'raw' order, otherwise, return self's 'raw' order. I'd be willing to implement this (if I can find the time) if people agree that it's a good idea. Martin -- Author of `Professional Plone Development`, a book for developers who want to work with Plone. See http://martinaspeli.net/plone-book
participants (2)
-
Christian Theune -
Martin Aspeli