[Checkins] SVN: z3c.configurator/ initial import of the
z3c.configurator package
Bernd Dorn
bernd.dorn at fhv.at
Wed Aug 16 02:51:10 EDT 2006
Log message for revision 69557:
initial import of the z3c.configurator package
The configurator is designed to extend a component after its
creation.
Changed:
A z3c.configurator/
A z3c.configurator/trunk/
A z3c.configurator/trunk/setup.cfg
A z3c.configurator/trunk/setup.py
A z3c.configurator/trunk/src/
A z3c.configurator/trunk/src/z3c/
A z3c.configurator/trunk/src/z3c/__init__.py
A z3c.configurator/trunk/src/z3c/configurator/
A z3c.configurator/trunk/src/z3c/configurator/README.txt
A z3c.configurator/trunk/src/z3c/configurator/__init__.py
A z3c.configurator/trunk/src/z3c/configurator/configurator.py
A z3c.configurator/trunk/src/z3c/configurator/interfaces.py
A z3c.configurator/trunk/src/z3c/configurator/tests.py
-=-
Added: z3c.configurator/trunk/setup.cfg
===================================================================
--- z3c.configurator/trunk/setup.cfg 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/setup.cfg 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = .dev
+tag_svn_revision = 1
Property changes on: z3c.configurator/trunk/setup.cfg
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/setup.py
===================================================================
--- z3c.configurator/trunk/setup.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/setup.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,18 @@
+#!python
+from setuptools import setup, find_packages
+
+setup(name='z3c.configurator',
+ version='0.1',
+ author = "??",
+ author_email = "office at lovelysystems.com",
+ description = "Dynamic configuration",
+ license = "ZPL 2.1",
+ keywords = "zope zope3",
+ url='http://svn.zope.org/z3c.configurator',
+ packages=find_packages('src'),
+ include_package_data=True,
+ package_dir = {'':'src'},
+ namespace_packages=['refline',],
+ install_requires = ['setuptools', ],
+ )
+
Property changes on: z3c.configurator/trunk/setup.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/__init__.py
===================================================================
--- z3c.configurator/trunk/src/z3c/__init__.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/__init__.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,6 @@
+try:
+ # Declare this a namespace package if pkg_resources is available.
+ import pkg_resources
+ pkg_resources.declare_namespace('z3c')
+except ImportError:
+ pass
Property changes on: z3c.configurator/trunk/src/z3c/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/configurator/README.txt
===================================================================
--- z3c.configurator/trunk/src/z3c/configurator/README.txt 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/configurator/README.txt 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,127 @@
+================
+The Configurator
+================
+
+The configurator is designed to extend a component after its
+creation. Traditionally this is done by listening to ``ObjectCreatedEvent``
+events. However, this low-level method does not suffice, since configuration
+often depends on other configuration steps and additional data is often needed
+to complete the configuration. And this is where the configurator comes
+in. It uses a separate plugin mechanism to implement the mentioned high-level
+functionality.
+
+Before we can demonstrate the configuration mechanism, we'll have to create an
+interface and a component on which the configuration can act upon:
+
+ >>> import zope.interface
+
+ >>> class ISomething(zope.interface.Interface):
+ ... """Some interesting interface."""
+
+ >>> class Something(object):
+ ... """Implementation of something."""
+ ... zope.interface.implements(ISomething)
+
+ >>> something = Something()
+
+Now we can have the configuration act on the component:
+
+ >>> from z3c import configurator
+ >>> configurator.configure(something, {})
+
+The second argument is the data dictionary, which can be used to pass in
+additional information that might be needed during the configuration. It is up
+to each plugin to interpret the data.
+
+Of course nothing happens, since no configuration plugins are
+registered. Let's now create a new configuration plugin, which sets a new
+attribute on the component:
+
+ >>> import zope.component
+ >>> from z3c.configurator import interfaces
+
+ >>> class AddFooAttribute(configurator.ConfigurationPluginBase):
+ ... zope.component.adapts(ISomething)
+ ...
+ ... def __call__(self, data):
+ ... setattr(self.context, 'foo', data.get('foo'))
+
+ >>> zope.component.provideAdapter(AddFooAttribute, name='add foo')
+
+If we execute the configuration again, the attribute will be added:
+
+ >>> configurator.configure(something, {'foo': u'my value'})
+ >>> something.foo
+ u'my value'
+
+
+Dependencies
+------------
+
+Now that we have simple configuration plugins, we can also develop plugins
+that depend on another one. Let's create a configuration plugin that adds some
+additional data to the foo attribute. Clearly, the foo attribute has to exist
+before this step can be taken. The ``dependencies`` attribute can be used to
+specify all plugin dependencies by name:
+
+ >>> class ExtendFooAttribute(configurator.ConfigurationPluginBase):
+ ... zope.component.adapts(ISomething)
+ ... dependencies = ('add foo',)
+ ...
+ ... def __call__(self, data):
+ ... self.context.foo = u'Text: ' + self.context.foo
+
+ >>> zope.component.provideAdapter(ExtendFooAttribute, name='extend foo')
+
+If we now execute the configuration again, the extended result should be seen:
+
+ >>> something = Something()
+ >>> configurator.configure(something, {'foo': u'my value'})
+ >>> something.foo
+ u'Text: my value'
+
+
+Data Schemas
+------------
+
+For purely informational purposes, a ``schema`` attribute is used on the
+plugin to describe the fields that the plugin expects from the data
+dictionary. For adding another simple attribute, this could look as follows:
+
+ >>> import zope.schema
+ >>> class IAddBar(zope.interface.Interface):
+ ... bar = zope.schema.Text(title=u'Bar')
+
+ >>> class AddBarAttribute(configurator.SchemaConfigurationPluginBase):
+ ... zope.component.adapts(ISomething)
+ ... schema = IAddBar
+ ...
+ ... def __call__(self, data):
+ ... self.verify(data)
+ ... setattr(self.context, 'bar', data.get('bar'))
+
+ >>> zope.component.provideAdapter(AddBarAttribute, name='add bar')
+
+The advantage of using the base class for this case is that it provides a
+``verify()`` method that allows you to verify the data against the shema. We
+can now run the configuration again:
+
+ >>> something = Something()
+ >>> configurator.configure(something, {'foo': u'my value', 'bar': u'value'})
+ >>> something.bar
+ u'value'
+
+The value must exist and be valid:
+
+ >>> something = Something()
+ >>> configurator.configure(something, {'foo': u'my value'})
+ Traceback (most recent call last):
+ ...
+ KeyError: 'bar'
+
+ >>> something = Something()
+ >>> configurator.configure(something, {'foo': u'my value', 'bar': 1})
+ Traceback (most recent call last):
+ ...
+ WrongType: (1, <type 'unicode'>)
+
Property changes on: z3c.configurator/trunk/src/z3c/configurator/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/configurator/__init__.py
===================================================================
--- z3c.configurator/trunk/src/z3c/configurator/__init__.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/configurator/__init__.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,5 @@
+# Make a package
+
+from z3c.configurator.configurator import configure
+from z3c.configurator.configurator import ConfigurationPluginBase
+from z3c.configurator.configurator import SchemaConfigurationPluginBase
Property changes on: z3c.configurator/trunk/src/z3c/configurator/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/configurator/configurator.py
===================================================================
--- z3c.configurator/trunk/src/z3c/configurator/configurator.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/configurator/configurator.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,86 @@
+##############################################################################
+#
+# Copyright (c) 2005 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.
+#
+##############################################################################
+"""Configurator Implementation
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import sys
+import zope.component
+import zope.interface
+import zope.schema
+
+from z3c.configurator import interfaces
+
+# Stati values
+NEW = 1
+OPEN = 2
+CLOSED = 3
+
+def configure(component, data):
+
+ plugins = dict(zope.component.getAdapters(
+ (component,), interfaces.IConfigurationPlugin))
+
+ # status is a dict plugin names as keys and stati as values.
+ status = dict([(name, NEW) for name in plugins])
+
+ def visit(name):
+ """The recursive part of the topological sort
+
+ Raises a CyclicDependencyError if cyclic depencencies are found.
+ """
+ if status[name] == NEW:
+ status[name] = OPEN
+ plugin = plugins[name]
+ for dep in getattr(plugin, 'dependencies', ()):
+ visit(dep)
+ plugin(data)
+ status[name] = CLOSED
+
+ elif status[name] == CLOSED:
+ return
+
+ # Stumbling over an OPEN node means there is a cyclic dependency
+ elif status[name] == OPEN:
+ raise interfaces.CyclicDependencyError(
+ "cyclic dependency at '%s'" % name)
+
+
+ for name in plugins:
+ visit(name)
+
+
+class ConfigurationPluginBase(object):
+ zope.interface.implements(interfaces.IConfigurationPlugin)
+
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, data):
+ raise NotImplemented
+
+class SchemaConfigurationPluginBase(object):
+ zope.interface.implements(interfaces.IConfigurationPlugin)
+ schema = zope.interface.Interface
+
+ def __init__(self, context):
+ self.context = context
+
+ def verify(self, data):
+ for name, field in zope.schema.getFields(self.schema).items():
+ field.validate(data[name])
+
+ def __call__(self, data):
+ raise NotImplemented
Property changes on: z3c.configurator/trunk/src/z3c/configurator/configurator.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/configurator/interfaces.py
===================================================================
--- z3c.configurator/trunk/src/z3c/configurator/interfaces.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/configurator/interfaces.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,53 @@
+##############################################################################
+#
+# Copyright (c) 2005 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.
+#
+##############################################################################
+"""Configurator Interfaces
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.interface
+import zope.schema
+
+
+class CyclicDependencyError(ValueError):
+ """Cyclic dependency of configuration plugins"""
+
+
+class DataMissingError(ValueError):
+ """Error raised when required data is missing during configuration
+ execution."""
+
+
+class IConfigurationPlugin(zope.interface.Interface):
+ """An object executing one configuration step."""
+
+ dependencies = zope.interface.Attribute(
+ """A sequence of dependencies to other configuration plugins.""")
+
+ def __call__(self, data):
+ """Execute the configuration.
+
+ The data is a dictionary containing values that might be of interest
+ to the configuration plugin. When some required data field is missing,
+ then raise a ``DataMissingError`` error.
+ """
+
+
+class ISchemaConfigurationPlugin(IConfigurationPlugin):
+ """A configuration plugin that provides a data schema."""
+
+ schema = zope.schema.Object(
+ title=u"Configuration Schema",
+ description=u"The schema describing the data fields needed.",
+ schema=zope.interface.interfaces.IInterface)
Property changes on: z3c.configurator/trunk/src/z3c/configurator/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: z3c.configurator/trunk/src/z3c/configurator/tests.py
===================================================================
--- z3c.configurator/trunk/src/z3c/configurator/tests.py 2006-08-16 06:18:13 UTC (rev 69556)
+++ z3c.configurator/trunk/src/z3c/configurator/tests.py 2006-08-16 06:51:09 UTC (rev 69557)
@@ -0,0 +1,42 @@
+##############################################################################
+#
+# Copyright (c) 2005 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.
+#
+##############################################################################
+"""Configurator Test Setup
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+__docformat__ = 'restructuredtext'
+
+import unittest
+from zope.testing import doctest
+from zope.testing.doctestunit import DocFileSuite
+from zope.app.testing import setup
+
+def setUp(test):
+ setup.placelessSetUp()
+
+def tearDown(test):
+ setup.placelessTearDown()
+
+
+def test_suite():
+ return unittest.TestSuite((
+ DocFileSuite('README.txt',
+ setUp=setUp, tearDown=tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+ ),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Property changes on: z3c.configurator/trunk/src/z3c/configurator/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Checkins
mailing list