<?xml version="1.0" encoding="UTF-8" ?>
<rdf:RDF xmlns="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><Project><name>grouparchy.schema</name>
<shortdesc>Grouparchy zope.schema extensions</shortdesc>
<description>;-*-Doctest-*-

============
Field Events
============

EventProperty is a zope.schema FieldProperty that fires an event when
the field is modified and sends the old and new values to the event.

    &gt;&gt;&gt; from zope import interface, schema
    &gt;&gt;&gt; import grouparchy.schema.event
    &gt;&gt;&gt; class IFoo(interface.Interface):
    ...     field = schema.Field()
    &gt;&gt;&gt; class Foo(object):
    ...     interface.implements(IFoo)
    ...     field = grouparchy.schema.event.EventProperty(
    ...         IFoo['field'])
    &gt;&gt;&gt; foo = Foo()

Before configuring a handler for the event nothing will happen::

    &gt;&gt;&gt; foo.field
    &gt;&gt;&gt; foo.field = 'foo'
    &gt;&gt;&gt; foo.field
    'foo'

When we provide a handler for the event, it will be triggered when we
change the value::

    &gt;&gt;&gt; from zope import component
    &gt;&gt;&gt; def handler(event):
    ...     print 'event: %s' % event
    ...     print 'object: %s' % event.object
    ...     print 'event.old: %s' % event.old
    ...     print 'event.new: %s' % event.new
    &gt;&gt;&gt; component.provideHandler(
    ...     handler, (grouparchy.schema.event.IFieldModifiedEvent,))

    &gt;&gt;&gt; foo.field = 'bar'
    event: &lt;grouparchy.schema.event.FieldModifiedEvent object at ...&gt;
    object: &lt;Foo object at ...&gt;
    event.old: foo
    event.new: bar

If the new value is equal to the existing value, the event isn't
triggered::

    &gt;&gt;&gt; foo.field
    'bar'
    &gt;&gt;&gt; foo.field = 'bar'

A different event can also be passed in to the property::

    &gt;&gt;&gt; class FooEvent(grouparchy.schema.event.FieldModifiedEvent):
    ...     pass
    &gt;&gt;&gt; Foo.field = grouparchy.schema.event.EventProperty(
    ...     IFoo['field'], event=FooEvent)
    &gt;&gt;&gt; foo.field = 'foo'
    event: &lt;FooEvent object at ...&gt;
    object: &lt;Foo object at ...&gt;
    event.old: bar
    event.new: foo

If the event is None, no event will be triggered::

    &gt;&gt;&gt; Foo.field = grouparchy.schema.event.EventProperty(
    ...     IFoo['field'], event=None)
    &gt;&gt;&gt; foo.field = 'bar'

Descriptors that subclass EventProperty can override the notify()
method for further control.  For example, the descriptor below will
trigger the event even if the field value is unchanged::

    &gt;&gt;&gt; from zope import event
    &gt;&gt;&gt; class AlwaysEventProperty(
    ...     grouparchy.schema.event.EventProperty):
    ...     def notify(self, instance, new, old):
    ...         event.notify(self.event(instance, new, old))
    &gt;&gt;&gt; Foo.field = AlwaysEventProperty(IFoo['field'])
    &gt;&gt;&gt; foo.field
    'bar'
    &gt;&gt;&gt; foo.field = 'bar'
    event: &lt;grouparchy.schema.event.FieldModifiedEvent object at ...&gt;
    object: &lt;Foo object at ...&gt;
    event.old: bar
    event.new: bar

;-*-Doctest-*-

================
Interface Fields
================

grouparchy.schema.interface includes zope.schema fields for
manipulating the interfaces provided by the context.

An implementation is included for managing the interfaces directly
provided by an object::

    &gt;&gt;&gt; from zope import interface
    &gt;&gt;&gt; from grouparchy.schema.bbb import component_iface
    &gt;&gt;&gt; class IFoo(interface.Interface): pass
    &gt;&gt;&gt; component_iface.provideInterface('', IFoo)

    &gt;&gt;&gt; class Context(object):
    ...     interface.implements(interface.Interface)

    &gt;&gt;&gt; from zope import component
    &gt;&gt;&gt; import grouparchy.schema.interface
    &gt;&gt;&gt; component.provideAdapter(
    ...     factory=grouparchy.schema.interface.DirectlyProvided)

    &gt;&gt;&gt; provider = Context()
    &gt;&gt;&gt; directlyProvided = (
    ...     grouparchy.schema.interface.IDirectlyProvided(
    ...         provider))
    &gt;&gt;&gt; tuple(directlyProvided.directlyProvided)
    ()

    &gt;&gt;&gt; directlyProvided.directlyProvided = (IFoo,)

    &gt;&gt;&gt; tuple(directlyProvided.directlyProvided)
    (&lt;InterfaceClass __builtin__.IFoo&gt;,)

The individual components offer much more flexibility.

Fields
------

InterfacesField describes a set of interfaces provided by the
context.

An InterfacesField must have an InterfaceField or Choice value_type::

    &gt;&gt;&gt; from zope import schema
    &gt;&gt;&gt; grouparchy.schema.interface.InterfacesField()
    Traceback (most recent call last):
    ...
    ValueError: 'value_type' must be an InterfaceField or a Choice.
    &gt;&gt;&gt; grouparchy.schema.interface.InterfacesField(
    ...     value_type=schema.Field())
    Traceback (most recent call last):
    ...
    ValueError: 'value_type' must be an InterfaceField or a Choice.
    &gt;&gt;&gt; field = grouparchy.schema.interface.InterfacesField(
    ...     value_type=schema.InterfaceField())

Valid values are sequences of interfaces::

    &gt;&gt;&gt; foo = object()
    &gt;&gt;&gt; bound = field.bind(foo)
    &gt;&gt;&gt; bound.validate(interface.Interface)
    Traceback (most recent call last):
    ...
    WrongType: (&lt;InterfaceClass zope.interface.Interface&gt;,
                (&lt;type 'set'&gt;, &lt;type 'tuple'&gt;, &lt;type 'list'&gt;))
    &gt;&gt;&gt; bound.validate((None,))
    Traceback (most recent call last):
    ...
    WrongContainedType: []
    &gt;&gt;&gt; bound.validate((interface.Interface,))
    &gt;&gt;&gt; bound.validate([interface.Interface])

Like any Set field, it accepts a Choice field with a vocabulary or
source to narrow the set of interfaces::

    &gt;&gt;&gt; field = grouparchy.schema.interface.InterfacesField(
    ...     value_type=schema.Choice(values=(IFoo,)))
    &gt;&gt;&gt; bound = field.bind(foo)
    &gt;&gt;&gt; bound.validate((interface.Interface,))
    Traceback (most recent call last):
    ...
    WrongContainedType: [&lt;InterfaceClass zope.interface.Interface&gt;]
    &gt;&gt;&gt; bound.validate((IFoo,))

A Choice field cannot circumvent the validation::

    &gt;&gt;&gt; field = grouparchy.schema.interface.InterfacesField(
    ...     value_type=schema.Choice(values=(None,)))
    &gt;&gt;&gt; bound = field.bind(foo)
    &gt;&gt;&gt; bound.validate((None,))
    Traceback (most recent call last):
    ...
    WrongContainedType: []

Sources
-------

A source is also provided which can be used with an interface type
used to determine set of valid interfaces for the field::

    &gt;&gt;&gt; [i for i in grouparchy.schema.interface.InterfacesSource()]
    [&lt;InterfaceClass __builtin__.IFoo&gt;]

Subsets of interfaces can be specified by passing an interface type::

    &gt;&gt;&gt; import zope.interface.interfaces
    &gt;&gt;&gt; class IIBar(zope.interface.interfaces.IInterface): pass
    &gt;&gt;&gt; class IBar(interface.Interface): pass
    &gt;&gt;&gt; component_iface.provideInterface('', IBar)
    &gt;&gt;&gt; component_iface.provideInterface('', IBar, IIBar)
    &gt;&gt;&gt; [i for i in grouparchy.schema.interface.InterfacesSource()]
    [&lt;InterfaceClass __builtin__.IFoo&gt;,
     &lt;InterfaceClass __builtin__.IBar&gt;]
    &gt;&gt;&gt; source = grouparchy.schema.interface.InterfacesSource(IIBar)
    &gt;&gt;&gt; [i for i in source]
    [&lt;InterfaceClass __builtin__.IBar&gt;]

Properties
----------

Two properties are also provided for getting and setting the field
value for either interface objects or dotted names for interfaces::

    &gt;&gt;&gt; class IFoo(interface.Interface):
    ...     all = grouparchy.schema.interface.InterfacesField(
    ...         value_type=schema.InterfaceField())
    ...     bar = grouparchy.schema.interface.InterfacesField(
    ...         value_type=schema.Choice(source=source))
    ...     dotted = grouparchy.schema.interface.InterfacesField(
    ...         value_type=schema.InterfaceField())
    &gt;&gt;&gt; class Foo(object):
    ...     all = grouparchy.schema.interface.InterfacesProperty(
    ...         IFoo['all'])
    ...     bar = grouparchy.schema.interface.InterfacesProperty(
    ...         IFoo['bar'])
    ...     dotted = (
    ...         grouparchy.schema.interface.InterfaceIdentsProperty(
    ...             IFoo['dotted']))
    &gt;&gt;&gt; foo = Foo()

The properties return an IDeclaration::

    &gt;&gt;&gt; isinstance(foo.all, interface.Declaration)
    True

Before the object provides anything, the declarations are empty::

    &gt;&gt;&gt; tuple(foo.all)
    ()
    &gt;&gt;&gt; tuple(foo.bar)
    ()
    &gt;&gt;&gt; tuple(foo.dotted)
    ()

    &gt;&gt;&gt; interface.alsoProvides(foo, interface.Interface)
    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,)
    &gt;&gt;&gt; tuple(foo.dotted)
    ('zope.interface.Interface',)

    &gt;&gt;&gt; interface.alsoProvides(foo, IBar)
    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,
     &lt;InterfaceClass __builtin__.IBar&gt;)
    &gt;&gt;&gt; tuple(foo.bar)
    (&lt;InterfaceClass __builtin__.IBar&gt;,)

    &gt;&gt;&gt; IBar.providedBy(foo)
    True
    &gt;&gt;&gt; foo.bar = ()
    &gt;&gt;&gt; tuple(foo.bar)
    ()
    &gt;&gt;&gt; IBar.providedBy(foo)
    False
    &gt;&gt;&gt; foo.bar = (IBar,)
    &gt;&gt;&gt; tuple(foo.bar)
    (&lt;InterfaceClass __builtin__.IBar&gt;,)
    &gt;&gt;&gt; IBar.providedBy(foo)
    True

The properties need to know how to get the context providing the
interfaces from the object the property lives on.  This is
accomplished with an adapter to the object.  The following checks some
names where the context is often found on adapters and fallsback to
the object itself::

    &gt;&gt;&gt; context = foo.context = Foo()
    &gt;&gt;&gt; interface.alsoProvides(foo.context, interface.Interface)
    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,
     &lt;InterfaceClass __builtin__.IBar&gt;)

    &gt;&gt;&gt; component.provideAdapter(
    ...     grouparchy.schema.interface.getInterfacesContext)

    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,)
    &gt;&gt;&gt; del foo.context
    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,
     &lt;InterfaceClass __builtin__.IBar&gt;)
    &gt;&gt;&gt; foo.object = context
    &gt;&gt;&gt; tuple(foo.all)
    (&lt;InterfaceClass zope.interface.Interface&gt;,)
    &gt;&gt;&gt; del foo.object

Events
------

The properties trigger an event by default::

    &gt;&gt;&gt; import zope.interface.interfaces
    &gt;&gt;&gt; def getIfacesStr(ifaces):
    ...     return ', '.join((str(i) for i in sorted(ifaces)))
    &gt;&gt;&gt; def printInterfacesModified(event):
    ...     print 'Event: %s' % event
    ...     print 'Object: %s' % event.object
    ...     print 'New: ' + getIfacesStr(event.new)
    ...     print 'Old: ' + getIfacesStr(event.old)
    ...     print 'Added: ' + getIfacesStr(event.added)
    ...     print 'Removed: ' + getIfacesStr(event.removed)
    &gt;&gt;&gt; component.provideHandler(
    ...     factory=printInterfacesModified,
    ...     adapts=(
    ...         grouparchy.schema.interface.IInterfacesModified,))

    &gt;&gt;&gt; class IBaz(interface.Interface): pass
    &gt;&gt;&gt; component_iface.provideInterface('', IBaz)
    &gt;&gt;&gt; component_iface.provideInterface('', IBaz, IIBar)

The default events all provide IInterfacesModified, but the event
triggered provides one of the more specific IInterfacesPopulated,
IInterfacesCleared, IInterfacesAdded, IInterfacesRemoved, or
IInterfacesChanged as apporpriate::

    &gt;&gt;&gt; foo.bar = ()
    Event:
    &lt;grouparchy.schema.interface.InterfacesCleared object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: 
    Old: &lt;InterfaceClass __builtin__.IBar&gt;
    Added: 
    Removed: &lt;InterfaceClass __builtin__.IBar&gt;
    &gt;&gt;&gt; foo.bar = (IBar,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesPopulated object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;
    Old: 
    Added: &lt;InterfaceClass __builtin__.IBar&gt;
    Removed: 
    &gt;&gt;&gt; foo.bar = (IBar, IBaz)
    Event:
    &lt;grouparchy.schema.interface.InterfacesAdded object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;,
    &lt;InterfaceClass __builtin__.IBaz&gt;
    Old: &lt;InterfaceClass __builtin__.IBar&gt;
    Added: &lt;InterfaceClass __builtin__.IBaz&gt;
    Removed: 
    &gt;&gt;&gt; foo.bar = (IBar,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesRemoved object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;
    Old: &lt;InterfaceClass __builtin__.IBar&gt;,
    &lt;InterfaceClass __builtin__.IBaz&gt;
    Added:
    Removed: &lt;InterfaceClass __builtin__.IBaz&gt;
    &gt;&gt;&gt; foo.bar = (IBaz,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesChanged object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBaz&gt;
    Old: &lt;InterfaceClass __builtin__.IBar&gt;
    Added: &lt;InterfaceClass __builtin__.IBaz&gt;
    Removed: &lt;InterfaceClass __builtin__.IBar&gt;

IInterfacesPopulated and IInterfacesCleared extend IInterfacesAdded
and IInterfacesRemoved respectively.  IInterfacesChanged extends
both::

    &gt;&gt;&gt; def printInterfacesAdded(event): print 'Interfaces Added'
    &gt;&gt;&gt; component.provideHandler(
    ...     factory=printInterfacesAdded,
    ...     adapts=(
    ...         grouparchy.schema.interface.IInterfacesAdded,))

    &gt;&gt;&gt; def printInterfacesRemoved(event): print 'Interfaces Removed'
    &gt;&gt;&gt; component.provideHandler(
    ...     factory=printInterfacesRemoved,
    ...     adapts=(
    ...         grouparchy.schema.interface.IInterfacesRemoved,))

    &gt;&gt;&gt; foo.bar = ()
    Event:
    &lt;grouparchy.schema.interface.InterfacesCleared object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: 
    Old: &lt;InterfaceClass __builtin__.IBaz&gt;
    Added: 
    Removed: &lt;InterfaceClass __builtin__.IBaz&gt;
    Interfaces Removed
    &gt;&gt;&gt; foo.bar = (IBar,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesPopulated object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;
    Old: 
    Added: &lt;InterfaceClass __builtin__.IBar&gt;
    Removed: 
    Interfaces Added
    &gt;&gt;&gt; foo.bar = (IBaz,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesChanged object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBaz&gt;
    Old: &lt;InterfaceClass __builtin__.IBar&gt;
    Added: &lt;InterfaceClass __builtin__.IBaz&gt;
    Removed: &lt;InterfaceClass __builtin__.IBar&gt;
    Interfaces Removed
    Interfaces Added

An event class can be passed to the property as with
grouparchy.schema.event.EventProperty::

    &gt;&gt;&gt; import grouparchy.schema.event
    &gt;&gt;&gt; class IBarInterfacesModified(
    ...     grouparchy.schema.event.IFieldModifiedEvent): pass
    &gt;&gt;&gt; class BarInterfacesModified(
    ...     grouparchy.schema.event.FieldModifiedEvent):
    ...         interface.implements(IBarInterfacesModified)

    &gt;&gt;&gt; def printBarInterfacesModified(event):
    ...     print 'Event: %s' % event
    ...     print 'Object: %s' % event.object
    ...     print 'New: ' + getIfacesStr(event.new)
    ...     print 'Old: ' + getIfacesStr(event.old)
    &gt;&gt;&gt; component.provideHandler(
    ...     factory=printBarInterfacesModified,
    ...     adapts=(IBarInterfacesModified,))

    &gt;&gt;&gt; foo.bar = ()
    Event:
    &lt;grouparchy.schema.interface.InterfacesCleared object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: 
    Old: &lt;InterfaceClass __builtin__.IBaz&gt;
    Added: 
    Removed: &lt;InterfaceClass __builtin__.IBaz&gt;
    Interfaces Removed
    &gt;&gt;&gt; foo.bar = (IBar,)
    Event:
    &lt;grouparchy.schema.interface.InterfacesPopulated object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;
    Old: 
    Added: &lt;InterfaceClass __builtin__.IBar&gt;
    Removed: 
    Interfaces Added

    &gt;&gt;&gt; Foo.bar = grouparchy.schema.interface.InterfacesProperty(
    ...     IFoo['bar'],
    ...     event=BarInterfacesModified)

    &gt;&gt;&gt; foo.bar = ()
    Event: &lt;BarInterfacesModified object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: 
    Old: &lt;InterfaceClass __builtin__.IBar&gt;
    &gt;&gt;&gt; foo.bar = (IBar,)
    Event: &lt;BarInterfacesModified object at ...&gt;
    Object: &lt;Foo object at ...&gt;
    New: &lt;InterfaceClass __builtin__.IBar&gt;
    Old:</description>
<homepage rdf:resource="http://pypi.python.org/pypi/grouparchy.schema" />
<maintainer><foaf:Person><foaf:name>Ross Patterson</foaf:name>
<foaf:mbox_sha1sum>b51d9c661f066d5875649f8019b2a7007e169030</foaf:mbox_sha1sum></foaf:Person></maintainer>
<release><Version><revision>0.1</revision></Version></release>
</Project></rdf:RDF>