[Checkins] SVN: z3c.discriminator/trunk/ Generalized discriminator
machinery to all adapters (see docs/HISTORY.txt). Bumped
version to 0.2.
Malthe Borch
mborch at gmail.com
Mon Nov 26 11:53:18 EST 2007
Log message for revision 81988:
Generalized discriminator machinery to all adapters (see docs/HISTORY.txt). Bumped version to 0.2.
Changed:
A z3c.discriminator/trunk/docs/
A z3c.discriminator/trunk/docs/HISTORY.txt
U z3c.discriminator/trunk/setup.py
U z3c.discriminator/trunk/z3c/discriminator/README.txt
U z3c.discriminator/trunk/z3c/discriminator/__init__.py
A z3c.discriminator/trunk/z3c/discriminator/discriminator.py
D z3c.discriminator/trunk/z3c/discriminator/meta.zcml
A z3c.discriminator/trunk/z3c/discriminator/patches.py
U z3c.discriminator/trunk/z3c/discriminator/tests.py
D z3c.discriminator/trunk/z3c/discriminator/zcml.py
-=-
Added: z3c.discriminator/trunk/docs/HISTORY.txt
===================================================================
--- z3c.discriminator/trunk/docs/HISTORY.txt (rev 0)
+++ z3c.discriminator/trunk/docs/HISTORY.txt 2007-11-26 16:53:17 UTC (rev 81988)
@@ -0,0 +1,23 @@
+Changelog
+---------
+
+Version 0.2 - November 26, 2007
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- Discriminator machinery is now introduced globally by patching the global
+ adapter registry and the GlobalObject configuration field.
+
+ The ``discriminator`` method now returns an interface that is in all
+ aspects equal to the discriminated interface except it's marked as a
+ discriminator.
+
+ Test suite have been expanded by including the entire test suite from
+ ``zope.component``.
+ [malthe]
+
+
+Version 0.1 - November 23, 2007
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- First public release
+ [malthe]
Modified: z3c.discriminator/trunk/setup.py
===================================================================
--- z3c.discriminator/trunk/setup.py 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/setup.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -1,16 +1,12 @@
from setuptools import setup, find_packages
import sys, os
-version = '0.1'
+version = '0.2'
setup(name='z3c.discriminator',
version=version,
- description="Provides a formalism for using adapters with discriminators.",
- long_description="""\
-This package provides a formalism for designating adapter arguments as
-discriminators in the sense that they will be used only for adapter lookup,
-not instantiation.""",
- # Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers
+ description="Provides a formalism for marking adapter specifications as discriminators.",
+ long_description=open("README.txt").read() + open("docs/HISTORY.txt").read(),
classifiers=[
"Framework :: Zope2",
"Framework :: Zope3",
Modified: z3c.discriminator/trunk/z3c/discriminator/README.txt
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/README.txt 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/z3c/discriminator/README.txt 2007-11-26 16:53:17 UTC (rev 81988)
@@ -1,14 +1,14 @@
z3c.discriminator
=================
-
-This package provides a formalism for designating adapter arguments as
+
+This package provides a formalism for marking adapter specifications as
discriminators in the sense that they will be used only for adapter lookup,
not instantiation.
- >>> from zope import interface
-
First a set of interfaces and their implementations.
+ >>> from zope import interface
+
>>> class IFoo(interface.Interface):
... pass
@@ -20,70 +20,68 @@
>>> class Bar(object):
... interface.implements(IBar)
-
+
>>> foo = Foo()
>>> bar = Bar()
Let's say we want to register an adapter for IFoo that also discriminates
-on IBar.
+on IBar. That is, the adapter itself takes only one argument (providing IFoo).
>>> def give_me_foo(foo):
... return foo
-We can use the ``discriminator`` method the decorate the interface as a
-discriminator. To register the adapter we use a custom ``provideAdapter``
-method that is basically a wrapper around the actual implementation from
-``zope.component``.
+We can use the ``discriminator`` method the mark the interface as a
+discriminator. Let's look at its properties:
>>> from z3c.discriminator import discriminator
- >>> from z3c.discriminator import provideAdapter
-
-Let's look at the properties of a discriminator.
-
>>> discriminator(IFoo).providedBy(foo)
True
-We designate that IBar is a discriminator by wrapping it using the
-``discriminator`` method:
-
- >>> provideAdapter(give_me_foo, (IFoo, discriminator(IBar)), IFoo)
+To register the adapter we use the standard ``provideAdapter`` method.
-Let's look up the adapter with the proper arguments.
+ >>> from zope import component
+ >>> component.provideAdapter(give_me_foo, (IFoo, discriminator(IBar)), IFoo)
+Let's look up the adapter providing both ``foo`` and ``bar``:
+
>>> from zope import component
>>> component.getMultiAdapter((foo, bar), IFoo)
<Foo object at ...>
-Extended adapter directive
---------------------------
+Adapter registration using ZCML
+-------------------------------
-The discriminator extension is also available from ZCML. The convention
-is that if a dotted interface specification is prefaced by a minus
-sign, it's interpreted as a discriminator, e.g.
+Directives that use ``zope.configuration.fields.GlobalObject`` as the value
+type for the global object parameters are automatically equipped to use
+discriminators.
+The convention is that if a dotted interface specification is prefaced by a dash,
+it's interpreted as a discriminator, e.g.
+
for="-some.package.ISomeInterface"
-The ``clearZCML`` method sets up the extended adapter directive.
+Let's try with the ``adapter`` directive. We'll register an adapter for IBar that
+also discriminates on IFoo.
- >>> from z3c.discriminator.tests import clearZCML
- >>> clearZCML()
-
-Let's register an adapter for IBar that also discriminates on IFoo.
-
>>> def give_me_bar(bar):
... return bar
-We need to patch our definitions onto the tests module to target
-them from the configuration string.
-
+To make our symbols available from the configuration machine we patch it onto
+the tests module.
+
>>> import z3c.discriminator.tests
>>> z3c.discriminator.tests.IBar = IBar
>>> z3c.discriminator.tests.IFoo = IFoo
>>> z3c.discriminator.tests.give_me_bar = give_me_bar
+We must first load the meta directives from ``zope.component``.
+
>>> from cStringIO import StringIO
>>> from zope.configuration import xmlconfig
+ >>> xmlconfig.XMLConfig('meta.zcml', component)()
+Now we can Register the adapter.
+
>>> xmlconfig.xmlconfig(StringIO("""
... <configure xmlns="http://namespaces.zope.org/zope">
... <adapter for="-z3c.discriminator.tests.IFoo
@@ -92,6 +90,8 @@
... factory="z3c.discriminator.tests.give_me_bar" />
... </configure>
... """))
+
+Let's verify the adapter lookup:
>>> component.getMultiAdapter((foo, bar), IBar)
<Bar object at ...>
Modified: z3c.discriminator/trunk/z3c/discriminator/__init__.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/__init__.py 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/z3c/discriminator/__init__.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -1,22 +1,2 @@
-from zope import interface
-from zope import component
-
-def discriminator(iface):
- class _(iface):
- pass
-
- _.__discriminated__ = iface
- _.providedBy = iface.providedBy
-
- return _
-
-def provideAdapter(factory, adapts=None, provides=None, name=''):
- def _factory(*args):
- _ = [provided for (provided, implemented) in zip(args, adapts)
- if not hasattr(implemented, '__discriminated__')]
- return factory(*_)
-
- # unwrap discriminators
- _adapts = [getattr(a, '__discriminated__', a) for a in adapts]
-
- component.provideAdapter(_factory, _adapts, provides, name)
+from discriminator import discriminator
+import patches
Added: z3c.discriminator/trunk/z3c/discriminator/discriminator.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/discriminator.py (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/discriminator.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -0,0 +1,23 @@
+def discriminator(iface):
+ """This method creates an interface class derived from ``iface`` that behaves
+ and identifies exactly like ``iface`` except it is marked as a discriminator
+ by providing ``__discriminated__``."""
+
+ class meta(type(iface)):
+ def __init__(self, name, bases=(), attrs=None, **kwargs):
+ del attrs['__metaclass__']
+ super(meta, self).__init__(name, bases=bases, attrs=attrs, **kwargs)
+
+ def __eq__(self, other):
+ if other is iface or other is self:
+ return True
+
+ def __hash__(self):
+ return hash(iface)
+
+ class _(iface):
+ __metaclass__ = meta
+
+ _.__discriminated__ = iface
+
+ return _
Deleted: z3c.discriminator/trunk/z3c/discriminator/meta.zcml
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/meta.zcml 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/z3c/discriminator/meta.zcml 2007-11-26 16:53:17 UTC (rev 81988)
@@ -1,15 +0,0 @@
-<configure
- xmlns="http://namespaces.zope.org/zope"
- xmlns:meta="http://namespaces.zope.org/meta">
-
- <meta:directives namespace="http://namespaces.zope.org/zope">
-
- <meta:directive
- name="adapter"
- schema="zope.component.zcml.IAdapterDirective"
- handler=".zcml.adapter"
- />
-
- </meta:directives>
-
-</configure>
Added: z3c.discriminator/trunk/z3c/discriminator/patches.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/patches.py (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/patches.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -0,0 +1,40 @@
+import zope.interface.adapter
+import zope.configuration.fields
+
+from z3c.discriminator import discriminator
+
+_register = zope.interface.adapter.BaseAdapterRegistry.register
+def register(self, required, provided, name, factory):
+ """This method wraps ``factory`` so it's discriminator-aware
+ if one or more ``required`` interfaces are designated as
+ discriminators."""
+
+ drequired = [hasattr(r, '__discriminated__') for r in required]
+
+ if factory is None or len(drequired) == 0:
+ return _register(self, required, provided, name, factory)
+
+ def _factory(*args):
+ _ = [provided for (provided, implemented) in
+ zip(args, tuple(required) + (None,) * (len(args) - len(required))) \
+ if not hasattr(implemented, '__discriminated__')]
+
+ return factory(*_)
+
+ _register(self, required, provided, name, _factory)
+
+# monkey-patch ``register`` method on zope.interface.adapter.BaseAdapterRegistry
+zope.interface.adapter.BaseAdapterRegistry.register = register
+
+_fromUnicode = zope.configuration.fields.GlobalObject.fromUnicode
+def fromUnicode(self, u):
+ """This method wraps ``fromUnicode`` so strings that begin with a
+ dash are wrapped as a discriminator."""
+
+ if u.startswith('-'):
+ return discriminator(self.fromUnicode(u[1:]))
+
+ return _fromUnicode(self, u)
+
+# monkey-patch ``fromUnicode`` on zope.configuration.fields.GlobalObject.fromUnicode
+zope.configuration.fields.GlobalObject.fromUnicode = fromUnicode
Modified: z3c.discriminator/trunk/z3c/discriminator/tests.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/tests.py 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/z3c/discriminator/tests.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -5,52 +5,22 @@
doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE)
-import zope.component
import zope.component.testing
import zope.component.tests
-from zope.configuration import xmlconfig
-
-import z3c.discriminator
-
-"""
-Note:
-
-To make sure the new adapter directive is correctly implemented,
-we run the corresponding test suite from zope.component against
-our implementation.
-"""
-
-def clearZCML(test=None):
- zope.component.testing.tearDown()
- zope.component.testing.setUp()
-
- xmlconfig.XMLConfig('meta.zcml', zope.component)()
- xmlconfig.XMLConfig('meta.zcml', z3c.discriminator)()
-
-clearZCML_save = zope.component.tests.clearZCML
-
-def setUp(test):
- zope.component.testing.setUp()
- zope.component.tests.clearZCML = clearZCML
-
-def tearDown(test):
- zope.component.testing.tearDown()
- zope.component.tests.clearZCML = clearZCML_save
-
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('README.txt',
optionflags=OPTIONFLAGS,
setUp=zope.component.testing.setUp,
tearDown=zope.component.testing.tearDown,
- package="z3c.discriminator"),
- doctest.DocFileSuite('zcml.txt',
- optionflags=OPTIONFLAGS,
- setUp=setUp,
- tearDown=tearDown,
- package="zope.component"),
- ))
+ package="z3c.discriminator"),) +
+ # run test suite from zope.component to make sure
+ # our patches are correct
+
+ tuple(suite for suite in zope.component.tests.test_suite()),
+ )
+
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
Deleted: z3c.discriminator/trunk/z3c/discriminator/zcml.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/zcml.py 2007-11-25 22:23:21 UTC (rev 81987)
+++ z3c.discriminator/trunk/z3c/discriminator/zcml.py 2007-11-26 16:53:17 UTC (rev 81988)
@@ -1,42 +0,0 @@
-import zope.interface
-import zope.component.zcml
-import zope.configuration.fields
-
-from z3c.discriminator import discriminator
-
-class DiscriminatorAwareGlobalObject(zope.configuration.fields.GlobalObject):
- def fromUnicode(self, u):
- if u.startswith('-'):
- return discriminator(self.fromUnicode(u[1:]))
-
- return super(DiscriminatorAwareGlobalObject, self).fromUnicode(u)
-
-# monkey-patch value type on for_-handler
-zope.component.zcml.IAdapterDirective['for_'].value_type = \
- DiscriminatorAwareGlobalObject(missing_value=object())
-
-def adapter(_context, factory, provides=None, for_=None, **kwargs):
- if len(factory) != 1:
- return zope.component.zcml.adapter(_context, factory, provides, for_, **kwargs)
-
- factory = factory[0]
-
- if for_ is None:
- for_ = zope.component.adaptedBy(factory)
-
- if for_ is None:
- raise TypeError("No for attribute was provided and can't "
- "determine what the factory adapts.")
-
- for_ = tuple(for_)
-
- @zope.interface.implementer(zope.interface.implementedBy(factory))
- def _factory(*args):
- _ = [provided for (provided, implemented) in zip(args, for_)
- if not hasattr(implemented, '__discriminated__')]
- return factory(*_)
-
- # unwrap discriminators
- adapts = [getattr(a, '__discriminated__', a) for a in for_]
-
- zope.component.zcml.adapter(_context, [_factory], provides=provides, for_=adapts, **kwargs)
More information about the Checkins
mailing list