[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