[Checkins] SVN: zope.generic/trunk/src/zope/generic/ initial code
from tiks.generic
Dominik Huber
dominik.huber at perse.ch
Sat Apr 8 16:33:02 EDT 2006
Log message for revision 66689:
initial code from tiks.generic
Changed:
A zope.generic/trunk/src/zope/generic/configuration/
A zope.generic/trunk/src/zope/generic/configuration/DEPENDENCIES.cfg
A zope.generic/trunk/src/zope/generic/configuration/README.txt
A zope.generic/trunk/src/zope/generic/configuration/SETUP.cfg
A zope.generic/trunk/src/zope/generic/configuration/__init__.py
A zope.generic/trunk/src/zope/generic/configuration/adapter.py
A zope.generic/trunk/src/zope/generic/configuration/api.py
A zope.generic/trunk/src/zope/generic/configuration/base.py
A zope.generic/trunk/src/zope/generic/configuration/configure.zcml
A zope.generic/trunk/src/zope/generic/configuration/event.py
A zope.generic/trunk/src/zope/generic/configuration/helper.py
A zope.generic/trunk/src/zope/generic/configuration/interfaces.py
A zope.generic/trunk/src/zope/generic/configuration/meta.zcml
A zope.generic/trunk/src/zope/generic/configuration/metaconfigure.py
A zope.generic/trunk/src/zope/generic/configuration/metadirectives.py
A zope.generic/trunk/src/zope/generic/configuration/testing.py
A zope.generic/trunk/src/zope/generic/configuration/tests.py
A zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-configure.zcml
A zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-meta.zcml
A zope.generic/trunk/src/zope/generic/directlyprovides/
A zope.generic/trunk/src/zope/generic/directlyprovides/DEPENDENCIES.cfg
A zope.generic/trunk/src/zope/generic/directlyprovides/PUBLICATION.cfg
A zope.generic/trunk/src/zope/generic/directlyprovides/README.txt
A zope.generic/trunk/src/zope/generic/directlyprovides/SETUP.cfg
A zope.generic/trunk/src/zope/generic/directlyprovides/__init__.py
A zope.generic/trunk/src/zope/generic/directlyprovides/api.py
A zope.generic/trunk/src/zope/generic/directlyprovides/configure.zcml
A zope.generic/trunk/src/zope/generic/directlyprovides/decorator.py
A zope.generic/trunk/src/zope/generic/directlyprovides/event.py
A zope.generic/trunk/src/zope/generic/directlyprovides/handler.py
A zope.generic/trunk/src/zope/generic/directlyprovides/helper.py
A zope.generic/trunk/src/zope/generic/directlyprovides/interfaces.py
A zope.generic/trunk/src/zope/generic/directlyprovides/property.py
A zope.generic/trunk/src/zope/generic/directlyprovides/testing.py
A zope.generic/trunk/src/zope/generic/directlyprovides/tests.py
A zope.generic/trunk/src/zope/generic/directlyprovides/zope.generic.directlyprovides-configure.zcml
A zope.generic/trunk/src/zope/generic/doc/
A zope.generic/trunk/src/zope/generic/doc/CHANGES.txt
A zope.generic/trunk/src/zope/generic/doc/README.txt
A zope.generic/trunk/src/zope/generic/doc/SETUP.cfg
A zope.generic/trunk/src/zope/generic/doc/TODO.txt
A zope.generic/trunk/src/zope/generic/doc/__init__.py
A zope.generic/trunk/src/zope/generic/doc/configure.zcml
A zope.generic/trunk/src/zope/generic/doc/zope.generic.doc-configure.zcml
A zope.generic/trunk/src/zope/generic/information/
A zope.generic/trunk/src/zope/generic/information/DEPENDENCIES.cfg
A zope.generic/trunk/src/zope/generic/information/PUBLICATION.cfg
A zope.generic/trunk/src/zope/generic/information/README.txt
A zope.generic/trunk/src/zope/generic/information/SETUP.cfg
A zope.generic/trunk/src/zope/generic/information/__init__.py
A zope.generic/trunk/src/zope/generic/information/api.py
A zope.generic/trunk/src/zope/generic/information/base.py
A zope.generic/trunk/src/zope/generic/information/configure.zcml
A zope.generic/trunk/src/zope/generic/information/helper.py
A zope.generic/trunk/src/zope/generic/information/interfaces.py
A zope.generic/trunk/src/zope/generic/information/meta.zcml
A zope.generic/trunk/src/zope/generic/information/metaconfigure.py
A zope.generic/trunk/src/zope/generic/information/metadirectives.py
A zope.generic/trunk/src/zope/generic/information/testing.py
A zope.generic/trunk/src/zope/generic/information/tests.py
A zope.generic/trunk/src/zope/generic/information/zope.generic.information-configure.zcml
A zope.generic/trunk/src/zope/generic/information/zope.generic.information-meta.zcml
A zope.generic/trunk/src/zope/generic/testing/
A zope.generic/trunk/src/zope/generic/testing/DEPENDENCIES.cfg
A zope.generic/trunk/src/zope/generic/testing/PUBLICATION.cfg
A zope.generic/trunk/src/zope/generic/testing/README.txt
A zope.generic/trunk/src/zope/generic/testing/SETUP.cfg
A zope.generic/trunk/src/zope/generic/testing/__init__.py
A zope.generic/trunk/src/zope/generic/testing/configure.zcml
A zope.generic/trunk/src/zope/generic/testing/testing.py
A zope.generic/trunk/src/zope/generic/testing/zope.generic.testing-configure.zcml
A zope.generic/trunk/src/zope/generic/type/
A zope.generic/trunk/src/zope/generic/type/DEPENDENCIES.cfg
A zope.generic/trunk/src/zope/generic/type/PUBLICATION.cfg
A zope.generic/trunk/src/zope/generic/type/README.txt
A zope.generic/trunk/src/zope/generic/type/SETUP.cfg
A zope.generic/trunk/src/zope/generic/type/__init__.py
A zope.generic/trunk/src/zope/generic/type/adapter.py
A zope.generic/trunk/src/zope/generic/type/api.py
A zope.generic/trunk/src/zope/generic/type/base.py
A zope.generic/trunk/src/zope/generic/type/configure.zcml
A zope.generic/trunk/src/zope/generic/type/factory.py
A zope.generic/trunk/src/zope/generic/type/helper.py
A zope.generic/trunk/src/zope/generic/type/interfaces.py
A zope.generic/trunk/src/zope/generic/type/meta.zcml
A zope.generic/trunk/src/zope/generic/type/metaconfigure.py
A zope.generic/trunk/src/zope/generic/type/metadirectives.py
A zope.generic/trunk/src/zope/generic/type/testing.py
A zope.generic/trunk/src/zope/generic/type/tests.py
A zope.generic/trunk/src/zope/generic/type/zope.generic.type-configure.zcml
A zope.generic/trunk/src/zope/generic/type/zope.generic.type-meta.zcml
-=-
Added: zope.generic/trunk/src/zope/generic/configuration/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/DEPENDENCIES.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/DEPENDENCIES.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,14 @@
+BTrees
+persistent
+zope.generic.configuration
+zope.generic.testing
+zope.app.component
+zope.app.event
+zope.app.location
+zope.component
+zope.configuration
+zope.dottedname
+zope.event
+zope.interface
+zope.schema
+zope.testing
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/configuration/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/configuration/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,271 @@
+=============
+Configuration
+=============
+
+Configuration is a container of configuration data. Configuration data are
+defined by an schema which is providing IConfigurationType.
+
+ >>> from zope.schema import TextLine
+
+ >>> class IMyConfiguration(interface.Interface):
+ ... my = TextLine(title=u'My')
+
+ # make available within the testing module
+ >>> testing.IMyConfiguration = IMyConfiguration
+
+ >>> registerDirective('''
+ ... <generic:configuration
+ ... interface="zope.generic.configuration.testing.IMyConfiguration"
+ ... label='My' hint='My bla.'
+ ... />
+ ... ''')
+
+ >>> from zope.generic.configuration.api import IConfigurationType
+ >>> IConfigurationType.providedBy(IMyConfiguration)
+ True
+
+The configuration itself is an information (see zope.generic.information) which
+is registered as utility providing IConfigurationInformation and named
+by the dotted configuration schema name:
+
+ >>> from zope.generic.configuration.api import IConfigurationInformation
+ >>> from zope.generic.information.api import queryInformation
+
+ >>> config_info = queryInformation(IMyConfiguration,
+ ... IConfigurationInformation)
+ >>> config_info.label == u'My'
+ True
+ >>> config_info.hint == u'My bla.'
+ True
+
+There is a convenience function for configuration informations too:
+
+ >>> from zope.generic.configuration.api import queryConfigurationInformation
+
+ >>> config_info == queryConfigurationInformation(IMyConfiguration)
+ True
+
+The modification of configuration might cause object configuration modified event.
+Those event extend the regular object modified event. This event regularly implies
+a location of the referenced object. Therefore only locatable objects will get
+notified. In our example we registered a transient global information which does
+not satify the condition:
+
+ >>> from zope.app.event.tests.placelesssetup import getEvents, clearEvents
+ >>> from zope.generic.configuration import IObjectConfigurationsModifiedEvent
+ >>> events = getEvents()
+ >>> len(events)
+ 0
+
+Attribute Configurations
+------------------------
+
+Regularly Configurations are provided by objects marked with
+IAttributeConfigurations automatically:
+
+ >>> from zope.generic.configuration.testing import placelesssetup
+ >>> placelesssetup.setUp()
+
+ >>> from zope.interface import implements
+ >>> from zope.generic.configuration import IAttributeConfigurable
+
+ >>> class Foo(object):
+ ... implements(IAttributeConfigurable)
+
+ >>> foo = Foo()
+ >>> IAttributeConfigurable.providedBy(foo)
+ True
+
+Now you can adapt you to IConfigurations:
+
+ >>> from zope.generic.configuration import IConfigurations
+
+ >>> configurations = IConfigurations(foo)
+ >>> IConfigurations.providedBy(configurations)
+ True
+
+At the beginning the IConfigurations storage does not exists:
+
+ >>> configurations.__nonzero__()
+ False
+
+Configuration data will be stored under an interface-key within the
+configurations. Such a configuration interface-key defines its configuration
+data:
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IFooConfiguration(Interface):
+ ... foo = TextLine(title=u'Foo')
+ ... optional = TextLine(title=u'Optional', required=False, default=u'Bla')
+
+ # make available within the module
+ >>> from zope.generic.configuration import adapter
+ >>> adapter.IFooConfiguration = IFooConfiguration
+ >>> IFooConfiguration.__module__ = 'zope.generic.configuration.adapter'
+
+The configuration interface-key is a regular schema, but it has to be typed
+by IConfigurationType (Regularly typed by the configuration directive):
+
+ >>> from zope.interface import directlyProvides
+
+ >>> directlyProvides(IFooConfiguration, IConfigurationType)
+ >>> IConfigurationType.providedBy(IFooConfiguration)
+ True
+
+The configuration provides a regular dictionary api by the UserDictMixin
+(like AttributeAnnotations). This mixin bases on the following methods:
+
+ >>> configurations[IFooConfiguration]
+ Traceback (most recent call last):
+ ...
+ KeyError: <InterfaceClass zope.generic.configuration.adapter.IFooConfiguration>
+
+ >>> del configurations[IFooConfiguration]
+ Traceback (most recent call last):
+ ...
+ KeyError: <InterfaceClass zope.generic.configuration.adapter.IFooConfiguration>
+
+ >>> configurations.keys()
+ []
+
+... if a value might be set to the configurations it must provide the
+configuration interface-key itself. The interface-key must provide
+IConfigurationType:
+
+ >>> class IBarConfiguration(Interface):
+ ... bar = TextLine(title=u'Bar')
+
+ >>> configurations[IBarConfiguration] = object()
+ Traceback (most recent call last):
+ ...
+ KeyError: 'Interface key IBarConfiguration does not provide IConfigurationType.'
+
+ >>> configurations[IFooConfiguration] = object()
+ Traceback (most recent call last):
+ ...
+ ValueError: Value does not provide IFooConfiguration.
+
+Furthermore there is an update method that can be used to update a specific
+configuration. This method can be only used if a configuration already exists:
+
+ >>> configurations.update(IFooConfiguration, {'foo': u'Foo!'})
+ Traceback (most recent call last):
+ ...
+ KeyError: <InterfaceClass zope.generic.configuration.adapter.IFooConfiguration>
+
+You can create valid configuration data using the generic ConfigurationData
+implementation:
+
+ >>> from zope.generic.configuration.base import ConfigurationData
+
+ >>> data = ConfigurationData(IFooConfiguration, {'foo': u'Foo!'})
+
+ >>> configurations[IFooConfiguration] = data
+
+The setting of the configuration is notified by a object configuration
+modified event if the parent has a location an the parent's parent
+is not None:
+
+ >>> events = getEvents()
+ >>> len(events)
+ 0
+
+ >>> from zope.app.location import Location
+ >>> parent = Location()
+ >>> configurations.__parent__ = parent
+
+ >>> configurations[IFooConfiguration] = data
+ >>> events = getEvents()
+ >>> len(events)
+ 0
+
+ >>> parent.__parent__ = Location()
+ >>> configurations[IFooConfiguration] = data
+ >>> events = getEvents()
+ >>> len(events)
+ 1
+
+ >>> event = events.pop()
+ >>> IObjectConfigurationsModifiedEvent.providedBy(event)
+ True
+ >>> [(key.__name__, value) for key, value in event.items()]
+ [('IFooConfiguration', {'foo': u'Foo!', 'optional': u'Bla'})]
+
+If the configuration data is set the first time an oobtree storage is set
+to the __configurations__ attribute of the context:
+
+ >>> configurations.__nonzero__()
+ True
+
+ >>> IFooConfiguration in configurations
+ True
+
+ >>> configurations[IFooConfiguration] == data
+ True
+
+ >>> [iface.__name__ for iface in configurations.keys()]
+ ['IFooConfiguration']
+
+You should update a configuration using the update method instead of setting
+new configuration data. If the change differs from the configuration an object
+configuration modified event is notify else not:
+
+ >>> clearEvents()
+ >>> configurations.update(IFooConfiguration, {'foo': u'Bar!'})
+ >>> events = getEvents()
+ >>> len(events)
+ 1
+ >>> event = events.pop()
+ >>> [(key.__name__, value) for key, value in event.items()]
+ [('IFooConfiguration', {'foo': u'Bar!'})]
+
+Also the deletion is notified:
+
+ >>> clearEvents()
+
+ >>> del configurations[IFooConfiguration]
+ >>> IFooConfiguration in configurations
+ False
+
+ >>> events = getEvents()
+ >>> len(events)
+ 1
+ >>> event = events.pop()
+ >>> [(key.__name__, value) for key, value in event.items()]
+ [('IFooConfiguration', {})]
+
+
+Configuration Handler
+---------------------
+
+The configurationHandler directive allows to share public configuration handlers.
+Those handlers have to provide a dedicated marker interface. This interface
+can be used for later lookup of such an handler:
+
+ >>> class IMyConfigurationHandler(interface.Interface):
+ ... pass
+
+ >>> def myConfigurationHandler(event, component, configurations=None, annotations=None):
+ ... print event, component, configurations, annotations
+
+ # make available within the testing module
+ >>> testing.IMyConfigurationHandler = IMyConfigurationHandler
+ >>> testing.myConfigurationHandler = myConfigurationHandler
+
+ >>> registerDirective('''
+ ... <generic:configurationHandler
+ ... interface='zope.generic.configuration.testing.IMyConfigurationHandler'
+ ... label='My Configuration Handler' hint='Please use it'
+ ... handler='zope.generic.configuration.testing.myConfigurationHandler'
+ ... />
+ ... ''')
+
+After the registration we can retrieve this handler by the following function:
+
+ >>> from zope.generic.configuration.api import queryConfigurationHandler
+
+ >>> handler = queryConfigurationHandler(IMyConfigurationHandler)
+ >>> handler('component', 'event', 'configurations', 'annotations')
+ component event configurations annotations
Property changes on: zope.generic/trunk/src/zope/generic/configuration/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.configuration-*.zcml
+</data-files>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/configuration/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/configuration/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.generic.configuration.interfaces import *
Property changes on: zope.generic/trunk/src/zope/generic/configuration/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/adapter.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/adapter.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/adapter.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,142 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from BTrees.OOBTree import OOBTree
+import transaction
+from UserDict import DictMixin
+
+from zope.app.location import Location
+from zope.app.location.interfaces import ILocation
+from zope.component import adapts
+from zope.event import notify
+from zope.interface import implements
+
+from zope.generic.configuration import IAttributeConfigurable
+from zope.generic.configuration import IConfigurationType
+from zope.generic.configuration import IConfigurations
+from zope.generic.configuration.event import Configuration
+from zope.generic.configuration.event import ObjectConfigurationsModifiedEvent
+from zope.generic.configuration.helper import configuratonToDict
+from zope.generic.configuration.helper import dottedName
+from zope.generic.configuration.helper import resolveClass
+
+
+
+class AttributeConfigurations(DictMixin, Location):
+ """Store configurations on an object within the __configurations__ attribute.
+
+ """
+
+ implements(IConfigurations)
+
+ adapts(IAttributeConfigurable)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __nonzero__(self):
+ return bool(getattr(self.context, '__configurations__', 0))
+
+ def __conform__(self, interface):
+ configurations = getattr(self.context, '__configurations__', None)
+ if configurations is None:
+ return None
+
+ else:
+ return configurations.get(dottedName(interface), None)
+
+ def __getitem__(self, interface):
+ configurations = getattr(self.context, '__configurations__', None)
+ if configurations is None:
+ raise KeyError(interface)
+
+ return configurations[dottedName(interface)]
+
+ def keys(self):
+ configurations = getattr(self.context, '__configurations__', None)
+ if configurations is None:
+ return []
+
+ return [resolveClass(iface) for iface in configurations.keys()]
+
+ def update(self, interface, data):
+ current_config = self[interface]
+
+ updated_data = {}
+ errors = []
+
+ savepoint = transaction.savepoint()
+ try:
+ for name, value in data.items():
+ # raise attribute error
+ field = interface[name]
+ if field.readonly:
+ raise ValueError(name, 'Data is readonly.')
+ else:
+ if value != getattr(current_config, name, field.missing_value):
+ setattr(current_config, name, value)
+ updated_data[name] = value
+
+ # notify update
+ parent = self.__parent__
+ if updated_data and ILocation.providedBy(parent) and parent.__parent__ is not None:
+ notify(ObjectConfigurationsModifiedEvent(parent,
+ Configuration(interface, updated_data)))
+
+ except:
+ savepoint.rollback()
+ raise
+
+ def __setitem__(self, interface, value):
+ # preconditions
+ if not IConfigurationType.providedBy(interface):
+ raise KeyError('Interface key %s does not provide %s.' %
+ (interface.__name__, IConfigurationType.__name__))
+
+ if not interface.providedBy(value):
+ raise ValueError('Value does not provide %s.' % interface.__name__)
+
+ # essentials
+ try:
+ configurations = self.context.__configurations__
+ except AttributeError:
+ configurations = self.context.__configurations__ = OOBTree()
+
+ data = configuratonToDict(interface, value, all=True)
+ configurations[dottedName(interface)] = value
+ # notify setting
+ parent = self.__parent__
+ if ILocation.providedBy(parent) and parent.__parent__ is not None:
+ notify(ObjectConfigurationsModifiedEvent(parent,
+ Configuration(interface, data)))
+
+ def __delitem__(self, interface):
+ try:
+ configurations = self.context.__configurations__
+ except AttributeError:
+ raise KeyError(interface)
+
+ del configurations[dottedName(interface)]
+ # notify deletion
+ # notify setting
+ parent = self.__parent__
+ if ILocation.providedBy(parent) and parent.__parent__ is not None:
+ notify(ObjectConfigurationsModifiedEvent(parent,
+ Configuration(interface, {})))
Property changes on: zope.generic/trunk/src/zope/generic/configuration/adapter.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/api.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/api.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,27 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+# usage see README.txt
+from zope.generic.configuration.base import ConfigurationData
+from zope.generic.configuration.interfaces import *
+from zope.generic.configuration.helper import dottedName
+from zope.generic.configuration.helper import provideConfigurationData
+from zope.generic.configuration.helper import queryConfigurationData
+from zope.generic.configuration.helper import queryConfigurationHandler
+from zope.generic.configuration.helper import queryConfigurationInformation
+from zope.generic.configuration.helper import resolveClass
Property changes on: zope.generic/trunk/src/zope/generic/configuration/api.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/base.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/base.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/base.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,205 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from persistent import Persistent
+from persistent.dict import PersistentDict
+
+from zope.app.annotation import IAnnotations
+from zope.interface import directlyProvides
+from zope.interface import implements
+from zope.interface.interfaces import IMethod
+from zope.schema.interfaces import IField
+from zope.schema.fieldproperty import FieldProperty
+
+from zope.generic.configuration import IConfigurationHandler
+from zope.generic.configuration import IConfigurations
+from zope.generic.configuration import missing
+
+__all__ = ['ConfigurationData']
+_marker = object()
+
+
+
+class ConfigurationData(Persistent):
+ """Generic configuration data.
+
+ Provide a configuration schema:
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IFooConfiguration(Interface):
+ ... foo = TextLine(title=u'Foo')
+ ... fuu = TextLine(title=u'Fuu', required=False)
+ ... fii = TextLine(title=u'Fii', required=False, readonly=True)
+
+ Create a corresponding configuration data:
+
+ >>> config_data = ConfigurationData(IFooConfiguration, {'foo': u'Foo!'})
+ >>> IFooConfiguration.providedBy(config_data)
+ True
+ >>> config_data.foo
+ u'Foo!'
+ >>> config_data.fuu
+
+ >>> config_data.bar
+ Traceback (most recent call last):
+ ...
+ AttributeError: bar
+
+ >>> config_data.fii = u'Bla bla'
+ Traceback (most recent call last):
+ ...
+ ValueError: ('fii', 'Data is readonly.')
+
+ If a relevant key is missed within the data a key error is raised:
+
+ >>> config_data = ConfigurationData(IFooConfiguration, {})
+ Traceback (most recent call last):
+ ...
+ KeyError: 'Missed keys: foo.'
+
+ The schema should not contain methods:
+
+ >>> class IBarConfiguration(Interface):
+ ... bar = TextLine(title=u'Bar')
+ ... def method(self):
+ ... pass
+
+ >>> config_data = ConfigurationData(IBarConfiguration, {'bar': u'Bar!', 'method': u'Method!'})
+ >>> config_data.bar
+ u'Bar!'
+ >>> config_data.method
+ Traceback (most recent call last):
+ ...
+ RuntimeError: ('Data value is not a schema field', 'method')
+ """
+
+ def __init__(self, schema, data):
+ # preconditions
+ missedKeys = []
+ for name in schema:
+ if name not in data:
+ field = schema[name]
+ if field.required is True:
+ missedKeys.append(name)
+
+ if missedKeys:
+ raise KeyError('Missed keys: %s.' % ', '.join(missedKeys))
+
+ # essentials
+ self.__dict__['_ConfigurationData__data'] = PersistentDict(data)
+ self.__dict__['_ConfigurationData__schema'] = schema
+ directlyProvides(self, schema)
+
+ def __getattr__(self, name):
+ schema = self.__dict__['_ConfigurationData__schema']
+ data = self.__dict__['_ConfigurationData__data']
+ try:
+ field = schema[name]
+ except KeyError:
+ raise AttributeError(name)
+ else:
+ value = data.get(name, _marker)
+ if value is _marker:
+ value = getattr(field, 'default', _marker)
+ if value is _marker:
+ raise RuntimeError('Data is missing', name)
+
+ if IMethod.providedBy(field):
+ if not IField.providedBy(field):
+ raise RuntimeError('Data value is not a schema field', name)
+ v = lambda: value
+ else:
+ v = value
+ # setattr(self, name, v)
+ return v
+ raise AttributeError(name)
+
+ def __setattr__(self, name, value):
+ schema = self.__dict__['_ConfigurationData__schema']
+ data = self.__dict__['_ConfigurationData__data']
+
+ if name != '__provides__':
+ try:
+ field = schema[name]
+ except KeyError:
+ raise AttributeError(name)
+ else:
+ if field.readonly is True:
+ raise ValueError(name, 'Data is readonly.')
+ data['name'] = value
+ else:
+ super(ConfigurationData, self).__setattr__(name, value)
+
+
+
+class ConfigurationHandler(object):
+ """Configuration handler."""
+
+ implements(IConfigurationHandler)
+
+ interface = FieldProperty(IConfigurationHandler['interface'])
+ passConfigurations = FieldProperty(IConfigurationHandler['passConfigurations'])
+ passAnnotations = FieldProperty(IConfigurationHandler['passAnnotations'])
+
+ def __init__(self, callable, interface=None, passConfigurations=False,
+ passAnnotations=False):
+
+ self.__callable = callable
+
+ # otherwise use IPrivatConfigurationHandler
+ if interface is not None:
+ self.interface = interface
+
+ self.passAnnotations = passAnnotations
+ self.passConfigurations = passConfigurations
+
+ def __call__(self, component, event, configurations=None, annotations=None):
+ if configurations is None and self.passConfigurations is True:
+ configurations = IConfigurations(component, missing)
+
+ if annotations is None and self.passAnnotations is True:
+ annotations = IAnnotations(component, missing)
+
+ self._apply(component, event, configurations, annotations)
+
+ def _apply(self, component, event, configurations, annotations):
+ # this method can be overwritten by subclasses
+ if self.__callable is not None:
+ return self.__callable(component, event, configurations, annotations)
+
+
+
+class ConfigurationHandlerChain(ConfigurationHandler):
+ """Process a chain of configuration handlers."""
+
+ implements(IConfigurationHandler)
+
+ interface = FieldProperty(IConfigurationHandler['interface'])
+
+ def __init__(self, handlers, interface=None, passConfigurations=True,
+ passAnnotations=True):
+ super(ConfigurationHandlerChain, self).__intit__(None, interface, passConfigurations, passAnnotations)
+ self.__handlers = handlers
+
+ def _apply(self, component, event, configurations, annotations):
+ """Invoke handler in the listed order."""
+ [handler(component, event, configurations, annotations) for handler in self.__handlers]
Property changes on: zope.generic/trunk/src/zope/generic/configuration/base.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,30 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:generic="http://namespaces.zope.org/generic"
+ i18n_domain="zope">
+
+
+ <generic:information
+ interface=".IConfigurationInformation"
+ label="Configuration Information"
+ registry="zope.generic.information.IInformationRegistryInformation"
+ />
+
+ <!-- attribute configurations -->
+ <class class=".adapter.AttributeConfigurations">
+ <allow
+ attributes="__contains__ keys __getitem__ get"
+ />
+ <require
+ permission="zope.ManageSite"
+ attributes="__setitem__ __delitem__"
+ />
+ </class>
+
+ <adapter
+ factory=".adapter.AttributeConfigurations"
+ provides="zope.generic.configuration.IConfigurations"
+ trusted="True"
+ />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/configuration/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/event.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/event.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/event.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,141 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.event.objectevent import ObjectModifiedEvent
+from zope.interface import implements
+
+from zope.generic.configuration import IObjectConfigurationsModifiedEvent
+from zope.generic.configuration import IConfigurationModificationDescription
+
+
+
+class Configuration(object) :
+ """Describes a single modified configuration.
+
+ A possible configuration schema:
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IMyConfiguration(Interface):
+ ... my = TextLine(title=u'My')
+
+ Check interface implementation:
+
+ >>> description = Configuration(IMyConfiguration, {'my': u'Bla'})
+
+ >>> IConfigurationModificationDescription.providedBy(description)
+ True
+
+ >>> description.interface == IMyConfiguration
+ True
+
+ >>> 'my' in description.data
+ True
+ >>> description.data.get('my')
+ u'Bla'
+
+ If no data argument is set, the data attribute will be set to an empty
+ dict, which implies that the configuration was deleted:
+
+ >>> description = Configuration(IMyConfiguration)
+ >>> description.interface == IMyConfiguration
+ True
+
+ >>> description.data
+ {}
+
+ """
+
+ implements(IConfigurationModificationDescription)
+
+ def __init__(self, interface, data=None) :
+ self.interface = interface
+ if data is not None:
+ self.data = data
+
+ else:
+ self.data = {}
+
+
+
+class ObjectConfigurationsModifiedEvent(ObjectModifiedEvent):
+ """An object's configurations has been modified.
+
+ A possible configuration schema:
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IMyConfiguration(Interface):
+ ... my = TextLine(title=u'My')
+
+ >>> class IYourConfiguration(Interface):
+ ... your = TextLine(title=u'Your')
+
+ >>> class IRegularInterface(Interface):
+ ... pass
+
+ A possible event:
+
+ >>> descriptions = []
+ >>> descriptions.append(Configuration(IMyConfiguration, {'my': u'Bla'}))
+ >>> descriptions.append(Configuration(IYourConfiguration))
+ >>> from zope.app.event.objectevent import Attributes
+ >>> descriptions.append(Attributes(IRegularInterface))
+ >>> context = object()
+ >>> event = ObjectConfigurationsModifiedEvent(context, *descriptions)
+
+ There are two convenience function to introspect configuration modifications
+ specifically:
+
+ >>> len(event.descriptions) is 3
+ True
+
+ >>> items = event.items()
+ >>> len(items) is 2
+ True
+ >>> [(interface.__name__, data) for interface, data in items]
+ [('IMyConfiguration', {'my': u'Bla'}), ('IYourConfiguration', {})]
+
+ >>> event.get(IMyConfiguration)
+ {'my': u'Bla'}
+
+ >>> event.get(IYourConfiguration)
+ {}
+
+ >>> event.get(IRegularInterface, 'default')
+ 'default'
+ """
+
+ implements(IObjectConfigurationsModifiedEvent)
+
+ def items(self):
+ return [(d.interface, d.data) for d in self.descriptions
+ if IConfigurationModificationDescription.providedBy(d)]
+
+ def get(self, interface, default=None):
+ result = [d.data for d in self.descriptions
+ if IConfigurationModificationDescription.providedBy(d) and d.interface is interface]
+ if result:
+ return result[0]
+
+ else:
+ return default
Property changes on: zope.generic/trunk/src/zope/generic/configuration/event.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/helper.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,156 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+
+from zope.dottedname.resolve import resolve
+from zope.component import getUtility
+
+from zope.generic.configuration import IConfigurationHandlerConfiguration
+from zope.generic.configuration import IConfigurationHandlerInformation
+from zope.generic.configuration import IConfigurationInformation
+from zope.generic.configuration import IConfigurations
+
+
+
+def dottedName(klass):
+ if klass is None:
+ return 'None'
+ return klass.__module__ + '.' + klass.__name__
+
+
+
+# cache
+__name_to_klass = {}
+
+def resolveClass(name):
+ try:
+ return __name_to_klass[name]
+ except KeyError:
+ return __name_to_klass.setdefault(name, resolve(name))
+
+
+
+def getConfigurationInformation(interface):
+ return getInformation(interface, IConfigurationInformation)
+
+
+
+def queryConfigurationInformation(interface, default=None):
+ # cyclic import :(
+ from zope.generic.information.api import queryInformation
+
+ return queryInformation(interface, IConfigurationInformation, default)
+
+
+
+def queryConfigurationData(context, interface, default=None):
+ """Evaluate corresponding configuration data satisfying the interface."""
+
+ configurations = IConfigurations(context, default)
+
+ if configurations is default:
+ return default
+
+ else:
+ return interface(configurations, default)
+
+
+def provideConfigurationData(context, interface, data):
+ """Set configuration data into the context."""
+ from zope.generic.configuration.base import ConfigurationData
+ if type(data) is dict:
+ data = ConfigurationData(interface, data)
+
+ configurations = IConfigurations(context)
+ configurations[interface] = data
+
+
+
+def queryConfigurationHandler(interface, default=None):
+ # cyclic import :(
+ from zope.generic.information.api import queryInformation
+
+ info = queryInformation(interface, IConfigurationHandlerInformation, None)
+
+ if info is None:
+ return default
+
+ configuration = queryConfigurationData(info, IConfigurationHandlerConfiguration)
+
+ if configuration is None:
+ return default
+
+ else:
+ return configuration.handler
+
+
+
+_marker = object()
+
+def configuratonToDict(interface, configuration, all=False):
+ """Extract values from configuration to a dictionary.
+
+ First we have to specify a test configurtion interface:
+
+ >>> from zope.interface import Interface
+ >>> from zope.schema import TextLine
+
+ >>> class IFooConfiguration(Interface):
+ ... fo = TextLine(title=u'Fo')
+ ... foo = TextLine(title=u'Foo', required=False)
+ ... fooo = TextLine(title=u'Fooo', required=False, readonly=True, default=u'fooo bla')
+
+ Minimal data without defaults:
+
+ >>> from zope.generic.configuration.base import ConfigurationData
+ >>> configuration = ConfigurationData(IFooConfiguration, {'fo': 'fo bla'})
+ >>> configuratonToDict(IFooConfiguration, configuration)
+ {'fo': 'fo bla'}
+
+ Including defaults:
+ >>> configuratonToDict(IFooConfiguration, configuration, all=True)
+ {'fooo': u'fooo bla', 'foo': None, 'fo': 'fo bla'}
+
+ """
+ data = {}
+ for name in interface:
+ value = getattr(configuration, name, _marker)
+ field = interface[name]
+
+ if field.required is False:
+ if value is not _marker and value != field.default:
+ data[name] = value
+
+ elif value == field.default:
+ if all:
+ data[name] = value
+
+ else:
+ if all:
+ data[name] = field.default
+
+ elif value is not _marker:
+ data[name] = value
+
+ else:
+ raise RuntimeError('Data is missing', name)
+
+ return data
+
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/configuration/helper.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/interfaces.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/interfaces.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/interfaces.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,270 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.event.interfaces import IModificationDescription
+from zope.app.event.interfaces import IObjectModifiedEvent
+from zope.app.location import ILocation
+from zope.interface import Interface
+from zope.interface import alsoProvides
+from zope.interface import Attribute
+from zope.interface.interfaces import IInterface
+from zope.schema import Bool
+from zope.schema import Dict
+from zope.schema import Object
+from zope.schema import Tuple
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+from zope.generic.information import IInformation
+from zope.generic.information import IInformationDeclaration
+
+__all__ = ['AnnotationKey', 'IConfigurable', 'IAttributeConfigurable',
+ 'IAnnotationsConfigurable', 'IConfigurationType',
+ 'IConfigurationModificationDescription',
+ 'IObjectConfigurationsModifiedEvent', 'IReadConfigurations',
+ 'IUpdateConfigurations', 'IWriteConfigurations', 'IConfigurations',
+ 'IConfigurationInformation', 'IConfigurationHandlerInformation',
+ 'IConfigurationHandlerType', 'IPrivateHandler',
+ 'IConfigurationHandler', 'missing', 'IConfigurationHandlerConfiguration']
+
+
+
+AnnotationKey = 'zope.generic.configuration.IConfigurations'
+
+
+
+class IConfigurable(Interface):
+ """Marker interface for objects that support storing configuraitons."""
+
+
+
+class IAttributeConfigurable(IConfigurable):
+ """Marker indicating that configurations can be stored on an attribute.
+
+ This is a marker interface giving permission for an `IConfigurations`
+ adapter to store data in an attribute named `__configurations__`.
+
+ """
+
+
+
+class IAnnotationsConfigurable(IConfigurable):
+ """Marker indicating that configurations can be stored on annotations.
+
+ """
+
+
+
+class IConfigurationType(IInterface):
+ """Mark a configuration data schema.
+
+ Typed schemas might be rendered to xml to provide a configuration view of an
+ object.
+ """
+
+
+
+class IConfigurationModificationDescription(IModificationDescription):
+ """Declares the modified configuration by its interface and
+ the corresponding data that got modified.
+
+ An empty data dictionary implies that the configuration was deleted."""
+
+ interface = Attribute("The involved configuratoin interface.")
+ data = Attribute("A dict of modified configuration data.")
+
+
+
+class IObjectConfigurationsModifiedEvent(IObjectModifiedEvent):
+ """An object's configurations has been modified.
+
+ The corresponding modifications will be attached on the description attribute
+ """
+
+ descriptions = Attribute("Sequence of modifiaction descriptions.")
+
+ def items():
+ """List affected configuration interfaces and corresponding data from the descriptions."""
+
+ def get(interface, default=None):
+ """Return affected configuration data from the description or default."""
+
+
+
+class IReadConfigurations(Interface):
+ """Read configurations."""
+
+ def __conform__(interface):
+ """Invoke values that are stored under the interface-key.
+
+ Regularly the interface-key should provide configuration type.
+ If no value could be found None is returned.
+ """
+
+ def __nonzero__():
+ """Test whether there are any configurations."""
+
+ def __getitem__(interface):
+ """Return the configuration stored under interface-key.
+
+ Raises a KeyError if the key is not found.
+ """
+
+ def keys(self):
+ """Return stored configuraitons keys."""
+
+
+
+class IUpdateConfigurations(Interface):
+ """Update configurations."""
+
+ def update(interface, data):
+ """Update configuration partially if nessecary.
+
+ data - dict providing values corresponding to the attribute names of the
+ interface.
+
+ The data object itself will not be saved, only the values that
+ differs from the existing configuration data within the configurations.
+
+ A ValueError is raised if an read-only attribute/value should be set.
+ A AttributeError is raised if a not declared name should be set.
+ A KeyError is raise if there is no corresponding configuration avaiable.
+
+ A successfull update is notified by a ObjectConfigurationModifiedEvent if
+ any value of the configuration got changed and the parent providing
+ ILocation.
+ """
+
+
+
+class IWriteConfigurations(Interface):
+ """Set or delete a configuration."""
+
+ def __setitem__(interface, value):
+ """Store a certain configuration data under the interface-key.
+
+ The interface should provide IConfigurationType.
+
+ The value has to provide the declared interface key and this value will
+ be invoked by the __conform__ mechanism if somebody try to adapt the
+ configuration data to this interface.
+
+ A successfull setting is notified by a ObjectConfigurationModifiedEvent
+ if the parent providing ILocation.
+ """
+
+ def __delitem__(interface):
+ """Removes the configuration stored under interface-key.
+
+ Raises a KeyError if the key is not found.
+
+ A successfull deletion is notified by a ObjectConfigurationModifiedEvent
+ if the parent providing ILocation.
+ """
+
+
+
+class IConfigurations(IReadConfigurations, IUpdateConfigurations,
+ IWriteConfigurations, IConfigurable, ILocation):
+ """United configurations interfaces."""
+
+
+
+class IConfigurationInformation(IInformation):
+ """Information about a configuration."""
+
+
+
+class IConfigurationHandlerInformation(IInformation):
+ """Information about a configuration handler."""
+
+
+
+class IConfigurationHandlerType(IInterface):
+ """Type a configuration handler marker interface."""
+
+
+
+class IPrivateHandler(Interface):
+ """Mark a private configuration handler.
+
+ Configuration handlers marked by this marker should not be used from
+ other parties.
+
+ """
+
+alsoProvides(IPrivateHandler, IConfigurationHandlerType)
+
+
+
+missing = object()
+
+class IConfigurationHandler(IInformationDeclaration):
+ """A configuration handler.
+
+ A handler marked by this type provides a certain configuration procdure
+ functionality."""
+
+ interface = Object(
+ title=_('Interface'),
+ description=_('Interface marker that references corresponding informations.'),
+ default=IPrivateHandler,
+ schema=IConfigurationHandlerType)
+
+ passConfigurations = Bool(
+ title=_('Lookup Configurations?'),
+ description=_('Should component configurations be invoked by the handler'),
+ default=False)
+
+ passAnnotations = Bool(
+ title=_('Lookup Annotations?'),
+ description=_('Should component annotations be invoked by the handler'),
+ default=False)
+
+ def __call__(component, event, configurations=None, annotations=None):
+ """Configure the component.
+
+ A None value for annotations or configurations implies, that no
+ configuration was looked up before.
+
+ If you couldn't look up a configurations or annotations you shoul
+ pass the missing marker object.
+
+ If configurations is missing or passConfigurations is False,
+ the handler should provide its own default configuration itself.
+
+ If annotations is missing or passAnnotations is False,
+ the handler should provide its own default configuration itself.
+
+ """
+
+
+
+class IConfigurationHandlerConfiguration(Interface):
+ """The configuration for the configuration handler registration."""
+
+ handler = Object(
+ title=_('Configuration Handler'),
+ description=_('Registered configuration handler.'),
+ required=True,
+ schema=IConfigurationHandler)
+
+alsoProvides(IConfigurationHandlerConfiguration, IConfigurationType)
Property changes on: zope.generic/trunk/src/zope/generic/configuration/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,21 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta">
+
+ <meta:directives namespace="http://namespaces.zope.org/generic">
+
+ <meta:directive
+ name="configuration"
+ schema=".metadirectives.IConfigurationDirective"
+ handler=".metaconfigure.configurationDirective"
+ />
+
+ <meta:directive
+ name="configurationHandler"
+ schema=".metadirectives.IConfigurationHandlerDirective"
+ handler=".metaconfigure.configurationHandlerDirective"
+ />
+
+ </meta:directives>
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/configuration/meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/metaconfigure.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/metaconfigure.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,106 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Projekt01 GmbH and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.component.interface import provideInterface
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import alsoProvides
+
+from zope.generic.information.api import queryInformation
+from zope.generic.information.metaconfigure import provideInformation
+
+from zope.generic.configuration import IConfigurationHandler
+from zope.generic.configuration import IConfigurationHandlerConfiguration
+from zope.generic.configuration import IConfigurationHandlerInformation
+from zope.generic.configuration import IConfigurationHandlerType
+from zope.generic.configuration import IConfigurationInformation
+from zope.generic.configuration import IConfigurationType
+from zope.generic.configuration import IConfigurations
+
+from zope.generic.configuration.base import ConfigurationData
+from zope.generic.configuration.base import ConfigurationHandler
+
+
+
+def configurationDirective(_context, interface, label=None, hint=None):
+ """Provide new configuration information."""
+
+ registry = IConfigurationInformation
+ iface_type = IConfigurationType
+
+ # assert type as soon as possible
+ if not iface_type.providedBy(interface):
+ alsoProvides(interface, iface_type)
+
+ _context.action(
+ discriminator = ('provideInformation', interface, registry),
+ callable = provideInformation,
+ args = (interface, registry, label, hint),
+ )
+
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = (None, interface, iface_type),
+ )
+
+
+def provideConfigurationHandlerConfiguration(interface, handler):
+ """Provide the handler to an configuration information."""
+
+ registry = IConfigurationHandlerInformation
+ info = queryInformation(interface, IConfigurationHandlerInformation)
+
+ # this should never happen...
+ if info is None:
+ ConfigurationError('No configuration handler information for %s'
+ % interface.__name__)
+
+ # Eventually wrap a callable
+ if not IConfigurationHandler.providedBy(handler):
+ handler = ConfigurationHandler(handler, interface)
+
+ configurations = IConfigurations(info)
+ # create configuration data
+ data = ConfigurationData(IConfigurationHandlerConfiguration, {'handler': handler})
+ # set configuration data
+ configurations[IConfigurationHandlerConfiguration] = data
+
+
+
+def configurationHandlerDirective(_context, interface, handler, label=None, hint=None):
+ """Register a public configuration handler."""
+
+ # assert type as soon as possible
+ if not IConfigurationHandlerType.providedBy(interface):
+ alsoProvides(interface, IConfigurationHandlerType)
+
+ registry = IConfigurationHandlerInformation
+
+ _context.action(
+ discriminator = ('provideInformation', interface, registry),
+ callable = provideInformation,
+ args = (interface, registry, label, hint),
+ )
+
+ _context.action(
+ discriminator = ('provideConfigurationHandlerConfiguration', interface, handler),
+ callable = provideConfigurationHandlerConfiguration,
+ args = (interface, handler),
+ )
Property changes on: zope.generic/trunk/src/zope/generic/configuration/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/metadirectives.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/metadirectives.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/metadirectives.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,51 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.fields import GlobalObject
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+from zope.generic.information.metadirectives import IBaseInformationDirective
+
+
+
+class IConfigurationDirective(IBaseInformationDirective):
+ """Declare configuration schema.
+
+ Register configuration schema as interface utility typed by
+ IConfigurationType within the configuration registry utility.
+ """
+
+
+
+class IConfigurationHandlerDirective(IBaseInformationDirective):
+ """Declare a public configuration handler.
+
+ Register configuration handler as interface utility typed by
+ IConfigurationHandlerType.
+
+ """
+
+ handler = GlobalObject(
+ title=_('Configuration Handler'),
+ description=_('Configuration handler or callable with the signature' +
+ '(componet, event, configuration=None, annotations=None).'),
+ required=True
+ )
Property changes on: zope.generic/trunk/src/zope/generic/configuration/metadirectives.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/testing.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/testing.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,87 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.component import provideAdapter
+from zope.configuration.xmlconfig import XMLConfig
+from zope.interface import Interface
+from zope.schema import TextLine
+
+from zope.generic.configuration import IConfigurations
+
+import zope.generic.information.testing
+
+
+################################################################################
+#
+# Public Test implementations
+#
+################################################################################
+
+class IMarker(Interface):
+ """Demo marker."""
+
+
+class IFooConfiguration(Interface):
+
+ foo = TextLine(title=u'Foo')
+
+ fo = TextLine(title=u'Fo', required=False, readonly=True, default=u'fo default')
+
+
+class IBarConfiguration(Interface):
+
+ bar = TextLine(title=u'Bar')
+
+
+class IInputConfiguration(Interface):
+
+ foo = TextLine(title=u'Foo')
+
+ bar = TextLine(title=u'Bar')
+
+
+
+################################################################################
+#
+# Placeless setup
+#
+################################################################################
+
+
+class PlacelessSetup(zope.generic.information.testing.PlacelessSetup):
+
+ def setUp(self, doctesttest=None):
+ super(PlacelessSetup, self).setUp(doctesttest)
+
+ # register attribute configurations adapter
+ import zope.generic.configuration.adapter
+ provideAdapter(zope.generic.configuration.adapter.AttributeConfigurations,
+ provides=IConfigurations)
+
+ # register the directive of this package
+ import zope.generic.configuration
+ XMLConfig('meta.zcml', zope.generic.configuration)()
+
+ def tearDown(self, doctesttest=None):
+ super(PlacelessSetup, self).tearDown(doctesttest)
+
+
+
+placelesssetup = PlacelessSetup()
Property changes on: zope.generic/trunk/src/zope/generic/configuration/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/tests.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,73 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+import unittest
+
+from zope import component
+from zope import interface
+from zope.testing import doctest
+
+from zope.generic.testing.testing import InterfaceBaseTest
+from zope.generic.testing.testing import registerDirective
+
+from zope.generic.configuration import testing
+from zope.generic.configuration.base import ConfigurationData
+
+
+
+class ConfigurationDataTest(InterfaceBaseTest):
+
+ _verify_class = False
+ _test_interface = testing.IFooConfiguration
+ _test_class = ConfigurationData
+ _test_pos = (testing.IFooConfiguration, {'foo': u'Bla bla'})
+
+ def test_readonly_attributes(self):
+ interface = self._test_interface
+ test_obj = self.makeTestObject()
+ for name in interface:
+ field = interface[name]
+ if field.readonly is True:
+ self.assertRaises(ValueError, setattr, test_obj, name, object())
+
+ def test_default_value(self):
+ interface = self._test_interface
+ test_obj = self.makeTestObject()
+ fo_field = interface['fo']
+ self.assertEqual(getattr(test_obj, 'fo'), fo_field.default)
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ unittest.makeSuite(ConfigurationDataTest),
+ doctest.DocTestSuite('zope.generic.configuration.base'),
+ doctest.DocTestSuite('zope.generic.configuration.adapter'),
+ doctest.DocTestSuite('zope.generic.configuration.event'),
+ doctest.DocTestSuite('zope.generic.configuration.helper'),
+ doctest.DocFileSuite('README.txt',
+ setUp=testing.placelesssetup.setUp,
+ tearDown=testing.placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'registerDirective': registerDirective,
+ 'testing': testing},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
+ ))
+
+if __name__ == '__main__': unittest.main()
Property changes on: zope.generic/trunk/src/zope/generic/configuration/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.configuration" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.configuration" file="meta.zcml" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/configuration/zope.generic.configuration-meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/DEPENDENCIES.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/DEPENDENCIES.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,8 @@
+zope.generic.testing
+zope.app.event
+zope.app.testing
+zope.component
+zope.event
+zope.interface
+zope.schema
+zope.testing
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/directlyprovides/PUBLICATION.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/PUBLICATION.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/PUBLICATION.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,8 @@
+Metadata-Version: 1.0
+Name: zope.generic.directlyprovides
+Summary: Controllable Directly Provides Mechanism
+Author: Dominik Huber, Perse Engineering GmbH, Switzerland
+Author-email: dominik.huber at perse.ch
+License: ZPL 2.1
+Description:
+ Provide facility to control directly provides mechanism partially.
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/PUBLICATION.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/directlyprovides/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,372 @@
+=================
+Directly Provides
+=================
+
+The `zope.interface` package offers the powerful mechanism of directly provided
+interfaces that means instance-specific interfaces.
+
+Directly provided interfaces today have the most important impact to
+interface-based lookups for example within the adapter registry, therefore the
+directly provided interface can fully control/determine the behavior of
+applications based on the component architecture.
+
+The problem is that those interface cannot be controlled properly:
+
+- Ordering depends on the chronological order, but often this order
+ cannot asserted properly other a later interface is hidden by an
+ earlier one.
+
+- No event notification even though the whole adaption based behavior might
+ have changed.
+
+- Sometimes an other order that the cronological should be asserted. That
+ means dedicated directly provided interfaces should be prepended someway.
+
+Those lacks might lead to mistaken lookups. The scope of this package
+is to provide better controll over the directly provided mechanism.
+
+Now we will explore this behavior in a small showcase. There are four
+interfaces IA, IB, IC, ID marking instances that will be adapted. The interface
+IResult is the target resp. provided interface. The class A and the adapters
+ResultForA, ResultForB, ResultForC, ResultForD are representing corresponding
+sample implementations:
+
+ >>> class IA(interface.Interface):
+ ... pass
+
+ >>> class IB(interface.Interface):
+ ... pass
+
+ >>> class IC(interface.Interface):
+ ... pass
+
+ >>> class ID(interface.Interface):
+ ... pass
+
+ >>> class IResult(interface.Interface):
+ ... pass
+
+ >>> class A(object):
+ ... interface.implements(IA)
+
+ >>> class ResultForA(object):
+ ... interface.implements(IResult)
+ ... component.adapts(IA)
+ ... def __init__(self, context):
+ ... pass
+
+ >>> class ResultForB(object):
+ ... interface.implements(IResult)
+ ... component.adapts(IB)
+ ... def __init__(self, context):
+ ... pass
+
+ >>> class ResultForC(object):
+ ... interface.implements(IResult)
+ ... component.adapts(IC)
+ ... def __init__(self, context):
+ ... pass
+
+ >>> class ResultForD(object):
+ ... interface.implements(IResult)
+ ... component.adapts(ID)
+ ... def __init__(self, context):
+ ... pass
+
+ >>> component.provideAdapter(ResultForA)
+ >>> component.provideAdapter(ResultForB)
+ >>> component.provideAdapter(ResultForC)
+ >>> component.provideAdapter(ResultForD)
+
+First we adapt an instance of `A` regularly:
+
+ >>> a = A()
+ >>> IResult(a)
+ <ResultForA object at ...>
+
+If we directly provides an interface, for example IB, the
+corresponding adapter `ResultForB` will be looked up:
+
+ >>> interface.directlyProvides(a, IB)
+ >>> IResult(a)
+ <ResultForB object at ...>
+
+ >>> interface.alsoProvides(a, IC)
+ >>> IResult(a)
+ <ResultForB object at ...>
+
+Given the fact that different orthagonal application such as the site
+framework uses the directly provided mechanism it is not possible
+to determine the order of directly provided interfaces in respect to
+the point in time when it will be setted:
+
+ >>> a = A()
+
+ >>> interface.directlyProvides(a, IC)
+ >>> IResult(a)
+ <ResultForC object at ...>
+
+ >>> interface.alsoProvides(a, IB)
+ >>> IResult(a)
+ <ResultForC object at ...>
+
+As long as different directly provided interfaces do not overlap
+features this unordered aspect is not relevant.
+
+One possibility is to rely heavly on this directly provides mechanism
+to model business domains using generic base classes and marker interfaces
+differing the business types. All features of generic business objects
+could be provided by adaption. In those edge cases it would be more
+comfortable to have partial control over the directly provided mechanism.
+
+The package `zope.generic.directlyprovides` offers the functionality to
+control directly provided interfaces partially. In the next showcase
+we implement a generic class Prependes. The attribute `prepended` offers
+a list of interfaces that should be prepended to the directly provided
+interfaces.
+
+First we define an interface deriving from IProvides:
+
+ >>> from zope.interface.interfaces import IInterface
+ >>> from zope.generic.directlyprovides import api
+
+ >>> class IPrepender(api.IProvides):
+ ...
+ ... first = schema.Tuple(title=u'First',
+ ... description=u'Prepend the listed interfaces first.',
+ ... default=(),
+ ... value_type=schema.Object(schema=IInterface))
+ ...
+ ... second = schema.Tuple(title=u'Second',
+ ... description=u'Prepend the listed interfaces second.',
+ ... default=(),
+ ... value_type=schema.Object(schema=IInterface))
+
+Then we have to implement the interface within the class Prepender.
+
+The *provides* defines the relevant attributes that contains the
+interfaces that should be prepented to the directly provided interfaces.
+
+We can use the decorator `updateProvides` or the property UpdateProvides
+to update the directly provide mechanism if the value of the prepended
+attribute is newly set.
+
+We declare the field that stores the value and we can determine optional
+pre- and post-hooks that should offer three parameters `self`, `new`
+and `old` as signature:
+
+ >>> def before_hook(self, new, old):
+ ... print 'before'
+
+ >>> def after_hook(self, new, old):
+ ... print 'after',
+ ... print str(tuple([iface.__name__ for iface in old])),
+ ... print 'to ' + str(tuple([iface.__name__ for iface in new]))
+
+If the directly provided interfaces has changed an directly provides event
+is notified. We register an handler for this event:
+
+ >>> from zope.interface import directlyProvidedBy
+ >>> def notifyDirectlyProvidesModifiedEvent(component, event):
+ ... print 'directlyProvided changed', str(tuple([iface.__name__
+ ... for iface in interface.directlyProvidedBy(event.object)]))
+
+ >>> ztapi.subscribe((api.IProvides, api.IDirectlyProvidesModifiedEvent), None,
+ ... notifyDirectlyProvidesModifiedEvent)
+
+ >>> from zope.app.event.interfaces import IObjectModifiedEvent
+
+ >>> def notifyObjectModifiedEvent(first, second=None):
+ ... if second:
+ ... print 'Object modified (multi subscriber), ',
+ ... first = second
+ ... else:
+ ... print 'Object modified (single subscriber), ',
+ ... description = first.descriptions[0]
+ ... print description.interface.__name__, description.attributes
+
+
+ >>> ztapi.subscribe((IObjectModifiedEvent,), None,
+ ... notifyObjectModifiedEvent)
+
+ >>> ztapi.subscribe((IPrepender, IObjectModifiedEvent,), None,
+ ... notifyObjectModifiedEvent)
+
+Now we are implementing an example class using the before- and after-hook.
+For documentation purposes we use for the `first` attribute the decorator and
+for the `second` attribute the property:
+
+ >>> class Prepender(object):
+ ...
+ ... interface.implements(IPrepender)
+ ... api.provides('first', 'second')
+ ...
+ ... def _g_first(self):
+ ... return self.__dict__.get('prepended', ())
+ ...
+ ... @api.updateProvides(IPrepender['first'], before_hook, after_hook)
+ ... def _s_first(self, value):
+ ... if value:
+ ... self.__dict__['prepended'] = value
+ ... else:
+ ... del self.__dict__['prepended']
+ ...
+ ... first = property(_g_first, _s_first)
+ ...
+ ... second = api.UpdateProvides(IPrepender['second'], before_hook, after_hook)
+
+Now, we are going to use our example implementation. At the beginning
+the generic prepended instance does not provide any adaptable interface,
+therefore an error is raised if we try to adapt to IResult:
+
+ >>> p = Prepender()
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ []
+ >>> IResult(p)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt'...)
+
+After that we provide IB directly:
+
+ >>> interface.directlyProvides(p, IB)
+ directlyProvided changed ('IB',)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IB']
+ >>> IResult(p)
+ <ResultForB object at ...>
+
+Another assignment is appended:
+
+ >>> interface.alsoProvides(p, IA)
+ directlyProvided changed ('IB', 'IA')
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IB', 'IA']
+
+ >>> IResult(p)
+ <ResultForB object at ...>
+
+But if we use our prepend mechanism the interface is prepended:
+
+ >>> p.second = (ID, )
+ before
+ directlyProvided changed ('ID', 'IB', 'IA')
+ after () to ('ID',)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['ID', 'IB', 'IA']
+
+ >>> IResult(p)
+ <ResultForD object at ...>
+
+ >>> p.first = (IC, )
+ before
+ directlyProvided changed ('IC', 'ID', 'IB', 'IA')
+ after () to ('IC',)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IC', 'ID', 'IB', 'IA']
+
+ >>> IResult(p)
+ <ResultForC object at ...>
+
+The value of the decorated attribute or the property will be only set if the
+old and new value differs:
+
+ >>> p.first = (IC, )
+ >>> p.second = (ID, )
+
+We can remove the prepended interface setting an empty tuple:
+
+ >>> p.first = ()
+ before
+ directlyProvided changed ('ID', 'IB', 'IA')
+ after ('IC',) to ()
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['ID', 'IB', 'IA']
+
+ >>> IResult(p)
+ <ResultForD object at ...>
+
+If the twice the same interface is set only the first is accepted.
+Attention, in this case no directly provides event is notified, because
+the order of the directly provided interfaces did not change:
+
+ >>> p.first = (ID,)
+ before
+ after () to ('ID',)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['ID', 'IB', 'IA']
+
+We can add more than one or switch them:
+
+ >>> p.first = (ID, IC)
+ before
+ directlyProvided changed ('ID', 'IC', 'IB', 'IA')
+ after ('ID',) to ('ID', 'IC')
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['ID', 'IC', 'IB', 'IA']
+ >>> IResult(p)
+ <ResultForD object at ...>
+
+ >>> p.first = (IC, ID)
+ before
+ directlyProvided changed ('IC', 'ID', 'IB', 'IA')
+ after ('ID', 'IC') to ('IC', 'ID')
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IC', 'ID', 'IB', 'IA']
+ >>> IResult(p)
+ <ResultForC object at ...>
+
+We can remove a regular directly provided:
+
+ >>> interface.directlyProvides(p, interface.directlyProvidedBy(p) - IB)
+ directlyProvided changed ('IC', 'ID', 'IA')
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IC', 'ID', 'IA']
+ >>> IResult(p)
+ <ResultForC object at ...>
+
+But we cannot remove a prepended one. Attention, in this case no directly provides
+event is notified, because the directly provided interfaces
+did not change:
+
+ >>> interface.directlyProvides(p, interface.directlyProvidedBy(p) - IC)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IC', 'ID', 'IA']
+ >>> IResult(p)
+ <ResultForC object at ...>
+
+If we like to remove prepended one, we have to set the corresponding attribute.
+Take care, sometimes a second prepended still offfers an removed interface:
+
+ >>> p.first = (IA,)
+ before
+ directlyProvided changed ('IA', 'ID')
+ after ('IC', 'ID') to ('IA',)
+
+ >>> [iface.__name__ for iface in interface.directlyProvidedBy(p)]
+ ['IA', 'ID']
+ >>> IResult(p)
+ <ResultForA object at ...>
+
+There is event dispatcher to object modified events provided if the object
+providing IProvides is marked by IObjectModifiedEventDispatchingProvides:
+
+ >>> interface.classImplements(Prepender,
+ ... api.IObjectModifiedEventDispatchingProvides)
+
+ >>> p.first = (IB,)
+ before
+ directlyProvided changed ('IB', 'ID')
+ Object modified (multi subscriber), IProvides ('__provides__',)
+ Object modified (single subscriber), IProvides ('__provides__',)
+ after ('IA',) to ('IB',)
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.directlyprovides-*.zcml
+</data-files>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/directlyprovides/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.generic.directlyprovides.interfaces import *
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/api.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/api.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+# usage see README.txt
+
+from zope.generic.directlyprovides.interfaces import *
+from zope.generic.directlyprovides.event import DirectlyProvidesModifiedEvent
+from zope.generic.directlyprovides.decorator import updateProvides
+from zope.generic.directlyprovides.helper import updateDirectlyProvided
+from zope.generic.directlyprovides.property import provides
+from zope.generic.directlyprovides.property import UpdateProvides
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/api.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="zope">
+
+ <subscriber
+ for=".IDirectlyProvidesModifiedEvent"
+ handler=".handler.notifyObjectModifiedEvent"
+ />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/decorator.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/decorator.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/decorator.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.generic.directlyprovides.helper import updateDirectlyProvided
+
+
+
+def updateProvides(field, before=None, after=None):
+ def decorator(f):
+ def new_f(self, value):
+ # remember the previous value
+ previous_value = getattr(self, field.__name__)
+
+ if previous_value != value:
+ # invoke before
+ if before:
+ before(self, value, previous_value)
+
+ # call decorated function
+ result = f(self, value)
+
+ # update directly provides
+ updateDirectlyProvided(self, value, previous_value)
+
+ # invoke after
+ if after:
+ after(self, value, previous_value)
+
+ return result
+ return None
+
+ new_f.func_name = f.func_name
+ return new_f
+ return decorator
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/decorator.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/event.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/event.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/event.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import implements
+
+from zope.generic.directlyprovides import IDirectlyProvidesModifiedEvent
+
+
+
+class DirectlyProvidesModifiedEvent(object):
+ """Directly provides event.
+
+ Event with two marker types:
+
+ >>> obj = object()
+ >>> event = DirectlyProvidesModifiedEvent(obj)
+
+ >>> event.object is obj
+ True
+
+ >>> IDirectlyProvidesModifiedEvent.providedBy(event)
+ True
+
+ """
+
+ implements(IDirectlyProvidesModifiedEvent)
+
+ def __init__(self, object):
+ self.object = object
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/event.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/handler.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/handler.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/handler.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.component import subscribers
+from zope.app.event.objectevent import Attributes
+from zope.app.event.objectevent import ObjectModifiedEvent
+
+from zope.generic.directlyprovides import IProvides
+from zope.generic.directlyprovides import IObjectModifiedEventDispatchingProvides
+
+
+
+def notifyObjectModifiedEvent(event):
+
+ if IObjectModifiedEventDispatchingProvides.providedBy(event.object):
+ event = ObjectModifiedEvent(event.object, Attributes(IProvides, '__provides__'))
+
+ for ignored in subscribers((event,), None):
+ pass
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/handler.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/helper.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/helper.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,93 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.interface import directlyProvidedBy
+from zope.interface import directlyProvides
+
+
+
+def assertListOfInterfaces(value):
+ """Assert a list of interfaces.
+
+ This helper function asserts that a list of interfaces is returned:
+
+ >>> from zope.interface import Interface
+
+ >>> class IA(Interface):
+ ... pass
+
+ >>> class IB(Interface):
+ ... pass
+
+ >>> class IC(Interface):
+ ... pass
+
+ An interface is returned as a list of this single interface:
+
+ >>> result = assertListOfInterfaces(IA)
+ >>> [iface.__name__ for iface in result]
+ ['IA']
+
+ A tuple of interface/interfaces is returned as list of interface/
+ interfaces:
+
+ >>> result = assertListOfInterfaces((IA, IB, IC))
+ >>> [iface.__name__ for iface in result]
+ ['IA', 'IB', 'IC']
+
+ A list of interface/interfaces is returned as new list of interface/
+ interfaces:
+
+ >>> input = [IA, IB, IC]
+ >>> result = assertListOfInterfaces(input)
+
+ >>> input is result, input == result
+ (False, True)
+
+ >>> [iface.__name__ for iface in result]
+ ['IA', 'IB', 'IC']
+
+ None is returned as an empty list:
+
+ >>> assertListOfInterfaces(None)
+ []
+
+ """
+
+ if isinstance(value, (tuple, list)):
+ # list/tuple of interfaces
+ return list(value)
+ elif value is None:
+ # None
+ return []
+ else:
+ # interface
+ return [value]
+
+
+
+def updateDirectlyProvided(self, value, previous_value=None):
+ """Update directly provides after a value is set."""
+
+ directlyProvided = list(directlyProvidedBy(self))
+ for iface in assertListOfInterfaces(previous_value):
+ if iface in directlyProvided:
+ directlyProvided.remove(iface)
+
+ directlyProvided = assertListOfInterfaces(value) + directlyProvided
+ directlyProvides(self, *directlyProvided)
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/helper.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/interfaces.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/interfaces.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/interfaces.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,49 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Attribute
+from zope.interface import Interface
+
+from zope.app.event.interfaces import IObjectEvent
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+
+
+class IProvides(Interface):
+ """Prependes important interfaces within the directly provides mechanism."""
+
+ __provides__ = Attribute(_('Provides'),
+ _('Return directly provided interfaces respecting a partial order of ' +
+ 'important interfaces that should be prepended any time.')
+ )
+
+
+
+class IDirectlyProvidesModifiedEvent(IObjectEvent):
+ """Reference an object where the directly provided interfaces were modified."""
+
+
+
+class IObjectModifiedEventDispatchingProvides(IProvides):
+ """Marked objects will be notify an additional ObjectModifiedEvent.
+
+ This interface is used for subscriber-based event dispatching.
+ """
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/property.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/property.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/property.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,251 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+import sys
+from zope.event import notify
+from zope.interface import directlyProvidedBy
+from zope.interface import directlyProvides
+from zope.interface import implementedBy
+from zope.interface.declarations import Declaration
+
+from zope.generic.directlyprovides.event import DirectlyProvidesModifiedEvent
+from zope.generic.directlyprovides.helper import assertListOfInterfaces
+from zope.generic.directlyprovides.helper import updateDirectlyProvided
+
+_marker = object()
+
+
+def hack_checker(value, length, inst):
+ from zope.interface.declarations import Declaration
+ flattened = [i for i in value.flattened()]
+
+ # precondition for the hack checker
+ for iface in implementedBy(inst.__class__):
+ if iface in flattened:
+ return True
+
+ iterated = [i for i in value]
+ if not flattened[0:length] == iterated[0:length]:
+ declaration = Declaration(*iterated)
+ if [i for i in declaration.flattened()][0:length] == flattened[0:length]:
+ return True
+ else:
+ return False
+ return True
+
+
+class ProvidesProperty(object):
+ """Prepend the values of the declared names to the directly provided interfaces."""
+
+ def __init__(self, *names):
+ self.__names = names
+
+ def __get__(self, inst, klass):
+ if inst is None:
+ return self
+
+ value = inst.__dict__.get('__provides__', _marker)
+ if value is _marker:
+ raise AttributeError('__provides__')
+
+ return value
+
+ def __set__(self, inst, value):
+ # remove a provides declaration
+ if value is None:
+ if '__provides__' in inst.__dict__:
+ del inst.__dict__['__provides__']
+
+ # evaluate interfaces that should be prepended
+ prepended = self._evaluatePrepended(inst)
+
+ if value:
+ ifaces = list(value)
+ else:
+ ifaces = []
+
+ is_ok = (len(ifaces) >= len(prepended) and ifaces[0:len(prepended)] == prepended)
+
+ # XXX: An exception that I do not understand???
+ # Problem if a interface is directly provided by the regular mechanism
+ # and afterward is set by our mechanism
+ if is_ok and not hack_checker(value, len(prepended), inst):
+ directlyProvides(inst)
+ directlyProvides(inst, *ifaces)
+
+ # everything prepended correctly
+ elif is_ok:
+ if list(Declaration(value.__bases__[:-1])) != list(directlyProvidedBy(inst)):
+ value.changed()
+ inst.__dict__['__provides__'] = value
+
+ notify(DirectlyProvidesModifiedEvent(inst))
+
+ # order the interfaces first
+ elif len(ifaces) > 0:
+ # remove duplicates
+ for iface in prepended:
+ while iface in ifaces:
+ ifaces.remove(iface)
+
+ for iface in implementedBy(inst.__class__):
+ while iface in ifaces:
+ ifaces.remove(iface)
+
+ # put pretended and other interfaces together and asign it again
+ ordered = prepended + ifaces
+ directlyProvides(inst, *ordered)
+
+ # no other directly provided interface
+ else:
+ directlyProvides(inst, *prepended)
+
+ def _evaluatePrepended(self, inst):
+ prependes = []
+ for name in self.__names:
+ for iface in assertListOfInterfaces(getattr(inst, name)):
+ if iface not in prependes:
+ prependes.append(iface)
+
+ return prependes
+
+
+
+def provides(*names):
+ """Declare the attributes which should be asserted by the directly provided mechnism.
+
+ This is used within a class suite defining an attribute __provides__:
+
+ >>> from zope.interface import Interface
+ >>> class IFoo(Interface):
+ ... pass
+
+ >>> class Bar(object):
+ ... provides('foo')
+ ... foo = IFoo
+
+ >>> Bar.__provides__._ProvidesProperty__names
+ ('foo',)
+
+ It is invalid to call contains outside a class suite:
+
+ >>> provides('foo')
+ Traceback (most recent call last):
+ ...
+ TypeError: provides not called from suite
+
+ Each time when attribute __provides__ is set an directly provides event
+ is notified:
+
+ >>> from zope.app.testing import placelesssetup
+ >>> placelesssetup.setUp()
+
+ >>> from zope.app.event.tests.placelesssetup import events
+ >>> from zope.interface import directlyProvidedBy
+
+ >>> class IA(Interface):
+ ... pass
+
+ >>> len(events)
+ 0
+
+ >>> bar = Bar()
+ >>> directlyProvides(bar, IA)
+
+ >>> len(events)
+ 1
+ >>> events.pop() # doctest: +ELLIPSIS
+ <zope.generic.directlyprovides.event.DirectlyProvidesModifiedEvent...>
+
+ >>> placelesssetup.tearDown()
+ """
+
+ frame = sys._getframe(1)
+ f_locals = frame.f_locals
+ f_globals = frame.f_globals
+
+ if not (f_locals is not f_globals
+ and f_locals.get('__module__')):
+ raise TypeError('provides not called from suite')
+
+ f_locals['__provides__'] = ProvidesProperty(*names)
+
+
+
+class UpdateProvides(object):
+ """Update the provides attribute after a new value is set.
+
+ Note that UpdateProvides cannot be used with slots. They can only
+ be used for attributes stored in instance dictionaries.
+ """
+
+ def __init__(self, field, before=None, after=None, value_hook=None, ):
+ self.__field = field
+ self.__name = field.__name__
+ self.__before = before
+ self.__after = after
+ self.__value_hook = value_hook
+
+ def __get__(self, inst, klass):
+ if inst is None:
+ return self
+
+ value = inst.__dict__.get(self.__name, _marker)
+ if value is _marker:
+ field = self.__field.bind(inst)
+ value = getattr(field, 'default', _marker)
+ if value is _marker:
+ value = getattr(field, 'missing_value', _marker)
+
+ if value is _marker:
+ raise AttributeError(self.__name)
+
+ return value
+
+ def __set__(self, inst, value):
+
+ previous_value = getattr(inst, self.__name)
+
+ # hook to rearrange values -> ordered features
+ if self.__value_hook:
+ value = self.__value_hook(inst, value, previous_value)
+
+ if value != previous_value:
+ # validate the value
+ field = self.__field.bind(inst)
+ field.validate(value)
+
+ # invoke before
+ if self.__before:
+ self.__before(inst, value, previous_value)
+
+ # store value within __dict__
+ if value is not getattr(field, 'missing_value', _marker):
+ inst.__dict__[self.__name] = value
+ else:
+ if self.__name in inst.__dict__:
+ del inst.__dict__[self.__name]
+
+ # update directly provides
+ updateDirectlyProvided(inst, value, previous_value)
+
+ # invoke after
+ if self.__after:
+ self.__after(inst, value, previous_value)
+
+ def __getattr__(self, name):
+ return getattr(self.__field, name)
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/property.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/testing.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/testing.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.testing import ztapi
+import zope.generic.testing.testing
+
+
+################################################################################
+#
+# Public Test implementations
+#
+################################################################################
+
+
+
+################################################################################
+#
+# Placeless setup
+#
+################################################################################
+
+
+
+class PlacelessSetup(zope.generic.testing.testing.PlacelessSetup):
+
+ def setUp(self, doctesttest=None):
+ super(PlacelessSetup, self).setUp(doctesttest)
+
+ # handlers
+ from zope.generic.directlyprovides.handler import notifyObjectModifiedEvent
+ from zope.generic.directlyprovides import IDirectlyProvidesModifiedEvent
+ ztapi.subscribe([IDirectlyProvidesModifiedEvent],
+ None, notifyObjectModifiedEvent)
+
+ def tearDown(self, doctesttest=None):
+ super(PlacelessSetup, self).tearDown()
+
+
+
+placelesssetup = PlacelessSetup()
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/tests.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/tests.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""Package zope.generic.directlyprovides.
+
+$Id$
+"""
+
+import unittest
+
+from zope import component
+from zope import interface
+from zope import schema
+from zope.testing import doctest
+
+from zope.generic.directlyprovides.testing import placelesssetup, ztapi
+from zope.generic.testing.testing import registerDirective
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite('zope.generic.directlyprovides.helper'),
+ doctest.DocTestSuite('zope.generic.directlyprovides.property'),
+ doctest.DocTestSuite('zope.generic.directlyprovides.event'),
+ doctest.DocFileSuite('README.txt',
+ setUp=placelesssetup.setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'schema': schema, 'ztapi': ztapi,
+ 'registerDirective': registerDirective},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
+ ))
+
+if __name__ == '__main__': unittest.main()
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/directlyprovides/zope.generic.directlyprovides-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/directlyprovides/zope.generic.directlyprovides-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/directlyprovides/zope.generic.directlyprovides-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.directlyprovides" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/directlyprovides/zope.generic.directlyprovides-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/CHANGES.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/CHANGES.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/CHANGES.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,4 @@
+=======
+CHANGES
+=======
+
Property changes on: zope.generic/trunk/src/zope/generic/doc/CHANGES.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,20 @@
+============
+zope.generic
+============
+
+Software models problem domains. Often we model domain components as object
+of corresponding implementations (classes). Those classes combine generic
+behavior and domain-specific behavior. This packages should help to model problem
+domains using generic implementations that do not provide any domain-specific
+behavior directly but mark instances of those generic implementations
+domain-specifically relying heavily on the directly provide mechanism of the
+zope.interface package.
+
+- .directlyprovides: Better control of the directly provides mechanism
+
+- .configuration: n/a
+
+- .information: Interface-based registrations and registries
+
+- .type: Type generic base classes by marker interfaces.
+
Property changes on: zope.generic/trunk/src/zope/generic/doc/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.doc-*.zcml
+</data-files>
Property changes on: zope.generic/trunk/src/zope/generic/doc/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/doc/TODO.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/TODO.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/TODO.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,7 @@
+====
+TODO
+====
+
+Things to do for the next release (sorted by importance):
+
+
Property changes on: zope.generic/trunk/src/zope/generic/doc/TODO.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
Property changes on: zope.generic/trunk/src/zope/generic/doc/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,35 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:apidoc="http://namespaces.zope.org/apidoc"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ i18n_domain="zope">
+
+ <apidoc:bookchapter zcml:condition="have apidoc"
+ id="zope.generic"
+ title="Zope Generic"
+ />
+
+ <!-- Register documentation with API Doc -->
+
+ <apidoc:bookchapter zcml:condition="have apidoc"
+ id="zope.generic.readme"
+ title="README"
+ doc_path="README.txt"
+ parent="zope.generic"
+ />
+
+ <apidoc:bookchapter zcml:condition="have apidoc"
+ id="zope.generic.changes"
+ title="CHANGES"
+ doc_path="CHANGES.txt"
+ parent="zope.generic"
+ />
+
+ <apidoc:bookchapter zcml:condition="have apidoc"
+ id="zope.generic.todo"
+ title="TODO"
+ doc_path="TODO.txt"
+ parent="zope.generic"
+ />
+
+</configure>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/doc/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/doc/zope.generic.doc-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/doc/zope.generic.doc-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/doc/zope.generic.doc-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.doc" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/doc/zope.generic.doc-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/information/DEPENDENCIES.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/DEPENDENCIES.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,9 @@
+zope.generic.configuration
+zope.generic.testing
+zope.app.annotation
+zope.app.component
+zope.component
+zope.configuration
+zope.interface
+zope.schema
+zope.testing
Property changes on: zope.generic/trunk/src/zope/generic/information/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/information/PUBLICATION.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/information/PUBLICATION.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/PUBLICATION.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,11 @@
+Metadata-Version: 1.0
+Name: zope.generic.information
+Summary: Information about interface based registrations
+Author: Dominik Huber, Perse Engineering GmbH, Switzerland
+Author-email: dominik.huber at perse.ch
+License: ZPL 2.1
+Description:
+ Provide facility for reusable information registry. The information
+ registries are implemented as utility providing IInformationRegistry.
+ The name of the registry is given by the dotted name of the interface
+ of the deciated information collected by the information registry.
Property changes on: zope.generic/trunk/src/zope/generic/information/PUBLICATION.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/information/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/information/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,182 @@
+===========
+Information
+===========
+
+The generic package relies heavily on interfaces. Often we have relation between
+different interfaces. Informations provides dedicated data about an certain
+marker interface. Informations are implemented as utility. The package provides
+some convenience functions and directives.
+
+An information offers annotations and configurations.
+
+Example
+-------
+
+You can use the information directive to register an information as utiliy
+under registry-interface using the dotted name of the interface as utility name:
+
+ >>> from zope.generic.information import api
+
+ >>> class ISpecialInformation(api.IInformation):
+ ... pass
+
+ >>> from zope.interface import Interface
+ >>> class IFooMarker(Interface):
+ ... pass
+
+ # make available within the testing module
+ >>> testing.ISpecialInformation, testing.IFooMarker = ISpecialInformation, IFooMarker
+ >>> IFooMarker.__module__ = ISpecialInformation.__module = 'zope.generic.information.testing'
+
+ >>> registerDirective('''
+ ... <generic:information
+ ... interface="zope.generic.information.testing.IFooMarker"
+ ... registry="zope.generic.information.testing.ISpecialInformation"
+ ... label='Foo Specials' hint='Bla bla foo.'
+ ... />
+ ... ''')
+
+Afterward the information can be queried using the following method:
+
+ >>> info = api.queryInformation(IFooMarker, ISpecialInformation)
+
+ >>> info.interface == IFooMarker
+ True
+ >>> ISpecialInformation.providedBy(info)
+ True
+ >>> info.label = u'Foo Specials'
+ >>> info.hint = u'Bla bla foo.'
+
+ >>> listing = list(api.registeredInformations(ISpecialInformation))
+ >>> len(listing) is 1
+ True
+ >>> listing[0][1] == info
+ True
+ >>> listing[0][0] == IFooMarker
+ True
+
+If no information is available for a certain interface the defined default
+value is returned:
+
+ >>> class IBarMarker(Interface):
+ ... pass
+
+ >>> default = object()
+ >>> info = api.queryInformation(IBarMarker, ISpecialInformation, default)
+ >>> info is default
+ True
+
+ >>> info = api.queryInformation(IBarMarker, ISpecialInformation)
+ >>> info is None
+ True
+
+Annotatable Informations
+------------------------
+
+Informations are annotable. The annotations mechanism is used to provide
+additional information in a generic manner by adaption:
+
+ >>> from zope.app.annotation.interfaces import IAnnotations
+
+ >>> info = api.queryInformation(IFooMarker, ISpecialInformation)
+
+ >>> annotations = IAnnotations(info)
+ >>> annotations.get('test.annotation')
+ >>> annotations['test.annotation']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'test.annotation'
+ >>> list(annotations.keys())
+ []
+ >>> del annotations['test.annotation']
+ Traceback (most recent call last):
+ ...
+ KeyError: 'test.annotation'
+ >>> annotations['test.annotation'] = 'a'
+ >>> annotations.get('test.annotation')
+ 'a'
+ >>> annotations['test.annotation']
+ 'a'
+ >>> list(annotations.keys())
+ ['test.annotation']
+ >>> del annotations['test.annotation']
+
+
+Congigurable Informations
+-------------------------
+
+Informations are configurable. The configurations mechanism is used to provide
+additional configurations information in a generic manner. A configuration
+is declared by a configuration schema. This is a regular schema that will be
+typed a IConfigurationType after its registration (see zope.generic.configuration):
+
+ >>> from zope.schema import TextLine
+
+ >>> class IMyConfiguration(interface.Interface):
+ ... my = TextLine(title=u'My')
+
+ # make available within the testing module
+ >>> testing.IMyConfiguration = IMyConfiguration
+
+ >>> registerDirective('''
+ ... <generic:configuration
+ ... interface="zope.generic.information.testing.IMyConfiguration"
+ ... label='My' hint='My bla.'
+ ... />
+ ... ''')
+
+ >>> from zope.generic.configuration import IConfigurationType
+ >>> IConfigurationType.providedBy(IMyConfiguration)
+ True
+
+For the further exploration we query this information:
+
+ >>> from zope.generic.configuration.api import queryConfigurationInformation
+ >>> from zope.generic.configuration.api import IConfigurationInformation
+
+ >>> my_configuration_information = queryConfigurationInformation(IMyConfiguration)
+ >>> my_configuration_information.interface == IMyConfiguration
+ True
+ >>> IConfigurationInformation.providedBy(my_configuration_information)
+ True
+
+We now use this configuration to extend our information about our IFooMarker.
+Before that there will be no configuration:
+
+ >>> from zope.generic.configuration.api import IConfigurations
+
+ >>> info_configurations = IConfigurations(info)
+ >>> IMyConfiguration(info_configurations, None) is None
+ True
+
+ or simply:
+ >>> from zope.generic.configuration.api import queryConfigurationData
+
+ >>> queryConfigurationData(info, IMyConfiguration)is None
+ True
+
+The configuration subdirective of the information directive provides a mechanism
+to register further configurations to an information:
+
+ >>> from zope.generic.configuration.api import ConfigurationData
+ >>> my_information_config = ConfigurationData(IMyConfiguration, {'my': u'My!'})
+
+ # make available within the testing module
+ >>> testing.my_information_config = my_information_config
+
+ >>> registerDirective('''
+ ... <generic:information
+ ... interface="zope.generic.information.testing.IFooMarker"
+ ... registry="zope.generic.information.testing.ISpecialInformation"
+ ... label='Foo Specials' hint='Bla bla foo.'
+ ... >
+ ... <configuration
+ ... interface="zope.generic.information.testing.IMyConfiguration"
+ ... data="zope.generic.information.testing.my_information_config"
+ ... />
+ ... </generic:information>
+ ... ''')
+
+ >>> info = api.queryInformation(IFooMarker, ISpecialInformation)
+ >>> queryConfigurationData(info, IMyConfiguration) is my_information_config
+ True
Property changes on: zope.generic/trunk/src/zope/generic/information/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/information/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.information-*.zcml
+</data-files>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/information/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/information/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.generic.information.interfaces import *
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/information/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/api.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/api.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+# usage see README.txt
+from zope.generic.information.interfaces import *
+
+from zope.generic.information.base import Information
+from zope.generic.information.helper import dottedName
+from zope.generic.information.helper import queryInformation
+from zope.generic.information.helper import registeredInformations
+from zope.generic.information.metaconfigure import provideInformation
Property changes on: zope.generic/trunk/src/zope/generic/information/api.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/base.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/base.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/base.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,101 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.interface import alsoProvides
+from zope.interface import implements
+
+from zope.generic.configuration import IAttributeConfigurable
+from zope.app.i18n import ZopeMessageFactory as _
+
+from zope.generic.information import IInformation
+from zope.generic.information import IInformationDescription
+from zope.generic.information.helper import dottedName
+
+
+
+class InformationDescription(object):
+ """Information description."""
+
+ implements(IInformationDescription)
+
+ def __init__(self, interface, label=None, hint=None):
+ self.interface = interface
+
+ if label is None:
+ self.label = _(dottedName(interface))
+ else:
+ self.label = label
+
+ if hint is None:
+ self.hint = _('No hint available.')
+ else:
+ self.hint = hint
+
+
+
+class Information(InformationDescription, dict):
+ """Default information.
+
+ Information do relate a dedicated type of information marked as an interface
+ extending IInformation and another marker interface:
+
+ >>> class ISpecialInformation(IInformation):
+ ... pass
+
+ >>> from zope.interface import Interface
+ >>> class IFooMarker(Interface):
+ ... pass
+
+ >>> info = Information(IFooMarker, ISpecialInformation)
+
+ The information will provide the interface of the dedicated information:
+
+ >>> ISpecialInformation.providedBy(info)
+ True
+
+ The information is related to the interface declared by the interface
+ attribute:
+
+ >>> info.interface == IFooMarker
+ True
+ >>> info.label
+ u'zope.generic.information.base.IFooMarker'
+
+ >>> info.hint
+ u'No hint available.'
+
+
+ Often you will provide a specific label and hint for the end-user:
+
+ >>> info = Information(IFooMarker, ISpecialInformation, u'Foo', u'Bla bla.')
+ >>> info.label
+ u'Foo'
+
+ >>> info.hint
+ u'Bla bla.'
+ """
+
+ implements(IInformation, IAttributeConfigurable, IAttributeAnnotatable)
+
+ def __init__(self, interface, provides, label=None, hint=None):
+ super(Information, self).__init__(interface, label, hint)
+ alsoProvides(self, provides)
+
Property changes on: zope.generic/trunk/src/zope/generic/information/base.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/information/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,12 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:generic="http://namespaces.zope.org/generic"
+ i18n_domain="zope">
+
+ <generic:information
+ interface=".IInformationRegistryInformation"
+ label="Information Registry Information"
+ registry=".IInformationRegistryInformation"
+ />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/information/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/helper.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/helper.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,50 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.component import getUtility
+from zope.component import getUtilitiesFor
+
+from zope.generic.configuration.api import resolveClass
+
+
+
+def dottedName(klass):
+ if klass is None:
+ return 'None'
+ return klass.__module__ + '.' + klass.__name__
+
+
+
+def getInformation(interface, registry):
+ return getUtility(registry, dottedName(interface))
+
+
+
+def queryInformation(interface, registry, default=None):
+ try:
+ return getInformation(interface, registry)
+
+ except:
+ return default
+
+
+def registeredInformations(registry, default=None):
+ for name, information in getUtilitiesFor(registry):
+ yield (resolveClass(name), information)
Property changes on: zope.generic/trunk/src/zope/generic/information/helper.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/interfaces.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/interfaces.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/interfaces.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,73 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface
+from zope.interface.interfaces import IInterface
+from zope.schema import Object
+from zope.schema import Text
+from zope.schema import TextLine
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+
+
+__all__ = ['IInformationDeclaration', 'IInformationDescription', 'IInformation',
+ 'IInformationRegistryInformation']
+
+
+
+class IInformationDeclaration(Interface):
+ """Declare an interface as information-specific-key."""
+
+ interface = Object(
+ title=_('Interface'),
+ description=_('Interface marker that references corresponding informations.'),
+ required=True,
+ schema=IInterface)
+
+
+
+class IInformationDescription(IInformationDeclaration):
+ """Describe the associated information declaration."""
+
+ label = TextLine(title=_('Label'),
+ description=_('Label for the registered interface marker.'),
+ required=True
+ )
+
+ hint = Text(title=_('Hint'),
+ description=_('Hint explaning the properties of the registered interface marker.'),
+ required=True
+ )
+
+
+
+class IInformation(IInformationDescription):
+ """Inform about an subject referenced by an interface-key.
+
+ Additional information can be stored within the information's annotations
+ or configurations.
+
+ Implementation should be adaptable to IConfigurations and IAnnotations."""
+
+
+
+class IInformationRegistryInformation(IInformation):
+ """Provide information about registered information registries."""
Property changes on: zope.generic/trunk/src/zope/generic/information/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/information/meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,22 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta">
+
+ <meta:directives namespace="http://namespaces.zope.org/generic">
+
+ <meta:complexDirective
+ name="information"
+ schema=".metadirectives.IInformationDirective"
+ handler=".metaconfigure.InformationDirective"
+ >
+
+ <meta:subdirective
+ name="configuration"
+ schema=".metadirectives.IConfigurationSubdirective"
+ />
+
+ </meta:complexDirective>
+
+ </meta:directives>
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/information/meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/metaconfigure.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/metaconfigure.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,133 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Projekt01 GmbH and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.app.component.interface import provideInterface
+from zope.component import provideUtility
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import alsoProvides
+
+from zope.generic.configuration.api import IConfigurations
+
+from zope.generic.information import IInformation
+from zope.generic.information.base import Information
+from zope.generic.information.helper import dottedName
+from zope.generic.information.helper import queryInformation
+
+
+
+def provideInformation(interface, registry, label=None, hint=None, factory=None):
+ """Provide new information for the given registry-interface.
+
+ Register an information as utiliy under registry-interface using
+ the dotted name of the interface as utility name:
+
+ >>> class ISpecialInformation(IInformation):
+ ... pass
+
+ >>> from zope.interface import Interface
+ >>> class IFooMarker(Interface):
+ ... pass
+
+ >>> provideInformation(IFooMarker, ISpecialInformation)
+
+ The information can be queried using the following method:
+
+ >>> from zope.generic.information.helper import queryInformation
+ >>> info = queryInformation(IFooMarker, ISpecialInformation)
+ >>> info.interface == IFooMarker
+ True
+ >>> ISpecialInformation.providedBy(info)
+ True
+
+ """
+
+ # precondition
+ if not registry.extends(IInformation):
+ raise ValueError('Registry must extend %s.' % IInformation.__name__)
+
+ if factory is None:
+ factory = Information
+
+ component = factory(interface, registry, label, hint)
+
+ if not registry.providedBy(component):
+ raise ValueError('Factory must implement %s.' % registry.__name__)
+
+ provideUtility(component, provides=registry, name=dottedName(interface))
+
+
+
+def provideConfiguration(interface, registry, configuration, data):
+ """Provide configuration for a certain type marker."""
+
+ info = queryInformation(interface, registry)
+
+ configurations = IConfigurations(info)
+ configurations[configuration] = data
+
+
+
+class InformationDirective(object):
+ """Provide a new information of a certain information registry."""
+
+ _interface_type = None
+
+ def __init__(self, _context, interface, registry, label=None, hint=None):
+ self._interface = interface
+ self._context = _context
+ self._registry = registry
+
+ # assert type as soon as possible
+ if self._interface_type is not None:
+ alsoProvides(interface, self._interface_type)
+
+ _context.action(
+ discriminator = ('provideInformation', self._interface, self._registry),
+ callable = provideInformation,
+ args = (self._interface, self._registry, label, hint),
+ )
+
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = (None, self._interface),
+ )
+
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = (None, self._registry),
+ )
+
+ def __call__(self):
+ "Handle empty/simple declaration."
+ return ()
+
+ def configuration(self, _context, interface, data):
+ # preconditions
+ if not interface.providedBy(data):
+ raise ConfigurationError('Data attribute must provide %s.' % interface.__name__)
+
+ _context.action(
+ discriminator = (
+ 'InformationConfiguration', self._interface, self._registry, interface),
+ callable = provideConfiguration,
+ args = (self._interface, self._registry, interface, data),
+ )
Property changes on: zope.generic/trunk/src/zope/generic/information/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/metadirectives.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/metadirectives.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/metadirectives.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,82 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.fields import GlobalInterface
+from zope.configuration.fields import GlobalObject
+from zope.configuration.fields import MessageID
+from zope.interface import Interface
+
+from zope.app.i18n import ZopeMessageFactory as _
+
+from zope.generic.information import IInformation
+
+
+
+class IBaseInformationDirective(Interface):
+ """Base information attributes."""
+
+ interface = GlobalInterface(
+ title=_('Interface'),
+ description=_('Interface that represents an information.'),
+ required=True
+ )
+
+ label = MessageID(
+ title=_('Label'),
+ description=_('Label of the information.'),
+ required=False
+ )
+
+ hint = MessageID(
+ title=_('Hint'),
+ description=_('Hint of the informtion.'),
+ required=False
+ )
+
+
+
+class IInformationDirective(IBaseInformationDirective):
+ """Directive for informations and information registries."""
+
+ registry = GlobalInterface(
+ title=_('Information Registry Key'),
+ description=_('A registry key is a dedicated interface which should extend' +
+ 'IInformation.'),
+ required=True,
+ constraint=lambda v: v.extends(IInformation)
+ )
+
+
+
+class IConfigurationSubdirective(Interface):
+ """Declare a certain configuration of a type."""
+
+ interface = GlobalInterface(
+ title=_('Interface'),
+ description=_('Interface referencing a configuraiton.'),
+ required=True
+ )
+
+ data = GlobalObject(
+ title=_('Data'),
+ description=_('Configuration data component providing the configuraiton interface.'),
+ required=True
+ )
+
Property changes on: zope.generic/trunk/src/zope/generic/information/metadirectives.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/testing.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/testing.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.xmlconfig import XMLConfig
+
+import zope.generic.testing.testing
+
+
+
+################################################################################
+#
+# Public Test implementations
+#
+################################################################################
+
+
+
+################################################################################
+#
+# Placeless setup
+#
+################################################################################
+
+
+class PlacelessSetup(zope.generic.testing.testing.PlacelessSetup):
+
+ def setUp(self, doctesttest=None):
+ super(PlacelessSetup, self).setUp(doctesttest)
+
+ # register the directive of this package
+ import zope.generic.information
+ XMLConfig('meta.zcml', zope.generic.information)()
+
+
+ def tearDown(self, doctesttest=None):
+ super(PlacelessSetup, self).tearDown(doctesttest)
+
+
+
+placelesssetup = PlacelessSetup()
Property changes on: zope.generic/trunk/src/zope/generic/information/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/information/tests.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/tests.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+import unittest
+
+from zope import component
+from zope import interface
+from zope.testing import doctest
+
+from zope.generic.configuration.testing import placelesssetup
+from zope.generic.testing.testing import registerDirective
+
+from zope.generic.information import testing
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite('zope.generic.information.base'),
+ doctest.DocTestSuite('zope.generic.information.metaconfigure'),
+ doctest.DocFileSuite('README.txt',
+ setUp=placelesssetup.setUp,
+ tearDown=placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'registerDirective': registerDirective,
+ 'testing': testing},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
+ ))
+
+if __name__ == '__main__': unittest.main()
Property changes on: zope.generic/trunk/src/zope/generic/information/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/zope.generic.information-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/information/zope.generic.information-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/zope.generic.information-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.information" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/information/zope.generic.information-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/information/zope.generic.information-meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/information/zope.generic.information-meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/information/zope.generic.information-meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.information" file="meta.zcml" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/information/zope.generic.information-meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/testing/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/DEPENDENCIES.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/DEPENDENCIES.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,7 @@
+zope.app.annotation
+zope.app.component
+zope.app.security
+zope.app.testing
+zope.component
+zope.configuration
+zope.interface
Property changes on: zope.generic/trunk/src/zope/generic/testing/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/testing/PUBLICATION.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/PUBLICATION.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/PUBLICATION.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,8 @@
+Metadata-Version: 1.0
+Name: zope.generic.testing
+Summary: Basic Testing Facility for zope.generic
+Author: Dominik Huber, Perse Engineering GmbH, Switzerland
+Author-email: dominik.huber at perse.ch
+License: ZPL 2.1
+Description:
+ Basic Testing Facility for zope.generic
Property changes on: zope.generic/trunk/src/zope/generic/testing/PUBLICATION.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/testing/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+=======
+Testing
+=======
+
+Provide basic testing facility for the zope.generic namespace.
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/testing/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/testing/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.testing-*.zcml
+</data-files>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/testing/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/testing/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,17 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
Property changes on: zope.generic/trunk/src/zope/generic/testing/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/testing/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,6 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:generic="http://namespaces.zope.org/generic"
+ i18n_domain="zope">
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/testing/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/testing/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/testing.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/testing.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+
+from cStringIO import StringIO
+from zope.configuration.xmlconfig import XMLConfig
+from zope.configuration.xmlconfig import xmlconfig
+from zope.interface.verify import verifyClass
+from zope.interface.verify import verifyObject
+import unittest
+
+from zope.component import provideAdapter
+import zope.app.testing.placelesssetup
+
+
+################################################################################
+#
+# Base Test implementations
+#
+################################################################################
+
+
+
+_marker_pos = object()
+_marker_kws = object()
+
+class InterfaceBaseTest(unittest.TestCase):
+ """Base class for interface based unit tests."""
+
+ _test_interface = None
+ _test_class = None
+ _test_pos = None
+ _test_kws = None
+ _verify_class = True
+ _verify_object = True
+
+ def makeTestObject(self, *pos, **kws):
+ # assert defaults for positional or keyword arguments
+ if not pos and self._test_pos is not None:
+ pos = self._test_pos
+
+ if not kws and self._test_kws is not None:
+ kws = self._test_kws
+
+ return self._test_class(*pos, **kws)
+
+ def test_verify_class(self):
+ if self._verify_class:
+ self.assert_(verifyClass(self._test_interface, self._verify_class))
+
+ def test_verify_object(self):
+ if self._verify_object:
+ self.assert_(verifyObject(self._test_interface, self.makeTestObject()))
+
+
+
+################################################################################
+#
+# Placeless setup
+#
+################################################################################
+
+# helper for directive testing
+template = """<configure
+ xmlns='http://namespaces.zope.org/zope'
+ xmlns:generic='http://namespaces.zope.org/generic'
+ xmlns:test='http://www.zope.org/NS/Zope3/test'
+ i18n_domain='zope'>
+ %s
+ </configure>"""
+
+
+def registerDirective(direcitive):
+ xmlconfig(StringIO(template % direcitive))
+
+
+
+class PlacelessSetup(zope.app.testing.placelesssetup.PlacelessSetup):
+
+ def setUp(self, doctesttest=None):
+ super(PlacelessSetup, self).setUp(doctesttest)
+
+ # zope.app.annotations
+ from zope.app.annotation.interfaces import IAnnotations
+ from zope.app.annotation.interfaces import IAttributeAnnotatable
+ from zope.app.annotation.attribute import AttributeAnnotations
+
+ provideAdapter(AttributeAnnotations, adapts=[IAttributeAnnotatable],
+ provides=IAnnotations)
+
+ # zcml configurations
+ import zope.app.component
+ XMLConfig('meta.zcml', zope.app.component)()
+ import zope.app.security
+ XMLConfig('meta.zcml', zope.app.security)()
+
+ def tearDown(self, doctesttest=None):
+ super(PlacelessSetup, self).tearDown()
+
+
+
+placelesssetup = PlacelessSetup()
Property changes on: zope.generic/trunk/src/zope/generic/testing/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/testing/zope.generic.testing-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/testing/zope.generic.testing-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/testing/zope.generic.testing-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.testing" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/testing/zope.generic.testing-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/DEPENDENCIES.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/type/DEPENDENCIES.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/DEPENDENCIES.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,15 @@
+persistent
+zope.generic.configuration
+zope.generic.directlyprovides
+zope.generic.information
+zope.generic.testing
+zope.app.annotation
+zope.app.component
+zope.app.container
+zope.app.folder
+zope.component
+zope.configuration
+zope.interface
+zope.schema
+zope.security
+zope.testing
Property changes on: zope.generic/trunk/src/zope/generic/type/DEPENDENCIES.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/type/PUBLICATION.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/type/PUBLICATION.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/PUBLICATION.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,9 @@
+Metadata-Version: 1.0
+Name: zope.generic.informed
+Summary: Provide a logical type facility
+Author: Dominik Huber, Perse Engineering GmbH, Switzerland
+Author-email: dominik.huber at perse.ch
+License: ZPL 2.1
+Description:
+ An object provides often serval interfaces. This package provides a
+ interace based type assoziation in a way like *classes* or *types* do.
Property changes on: zope.generic/trunk/src/zope/generic/type/PUBLICATION.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/type/README.txt
===================================================================
--- zope.generic/trunk/src/zope/generic/type/README.txt 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/README.txt 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,240 @@
+====
+Type
+====
+
+An object provides often serval interfaces. This package provides a interace
+based type assoziation in a way like *classes* or *types* do. Typeable object
+provides by adaption or implementation access to a type marker. This type
+marker can be used to lookup further information about the referenced type.
+
+For each interface typed by our type marker type (ITypeType) we provied a type
+factory that can create instaces of this certain *logical* type.
+
+Furthermore a type information utility will be provided. This type information
+allows to annotate additonal stuff like using the annotations and configurations
+mechanism.
+
+Informations provided by the type information should be accounted by the handling
+of instances marked by a certain type marker interface.
+
+The type directive does extend the information directive
+(see zope.generic.information).
+
+
+Base type directive
+-------------------
+
+In our example we register type using the generic:type directive. Therefore we
+need an type marker:
+
+ >>> class IFooMarker(interface.Interface):
+ ... pass
+
+ # make available within the testing module
+ >>> testing.IFooMarker = IFooMarker
+
+The only thing to register a specific logical type is this type marker interface.
+The package offers four different generic implementation such as Object,
+Contained, Container and Folder (Site) that you might use as implementation of
+your logical type. Certainly you can provide your own implementation. Such an
+implementation should implement at least the marker ITypeable and a corresponding
+adapter to ITyped.
+
+In our example we will use a simple generic object:
+
+ >>> from zope.generic.type import api
+ >>> api.ITypeable.implementedBy(api.Object)
+ True
+ >>> api.IDirectlyTyped.implementedBy(api.Object)
+ True
+
+ >>> registerDirective('''
+ ... <generic:type
+ ... interface="zope.generic.type.testing.IFooMarker"
+ ... label='Foo Type' hint='Bla bla bla.'
+ ... class='zope.generic.type.api.Object'
+ ... />
+ ... ''')
+
+After the typed is registered the type marker will provide ITypeType:
+
+ >>> from zope.generic.type import api
+
+ >>> api.ITypeType.providedBy(IFooMarker)
+ True
+
+You can create instances of the registered logical type:
+
+ >>> foo = api.createObject(IFooMarker)
+ >>> typed = api.ITyped(foo)
+ >>> typed.interface == IFooMarker
+ True
+
+In our example we use a generic directly typed implementation. In those cases
+the instance will provide the type marker too:
+
+ >>> IFooMarker.providedBy(foo)
+ True
+
+A corresponding type information utility will be available. Your can
+retrieve this utility using the conventional utility api:
+
+ >>> from zope.component import queryUtility
+ >>> from zope.generic.configuration.api import dottedName
+
+ >>> info = queryUtility(api.ITypeInformation, dottedName(IFooMarker))
+
+ >>> info.interface == IFooMarker
+ True
+ >>> info.label
+ u'Foo Type'
+ >>> info.hint
+ u'Bla bla bla.'
+
+There is convenience function for the lookup of corresponding type information.
+You can lookup the type information by the type marker interface or an object
+providing ITyped by implementation or adaption:
+
+ >>> api.queryTypeInformation(IFooMarker) == info
+ True
+
+ >>> api.queryTypeInformation(foo) == info
+ True
+
+
+Type subdirectives
+------------------
+
+There are serveral subdirectives like:
+
+- configurations (see zope.generic.information)
+- initializer
+
+You can extend type informations by the annotations and configurations mechanism
+like the information will do.
+
+First we will provide a new bar type including an additional configuration:
+
+ >>> class IBarMarker(interface.Interface):
+ ... pass
+
+ # make available within the testing module
+ >>> testing.IBarMarker = IBarMarker
+
+Then we provide two example configurations for our example:
+
+ >>> from zope.schema import TextLine
+
+ >>> class IAnyConfiguration(interface.Interface):
+ ... any = TextLine(title=u'Any')
+
+ >>> class IOtherConfiguration(interface.Interface):
+ ... other = TextLine(title=u'Other')
+ ... optional = TextLine(title=u'Other', required=False, default=u'Default bla.')
+
+ # make available within the testing module
+ >>> testing.IAnyConfiguration = IAnyConfiguration
+ >>> testing.IOtherConfiguration = IOtherConfiguration
+ >>> IAnyConfiguration.__module__ = IOtherConfiguration.__module__ = 'zope.generic.type.testing'
+
+ >>> registerDirective('''
+ ... <generic:configuration
+ ... interface="zope.generic.type.testing.IAnyConfiguration"
+ ... label='Any' hint='Any bla.'
+ ... />
+ ... ''')
+
+ >>> registerDirective('''
+ ... <generic:configuration
+ ... interface="zope.generic.type.testing.IOtherConfiguration"
+ ... />
+ ... ''')
+
+ >>> from zope.generic.configuration.api import ConfigurationData
+ >>> typedata = ConfigurationData(IAnyConfiguration, {'any': u'Guguseli from Type!'})
+ >>> IAnyConfiguration.providedBy(typedata)
+ True
+
+ # make available within the testing module
+ >>> testing.typedata = typedata
+
+We can provide a specific intializer:
+
+ >>> def barInitializer(context, *pos, **kws):
+ ... print 'Initializing ...'
+
+ # make available within the testing module
+ >>> testing.barInitializer = barInitializer
+
+After all we register our component using the type directive:
+
+ >>> registerDirective('''
+ ... <generic:type
+ ... interface="zope.generic.type.testing.IBarMarker"
+ ... label='Bar Type' hint='Bla bla bla.'
+ ... class='zope.generic.type.api.Object'
+ ... >
+ ... <initializer
+ ... interface='zope.generic.type.testing.IOtherConfiguration'
+ ... handler='zope.generic.type.testing.barInitializer'
+ ... />
+ ... <configuration
+ ... interface='zope.generic.type.testing.IAnyConfiguration'
+ ... data='zope.generic.type.testing.typedata'
+ ... />
+ ... </generic:type>
+ ... ''')
+
+Now we can create an instance of the logical type. We defined an initializer
+interface. Doing the **kws parameter are stored as configuration to the object.
+If we do not satify the declaration an KeyError is raised:
+
+ >>> api.createParameter(IBarMarker) == IOtherConfiguration
+ True
+
+ >>> bar = api.createObject(IBarMarker)
+ Traceback (most recent call last):
+ ...
+ KeyError: 'Missed keys: other.'
+
+ >>> bar = api.createObject(IBarMarker, **{'other': u'Specific initialization data.'})
+ Initializing ...
+
+This registration attached the specific configuration to the type information.
+You can retrieve type information by a typed instance or the marker type itself
+using the following convenience function:
+
+ >>> api.queryTypeConfiguration(IBarMarker, IAnyConfiguration).any
+ u'Guguseli from Type!'
+
+ >>> api.queryTypeConfiguration(bar, IAnyConfiguration).any
+ u'Guguseli from Type!'
+
+ >>> api.queryTypeConfiguration(IBarMarker, IOtherConfiguration) is None
+ True
+
+This configuration is type specific. You cannot lookup any object- or
+instance-specific configuration, but you can use a function that `acquires`
+different configurations:
+
+ >>> api.queryObjectConfiguration(bar, IAnyConfiguration) is None
+ True
+
+ >>> api.queryObjectConfiguration(bar, IOtherConfiguration).other
+ u'Specific initialization data.'
+
+ >>> api.acquireObjectConfiguration(bar, IAnyConfiguration).any
+ u'Guguseli from Type!'
+
+ >>> api.acquireObjectConfiguration(bar, IOtherConfiguration).other
+ u'Specific initialization data.'
+
+ >>> from zope.generic.configuration.api import IConfigurations
+ >>> objectdata = ConfigurationData(IAnyConfiguration, {'any': u'Guguseli from Object!'})
+ >>> IConfigurations(bar)[IAnyConfiguration] = objectdata
+
+ >>> api.queryObjectConfiguration(bar, IAnyConfiguration).any
+ u'Guguseli from Object!'
+
+ >>> api.acquireObjectConfiguration(bar, IAnyConfiguration).any
+ u'Guguseli from Object!'
Property changes on: zope.generic/trunk/src/zope/generic/type/README.txt
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/SETUP.cfg
===================================================================
--- zope.generic/trunk/src/zope/generic/type/SETUP.cfg 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/SETUP.cfg 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ zope.generic.type-*.zcml
+</data-files>
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/type/SETUP.cfg
___________________________________________________________________
Name: svn:keywords
+ Id
Added: zope.generic/trunk/src/zope/generic/type/__init__.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/__init__.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/__init__.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+from zope.generic.type.interfaces import *
\ No newline at end of file
Property changes on: zope.generic/trunk/src/zope/generic/type/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/adapter.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/adapter.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/adapter.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from BTrees.OOBTree import OOBTree
+import transaction
+from UserDict import DictMixin
+
+from zope.app.location import Location
+from zope.app.location.interfaces import ILocation
+from zope.component import adapts
+from zope.event import notify
+from zope.interface import implements
+
+from zope.generic.configuration.api import provideConfigurationData
+
+from zope.generic.type import IInitializer
+from zope.generic.type import IInitializerConfiguration
+from zope.generic.type import ITypeable
+from zope.generic.type.api import queryTypeConfiguration
+
+
+
+class Initializer(object):
+ """Initialize an object."""
+
+ implements(IInitializer)
+
+ adapts(ITypeable)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, *pos, **kws):
+ config = queryTypeConfiguration(self.context, IInitializerConfiguration)
+ if config:
+ # store initialization data
+ if config.interface:
+ provideConfigurationData(self.context, config.interface, kws)
+
+ # invoke initialization handler
+ if config.handler:
+ config.handler(self.context, *pos, **kws)
Property changes on: zope.generic/trunk/src/zope/generic/type/adapter.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/api.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/api.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/api.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,31 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+# usage see README.txt
+from zope.generic.type.interfaces import *
+from zope.generic.type.base import Object
+from zope.generic.type.base import Contained
+from zope.generic.type.base import Container
+from zope.generic.type.base import Folder
+
+from zope.generic.type.helper import acquireObjectConfiguration
+from zope.generic.type.helper import createObject
+from zope.generic.type.helper import createParameter
+from zope.generic.type.helper import queryObjectConfiguration
+from zope.generic.type.helper import queryTypeConfiguration
+from zope.generic.type.helper import queryTypeInformation
Property changes on: zope.generic/trunk/src/zope/generic/type/api.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/base.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/base.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/base.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,112 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from persistent import Persistent
+
+from zope.interface import implements
+
+from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.container import contained
+from zope.app.container import btree
+from zope.app import folder
+
+from zope.generic.configuration.api import IAttributeConfigurable
+from zope.generic.directlyprovides.api import provides
+from zope.generic.directlyprovides.api import UpdateProvides
+from zope.generic.directlyprovides.api import updateDirectlyProvided
+
+from zope.generic.type import IDirectlyTyped
+from zope.generic.type import IInitializer
+
+
+
+class Object(object):
+ """Default implementation for simple objects."""
+
+ implements(IDirectlyTyped, IAttributeConfigurable, IAttributeAnnotatable)
+
+ def __init__(self, interface, *pos, **kws):
+ super(Object, self).__init__()
+ self.__dict__['interface'] = interface
+ updateDirectlyProvided(self, interface)
+ initializer = IInitializer(self, None)
+ if initializer:
+ initializer(*pos, **kws)
+
+ provides('interface')
+
+ interface = UpdateProvides(IDirectlyTyped['interface'])
+
+
+
+class Contained(contained.Contained, Persistent):
+ """Default implementation local, persistend and contained objects."""
+
+ implements(IDirectlyTyped, IAttributeConfigurable, IAttributeAnnotatable)
+
+ def __init__(self, interface, *pos, **kws):
+ super(Contained, self).__init__()
+ self.__dict__['interface'] = interface
+ updateDirectlyProvided(self, interface)
+ initializer = IInitializer(self, None)
+ if initializer:
+ initializer(*pos, **kws)
+
+ provides('interface')
+
+ interface = UpdateProvides(IDirectlyTyped['interface'])
+
+
+
+class Container(btree.BTreeContainer):
+ """Default implementation local, persistend and containerish objects."""
+
+ implements(IDirectlyTyped, IAttributeConfigurable, IAttributeAnnotatable)
+
+ def __init__(self, interface, *pos, **kws):
+ super(Container, self).__init__()
+ self.__dict__['interface'] = interface
+ updateDirectlyProvided(self, interface)
+ initializer = IInitializer(self, None)
+ if initializer:
+ initializer(*pos, **kws)
+
+ provides('interface')
+
+ interface = UpdateProvides(IDirectlyTyped['interface'])
+
+
+
+class Folder(folder.Folder):
+ """Default implementation local, persistend and containerish possible sites."""
+
+ implements(IDirectlyTyped, IAttributeConfigurable, IAttributeAnnotatable)
+
+ def __init__(self, interface, *pos, **kws):
+ super(Folder, self).__init__()
+ self.__dict__['interface'] = interface
+ updateDirectlyProvided(self, interface)
+ initializer = IInitializer(self, None)
+ if initializer:
+ initializer(*pos, **kws)
+
+ provides('interface')
+
+ interface = UpdateProvides(IDirectlyTyped['interface'])
Property changes on: zope.generic/trunk/src/zope/generic/type/base.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/type/configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,12 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:generic="http://namespaces.zope.org/generic"
+ i18n_domain="zope">
+
+ <generic:information
+ interface="zope.generic.information.IInformationRegistryInformation"
+ label="Type Information Registry"
+ registry=".ITypeInformation"
+ />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/type/configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/factory.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/factory.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/factory.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,120 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import implements
+
+from zope.component.factory import Factory
+from zope.component.interfaces import IFactory
+
+from zope.generic.type import ITypeable
+from zope.generic.type import ITyped
+from zope.generic.type import IDirectlyTyped
+from zope.generic.type import ITypeType
+
+
+
+class TypeFactory(Factory):
+ """Type factory implementation.
+
+ Preset the type interface for generic directly typed implementation
+ of its __init__ method.
+
+ The type factory constructs directly typed objects of a given generic
+ implementation (class).
+
+ First we declare a type marker:
+
+ >>> from zope.interface import Interface
+
+ >>> class IMyMarker(Interface):
+ ... pass
+
+ >>> from zope.app.component.interface import provideInterface
+ >>> provideInterface('', IMyMarker, ITypeType)
+
+ Afterward we build a generic implementation implementing ITyped or a
+ regular typeable class:
+
+ >>> from zope.generic.type import ITyped
+ >>> from zope.generic.directlyprovides.api import provides
+ >>> from zope.generic.directlyprovides.api import UpdateProvides
+ >>> from zope.generic.directlyprovides.api import updateDirectlyProvided
+
+ >>> class Object(object):
+ ... implements(IDirectlyTyped)
+ ...
+ ... def __init__(self, interface, **kws):
+ ... super(Object, self).__init__()
+ ... self.__dict__['interface'] = interface
+ ... updateDirectlyProvided(self, interface)
+ ...
+ ... provides('interface')
+ ... interface = UpdateProvides(ITyped['interface'])
+
+ >>> class Foo(object):
+ ... implements(ITypeable)
+
+ Now we make a factory instance and check it:
+
+ >>> myFactory = TypeFactory(Object, IMyMarker)
+
+ >>> my = myFactory()
+ >>> isinstance(my, Object)
+ True
+ >>> IMyMarker.providedBy(my)
+ True
+
+ >>> ITyped in myFactory.getInterfaces().flattened()
+ False
+ >>> IMyMarker in myFactory.getInterfaces().flattened()
+ True
+
+ >>> myFactory
+ <TypeFactory for <class 'zope.generic.type.factory.Object'>>
+
+ """
+
+ implements(IFactory)
+
+ def __init__(self, callable, interface):
+ # preconditions
+ if not ITypeable.implementedBy(callable):
+ raise ValueError('Callable must implement %s.' % ITypeable.__name__)
+
+ if not ITypeType.providedBy(interface):
+ raise ValueError('Interface must provide %s.' % ITypeType.__name__)
+
+ super(TypeFactory, self).__init__(callable, title='', description='', interfaces=(interface,))
+
+ # essentials
+ self._interface = interface
+
+ def __call__(self, *pos, **kws):
+ if IDirectlyTyped.implementedBy(self._callable):
+ instance = self._callable(self._interface, *pos, **kws)
+
+ else:
+ instance = self._callable(*pos, **kws)
+
+ # TODO: query type information look for InitConfiguration and invoke the
+ # handler if possible
+
+ return instance
+
Property changes on: zope.generic/trunk/src/zope/generic/type/factory.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/helper.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/helper.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/helper.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,119 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope import component
+
+from zope.generic.configuration.api import dottedName
+from zope.generic.configuration.api import queryConfigurationData
+from zope.generic.information.api import queryInformation
+
+from zope.generic.type import IInitializerConfiguration
+from zope.generic.type import ITypeInformation
+from zope.generic.type import ITyped
+from zope.generic.type import ITypeType
+
+
+
+def createObject(interface, *pos, **kws):
+ """Create an instance of a logical type using the type marker."""
+ return component.createObject(dottedName(interface), *pos, **kws)
+
+
+def createParameter(interface):
+ config = queryTypeConfiguration(interface, IInitializerConfiguration)
+ if config:
+ return config.interface
+
+ else:
+ return None
+
+
+
+def getType(object):
+ """Evaluate relevant type marker interface of an object."""
+
+ if ITypeType.providedBy(object):
+ interface = object
+
+ elif ITyped.providedBy(object):
+ interface = object.interface
+
+ else:
+ interface = ITyped(object).interface
+
+ return interface
+
+
+
+def queryType(object, default=None):
+ try:
+ return getType(object)
+
+ except:
+ return default
+
+
+
+def getTypeInformation(object):
+ return queryInformation(getType(object), ITypeInformation)
+
+
+
+def queryTypeInformation(object, default=None):
+ """Lookup an type information of any object."""
+
+ try:
+ return getTypeInformation(object)
+
+ except:
+ return default
+
+
+
+def queryObjectConfiguration(object, configuration, default=None):
+ return queryConfigurationData(object, configuration, default)
+
+
+
+def queryTypeConfiguration(object, configuration, default=None):
+ info = queryTypeInformation(object)
+ return queryConfigurationData(info, configuration, default)
+
+
+
+def acquireTypeConfiguration(object, configuration, default=None):
+ try:
+ interface = getType(object, default)
+
+ except:
+ return default
+
+
+def acquireObjectConfiguration(object, configuration, default=None):
+ # first try to evaluate object configuration data
+ data = queryObjectConfiguration(object, configuration, default)
+
+ if data is not default:
+ return data
+
+ # return type configuration data
+ else:
+ return queryTypeConfiguration(object, configuration, default)
+
Property changes on: zope.generic/trunk/src/zope/generic/type/helper.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/interfaces.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/interfaces.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/interfaces.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,124 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.interface import alsoProvides
+from zope.interface import Interface
+from zope.interface.interfaces import IInterface
+from zope.schema import Bool
+from zope.schema import Object
+
+from zope.generic.configuration import IConfigurationHandler
+from zope.generic.configuration import IConfigurationType
+from zope.generic.directlyprovides import IProvides
+from zope.app.i18n import ZopeMessageFactory as _
+from zope.generic.information import IInformation
+from zope.generic.information import IInformationDeclaration
+
+__all__ = ['ITypeType', 'ITypeable', 'ITyped', 'IDirectlyTyped',
+ 'ITypeInformation', 'IInitializer', 'IInitializationHandler',
+ 'IInitializerConfiguration']
+
+
+
+class ITypeType(IInterface):
+ """An abstract interface marker marker type.
+
+ An interface marked by this marker type will provide an typed information
+ within the corresponding ITypeInformation registry.
+ """
+
+
+
+class ITypeable(Interface):
+ """Assert ITyped by adaption or by implementation."""
+
+
+
+class ITyped(ITypeable, IInformationDeclaration):
+ """Provid an information within the."""
+
+ interface = Object(
+ title=_('Interface'),
+ description=_('Interface marker that references corresponding type informations.'),
+ required=True,
+ schema=ITypeType)
+
+
+
+class IDirectlyTyped(ITyped, IProvides, IInformationDeclaration):
+ """Directly provide the declared interface."""
+
+ def __init__(interface, *pos, **kws):
+ """Directly provide the type interface during the __init__ call."""
+
+ interface = Object(
+ title=_('Interface'),
+ description=_('The declared interface must be directly provided too.'),
+ required=True,
+ readonly=True,
+ schema=ITypeType)
+
+
+
+class ITypeInformation(IInformation):
+ """Provide information for the declared type interface."""
+
+
+
+class IInitializer(Interface):
+ """Initialize an object."""
+
+ def __call__(*pos, **kws):
+ """Invoke initialization handler declared by the initializer configuration."""
+
+
+
+class IInitializationHandler(Interface):
+ """Initialize an object."""
+
+ def __call__(context, *pos, **kws):
+ """Initialize the object referenced by self."""
+
+
+
+class IInitializerConfiguration(Interface):
+ """Provide initialization handler.
+
+ At least a handler or an interface must be defined.
+
+ If the interface is defined, **kws are stored as configuration defined by
+ the interface.
+
+ If the **kws does not satify the interface a KeyError is raised.
+ """
+
+ interface = Object(
+ title=_('Configuration interface'),
+ description=_('Configuration interface defining the signature.'),
+ required=False,
+ schema=IConfigurationType)
+
+ handler = Object(
+ title=_('Initialization Handler'),
+ description=_('Callable (context, *pos, **kws).'),
+ required=False,
+ schema=IInitializationHandler)
+
+alsoProvides(IInitializerConfiguration, IConfigurationType)
Property changes on: zope.generic/trunk/src/zope/generic/type/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/type/meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,27 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:meta="http://namespaces.zope.org/meta">
+
+ <meta:directives namespace="http://namespaces.zope.org/generic">
+
+ <meta:complexDirective
+ name="type"
+ schema=".metadirectives.ITypeDirective"
+ handler=".metaconfigure.TypeDirective"
+ >
+
+ <meta:subdirective
+ name="configuration"
+ schema="zope.generic.information.metadirectives.IConfigurationSubdirective"
+ />
+
+ <meta:subdirective
+ name="initializer"
+ schema="zope.generic.type.metadirectives.IInitializerSubdirective"
+ />
+
+ </meta:complexDirective>
+
+ </meta:directives>
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/type/meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/metaconfigure.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/metaconfigure.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/metaconfigure.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,130 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from types import ModuleType
+
+from zope.app.component.metaconfigure import proxify
+from zope.app.component.metaconfigure import adapter
+from zope.component import provideAdapter
+from zope.component import provideUtility
+from zope.component.interfaces import IFactory
+from zope.configuration.exceptions import ConfigurationError
+from zope.interface import implements
+from zope.security.checker import CheckerPublic
+from zope.security.checker import InterfaceChecker
+
+from zope.generic.configuration.api import ConfigurationData
+from zope.generic.configuration.api import dottedName
+from zope.generic.configuration.api import provideConfigurationData
+from zope.generic.information.metaconfigure import InformationDirective
+
+from zope.generic.type import IInitializationHandler
+from zope.generic.type import IInitializerConfiguration
+from zope.generic.type import ITypeInformation
+from zope.generic.type import ITypeType
+from zope.generic.type.adapter import Initializer
+from zope.generic.type.factory import TypeFactory
+from zope.generic.type.helper import queryTypeInformation
+
+
+
+def provideTypeConfiguration(interface, configuration, data):
+ """Set configuration data into the context."""
+
+ info = queryTypeInformation(interface)
+ provideConfigurationData(info, configuration, data)
+
+
+
+class InitializationHandler(object):
+ """Initialization handler.
+
+ Wrap a callable:
+
+ >>> def callable(context, *pos, **kws):
+ ... print context, pos, kws
+
+ >>> init_handler = InitializationHandler(callable)
+
+ >>> init_handler(1, 2, 3, x=4)
+ 1 (2, 3) {'x': 4}
+
+ """
+
+ implements(IInitializationHandler)
+
+ def __init__(self, callable):
+ self.__callable = callable
+
+ def __call__(self, context, *pos, **kws):
+ self.__callable(context, *pos, **kws)
+
+
+
+class TypeDirective(InformationDirective):
+ """Provide a new logical type."""
+
+ # mark types with a type marker type
+ _interface_type = ITypeType
+
+
+ def __init__(self, _context, interface, class_, label=None, hint=None):
+ # preconditions
+ if isinstance(class_, ModuleType):
+ raise ConfigurationError('Implementation attribute must be a class')
+
+ # register types within the type information registry
+ registry = ITypeInformation
+ super(TypeDirective, self).__init__(_context, interface, registry, label, hint)
+
+ # create and proxy type factory
+ factory = TypeFactory(class_, self._interface)
+ component = proxify(factory, InterfaceChecker(IFactory, CheckerPublic))
+
+ _context.action(
+ discriminator = ('provideUtility', self._interface),
+ callable = provideUtility,
+ args = (component, IFactory, dottedName(self._interface)),
+ )
+
+ def initializer(self, _context, interface=None, handler=None):
+ """Add initializer."""
+ # preconditions
+ if interface is None and handler is None:
+ raise ConfigurationError('Attribute interface or handler must be defined')
+
+ data = {}
+ if handler is not None:
+ if not IInitializationHandler.providedBy(handler):
+ handler = InitializationHandler(handler)
+
+ data['handler'] = handler
+
+ if interface is not None:
+ data['interface'] = interface
+
+ adapter(self._context, [Initializer], None, [self._interface], None, '', True, False)
+
+ _context.action(
+ discriminator = (
+ 'initializer', self._interface),
+ callable = provideTypeConfiguration,
+ args = (self._interface, IInitializerConfiguration, data),
+ )
Property changes on: zope.generic/trunk/src/zope/generic/type/metaconfigure.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/metadirectives.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/metadirectives.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/metadirectives.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,58 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.fields import Bool
+from zope.configuration.fields import GlobalInterface
+from zope.configuration.fields import GlobalObject
+from zope.interface import Interface
+
+from zope.app.i18n import ZopeMessageFactory as _
+from zope.generic.information.metadirectives import IBaseInformationDirective
+
+
+
+class ITypeDirective(IBaseInformationDirective):
+ """Declare attriubtes of the type directive.
+
+ Register an type information and a type factory.
+ """
+
+ class_ = GlobalObject(
+ title=_('Class'),
+ description=_('Generic class implementation.'),
+ required=True
+ )
+
+
+
+class IInitializerSubdirective(Interface):
+ """Provide an initializer configuration for the type."""
+
+ interface = GlobalInterface(
+ title=_('Configuration interface'),
+ description=_('Configuration interface defining the signature.'),
+ required=False
+ )
+
+ handler = GlobalObject(
+ title=_('Initializiation handler'),
+ description=_('Callable (context, *pos, **kws).'),
+ required=False
+ )
Property changes on: zope.generic/trunk/src/zope/generic/type/metadirectives.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/testing.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/testing.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/testing.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,56 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+__docformat__ = 'restructuredtext'
+
+from zope.configuration.xmlconfig import XMLConfig
+
+import zope.generic.configuration.testing
+
+################################################################################
+#
+# Public Test implementations
+#
+################################################################################
+
+def testInitializer(context, *pos, **kws):
+ print context, pos, kws
+
+
+
+################################################################################
+#
+# Placeless setup
+#
+################################################################################
+
+# helper for directive testing
+class PlacelessSetup(zope.generic.configuration.testing.PlacelessSetup):
+
+ def setUp(self, doctesttest=None):
+ super(PlacelessSetup, self).setUp(doctesttest)
+ # register the directive of this package
+ import zope.generic.type
+ XMLConfig('meta.zcml', zope.generic.type)()
+
+ def tearDown(self, doctesttest=None):
+ super(PlacelessSetup, self).tearDown(doctesttest)
+
+
+
+placelesssetup = PlacelessSetup()
Property changes on: zope.generic/trunk/src/zope/generic/type/testing.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/tests.py
===================================================================
--- zope.generic/trunk/src/zope/generic/type/tests.py 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/tests.py 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,45 @@
+##############################################################################
+#
+# Copyright (c) 2005, 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+"""
+$Id$
+"""
+
+import unittest
+
+from zope import component
+from zope import interface
+from zope.testing import doctest
+
+
+from zope.generic.type import testing
+from zope.generic.testing.testing import registerDirective
+
+
+
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocTestSuite('zope.generic.type.factory'),
+ doctest.DocTestSuite('zope.generic.type.metaconfigure'),
+ doctest.DocFileSuite('README.txt',
+ setUp=testing.placelesssetup.setUp,
+ tearDown=testing.placelesssetup.tearDown,
+ globs={'component': component, 'interface': interface,
+ 'registerDirective': registerDirective,
+ 'testing': testing},
+ optionflags=doctest.NORMALIZE_WHITESPACE+
+ doctest.ELLIPSIS),
+ ))
+
+if __name__ == '__main__': unittest.main()
Property changes on: zope.generic/trunk/src/zope/generic/type/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/zope.generic.type-configure.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/type/zope.generic.type-configure.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/zope.generic.type-configure.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.type" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/type/zope.generic.type-configure.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: zope.generic/trunk/src/zope/generic/type/zope.generic.type-meta.zcml
===================================================================
--- zope.generic/trunk/src/zope/generic/type/zope.generic.type-meta.zcml 2006-04-08 20:00:06 UTC (rev 66688)
+++ zope.generic/trunk/src/zope/generic/type/zope.generic.type-meta.zcml 2006-04-08 20:32:57 UTC (rev 66689)
@@ -0,0 +1,5 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+ <include package="zope.generic.type" file="meta.zcml" />
+
+</configure>
Property changes on: zope.generic/trunk/src/zope/generic/type/zope.generic.type-meta.zcml
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Checkins
mailing list