[Checkins] SVN: z3c.discriminator/ Initial import.
Malthe Borch
mborch at gmail.com
Sat Nov 24 17:46:56 EST 2007
Log message for revision 81979:
Initial import.
Changed:
A z3c.discriminator/
A z3c.discriminator/branches/
A z3c.discriminator/tags/
A z3c.discriminator/trunk/
A z3c.discriminator/trunk/setup.cfg
A z3c.discriminator/trunk/setup.py
A z3c.discriminator/trunk/z3c/
A z3c.discriminator/trunk/z3c/__init__.py
A z3c.discriminator/trunk/z3c/discriminator/
A z3c.discriminator/trunk/z3c/discriminator/README.txt
A z3c.discriminator/trunk/z3c/discriminator/__init__.py
A z3c.discriminator/trunk/z3c/discriminator/meta.zcml
A z3c.discriminator/trunk/z3c/discriminator/tests.py
A z3c.discriminator/trunk/z3c/discriminator/zcml.py
-=-
Added: z3c.discriminator/trunk/setup.cfg
===================================================================
--- z3c.discriminator/trunk/setup.cfg (rev 0)
+++ z3c.discriminator/trunk/setup.cfg 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,3 @@
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
Added: z3c.discriminator/trunk/setup.py
===================================================================
--- z3c.discriminator/trunk/setup.py (rev 0)
+++ z3c.discriminator/trunk/setup.py 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,36 @@
+from setuptools import setup, find_packages
+import sys, os
+
+version = '0.1'
+
+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
+ classifiers=[
+ "Framework :: Zope2",
+ "Framework :: Zope3",
+ "Programming Language :: Python",
+ "Topic :: Software Development :: Libraries :: Python Modules",
+ ],
+ keywords='zope adapter discriminator',
+ author='Malthe Borch',
+ author_email='mborch at gmail.com',
+ url='',
+ license='ZPL',
+ packages=find_packages(exclude=['ez_setup']),
+ namespace_packages=['z3c'],
+ include_package_data=True,
+ zip_safe=False,
+ install_requires=[
+ 'setuptools',
+ # -*- Extra requirements: -*-
+ ],
+ entry_points="""
+ # -*- Entry points: -*-
+ """,
+ )
Added: z3c.discriminator/trunk/z3c/__init__.py
===================================================================
--- z3c.discriminator/trunk/z3c/__init__.py (rev 0)
+++ z3c.discriminator/trunk/z3c/__init__.py 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,6 @@
+# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
+try:
+ __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
Added: z3c.discriminator/trunk/z3c/discriminator/README.txt
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/README.txt (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/README.txt 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,89 @@
+z3c.discriminator
+=================
+
+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.
+
+ >>> from zope import interface
+
+First a set of interfaces and their implementations.
+
+ >>> class IFoo(interface.Interface):
+ ... pass
+
+ >>> class IBar(interface.Interface):
+ ... pass
+
+ >>> class Foo:
+ ... interface.implements(IFoo)
+
+ >>> class Bar:
+ ... interface.implements(IBar)
+
+Let's say we want to register an adapter for IFoo that also discriminates
+on IBar.
+
+ >>> 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``.
+
+ >>> from z3c.discriminator import discriminator
+ >>> from z3c.discriminator import provideAdapter
+
+ >>> provideAdapter(give_me_foo, (IFoo, discriminator(IBar)), IFoo)
+
+Let's look up the adapter with the proper arguments.
+
+ >>> foo = Foo()
+ >>> bar = Bar()
+
+ >>> from zope import component
+ >>> component.getMultiAdapter((foo, bar), IFoo)
+ <__builtin__.Foo instance at ...>
+
+Extended adapter directive
+--------------------------
+
+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.
+
+ for="-some.package.ISomeInterface"
+
+The ``clearZCML`` method sets up the extended adapter directive.
+
+ >>> 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.
+
+ >>> import z3c.discriminator.tests
+ >>> z3c.discriminator.tests.IBar = IBar
+ >>> z3c.discriminator.tests.IFoo = IFoo
+ >>> z3c.discriminator.tests.give_me_bar = give_me_bar
+
+ >>> from cStringIO import StringIO
+ >>> from zope.configuration import xmlconfig
+
+ >>> xmlconfig.xmlconfig(StringIO("""
+ ... <configure xmlns="http://namespaces.zope.org/zope">
+ ... <adapter for="-z3c.discriminator.tests.IFoo
+ ... z3c.discriminator.tests.IBar"
+ ... provides="z3c.discriminator.tests.IBar"
+ ... factory="z3c.discriminator.tests.give_me_bar" />
+ ... </configure>
+ ... """))
+
+ >>> component.getMultiAdapter((foo, bar), IBar)
+ <__builtin__.Bar instance at ...>
Added: z3c.discriminator/trunk/z3c/discriminator/__init__.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/__init__.py (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/__init__.py 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,22 @@
+from zope import interface
+from zope import component
+
+class discriminator(object):
+ interface.implements(interface.interfaces.ISpecification,
+ interface.interfaces.IInterface)
+
+ def __init__(self, iface):
+ self.iface = iface
+ self.__name__ = iface.__name__
+ interface.alsoProvides(self, iface)
+
+def provideAdapter(factory, adapts=None, provides=None, name=''):
+ def _factory(*args):
+ _ = [provided for (provided, implemented) in zip(args, adapts)
+ if not isinstance(implemented, discriminator)]
+ return factory(*_)
+
+ # unwrap discriminators
+ _adapts = [isinstance(a, discriminator) and a.iface or a for a in adapts]
+
+ component.provideAdapter(_factory, _adapts, provides, name)
Added: z3c.discriminator/trunk/z3c/discriminator/meta.zcml
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/meta.zcml (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/meta.zcml 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,15 @@
+<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/tests.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/tests.py (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/tests.py 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,55 @@
+from zope.testing import doctest
+import unittest
+
+OPTIONFLAGS = (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"),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: z3c.discriminator/trunk/z3c/discriminator/zcml.py
===================================================================
--- z3c.discriminator/trunk/z3c/discriminator/zcml.py (rev 0)
+++ z3c.discriminator/trunk/z3c/discriminator/zcml.py 2007-11-24 22:46:56 UTC (rev 81979)
@@ -0,0 +1,43 @@
+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)
+
+class IAdapterDirective(zope.component.zcml.IAdapterDirective):
+ pass
+
+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 isinstance(implemented, discriminator)]
+ return factory(*_)
+
+ # unwrap discriminators
+ adapts = [isinstance(a, discriminator) and a.iface or a for a in for_]
+
+ zope.component.zcml.adapter(_context, [_factory], provides=provides, for_=adapts, **kwargs)
More information about the Checkins
mailing list