summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-12-19 21:14:30 +0000
committerChris McDonough <chrism@agendaless.com>2009-12-19 21:14:30 +0000
commit251ce7d166fa901b33f20cf46315ec464e3eac64 (patch)
tree2cd31c1de76f3a915dfb702cc8c18edff27e60b1 /repoze
parent12daf9e069b66aef5715a14641fc269367c091dd (diff)
downloadpyramid-251ce7d166fa901b33f20cf46315ec464e3eac64.tar.gz
pyramid-251ce7d166fa901b33f20cf46315ec464e3eac64.tar.bz2
pyramid-251ce7d166fa901b33f20cf46315ec464e3eac64.zip
- Add two new APIs to the ``repoze.bfg.configuration.Configurator``
class: ``add_adapter`` and ``add_utility``. These, respectively, perform the same functions as the ``registerAdapter`` and ``registerUtility`` functions of a ZCA registry. They were added to allow for a more consistent testing API for applications that make use of the ZCA directly. - Cause the ``adapter``, ``utility``, and ``subscriber`` ZCML directives to use a ``Configurator`` instance and associated configurator APIs rather than a ZCA registry directly.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/configuration.py50
-rw-r--r--repoze/bfg/tests/test_configuration.py40
-rw-r--r--repoze/bfg/tests/test_zcml.py80
-rw-r--r--repoze/bfg/zcml.py230
4 files changed, 226 insertions, 174 deletions
diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py
index 0ee08868d..7b204fec3 100644
--- a/repoze/bfg/configuration.py
+++ b/repoze/bfg/configuration.py
@@ -10,6 +10,7 @@ from zope.configuration import xmlconfig
from zope.interface import Interface
from zope.interface import implementedBy
+from zope.interface import providedBy
from zope.interface.interfaces import IInterface
from zope.interface import implements
@@ -291,7 +292,7 @@ class Configurator(object):
"""
return self.manager.pop()
- def add_subscriber(self, subscriber, iface=None):
+ def add_subscriber(self, subscriber, iface=None, info=u''):
"""Add an event :term:`subscriber` for the event stream
implied by the supplied ``iface`` interface. The
``subscriber`` argument represents a callable object; it will
@@ -305,9 +306,54 @@ class Configurator(object):
iface = (Interface,)
if not isinstance(iface, (tuple, list)):
iface = (iface,)
- self.registry.registerHandler(subscriber, iface)
+ self.registry.registerHandler(subscriber, iface, info=info)
return subscriber
+ def add_subscription_adapter(self, factory, required=None, provided=None,
+ info=u''):
+ """Add a Zope Component Architecture subscription adapter.
+ What is a subscription adapter, you ask? I have no idea
+ either. This is currently only here to support the
+ ``subscriber`` ZCML directive. This is not a published API
+ until I figure out why I would need a subscription adapter."""
+ self.registry.registerSubscriptionAdapter(factory, required=required,
+ provided=provided, info=info)
+
+ def add_adapter(self, factory, required=None, provided=None, name='',
+ info=u''):
+ """Add a :term:`Zope Component Architecture` adapter. Use of
+ this method is the equivalent of using an ``adapter``
+ :term:`ZCML declaration` or the ``registerAdapter`` method of
+ a ZCA registry.
+
+ .. note:: This method is not useful unless you use :term:`Zope
+ Component Architecture` APIs in your :mod:`repoze.bfg`
+ application directly.
+ """
+ self.registry.registerAdapter(factory, required=required,
+ provided=provided, name=name, info=info)
+
+ def add_utility(self, component=None, provided=None, name=u'', info=u'',
+ factory=None):
+ """Add a :term:`Zope Component Architecture` utility. Use of
+ this method is the equivalent of using a ``utility``
+ :term:`ZCML declaration` or the ``registerUtility`` method of
+ a ZCA registry.
+
+ .. note:: This method is not useful unless you use :term:`Zope
+ Component Architecture` APIs in your :mod:`repoze.bfg`
+ application directly.
+ """
+ if factory:
+ kw = dict(factory=factory)
+ else:
+ # older component registries don't accept factory as a kwarg,
+ # so if we don't need it, we don't pass it
+ kw = {}
+ self.registry.registerUtility(
+ component=component, provided=provided, name=name, info=info,
+ **kw)
+
def make_wsgi_app(self):
""" Returns a :mod:`repoze.bfg` WSGI application representing
the current configuration state and sends a
diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py
index 7d714f42a..520f9a5bc 100644
--- a/repoze/bfg/tests/test_configuration.py
+++ b/repoze/bfg/tests/test_configuration.py
@@ -1813,6 +1813,37 @@ class ConfiguratorTests(unittest.TestCase):
result = render_view_to_response(ctx, req, 'pod_notinit')
self.assertEqual(result, None)
+ def test_add_subscription_adapter(self):
+ config = self._makeOne()
+ def factory(abc): pass
+ config.add_subscription_adapter(factory, (IDummy,), IDummy,
+ info='info')
+ adapters = config.registry.registeredSubscriptionAdapters()
+ self.assertEqual(list(adapters)[0].factory, factory)
+
+ def test_add_adapter(self):
+ config = self._makeOne()
+ def factory(abc): return 'OK'
+ config.add_adapter(factory, (IDummy,), IDummy, name='foo',
+ info='info')
+ result = config.registry.adapters.lookup((IDummy,), IDummy, name='foo')
+ self.assertEqual(result(None), 'OK')
+
+ def test_add_utility_no_factory(self):
+ config = self._makeOne()
+ def component(): pass
+ config.add_utility(component, IDummy, name='foo', info='info')
+ result = config.registry.queryUtility(IDummy, name='foo')
+ self.assertEqual(result, component)
+
+ def test_add_utility_with_factory(self):
+ config = self._makeOne()
+ def factory(): return 'OK'
+ config.add_utility(None, IDummy, name='foo', info='info',
+ factory=factory)
+ result = config.registry.queryUtility(IDummy, name='foo')
+ self.assertEqual(result, 'OK')
+
class Test__map_view(unittest.TestCase):
def setUp(self):
from repoze.bfg.registry import Registry
@@ -2812,3 +2843,12 @@ class DummyThreadLocalManager(object):
self.pushed = d
def pop(self):
self.popped = True
+
+class IFactory(Interface):
+ pass
+
+class DummyFactory(object):
+ implements(IFactory)
+ def __call__(self):
+ """ """
+
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index cbbbe664c..59254846f 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -724,7 +724,7 @@ class TestAdapterDirective(unittest.TestCase):
provides=None, for_=None)
def test_for_is_None_adaptedBy_set(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
factory = DummyFactory()
factory.__component_adapts__ = (IDummy,)
@@ -733,11 +733,10 @@ class TestAdapterDirective(unittest.TestCase):
regadapt = context.actions[0]
self.assertEqual(regadapt['discriminator'],
('adapter', (IDummy,), IFactory, ''))
- self.assertEqual(regadapt['callable'],
- handler)
+ self.assertEqual(regadapt['callable'].im_func,
+ Configurator.add_adapter.im_func)
self.assertEqual(regadapt['args'],
- ('registerAdapter', factory, (IDummy,), IFactory,
- '', None))
+ (factory, (IDummy,), IFactory, '', None))
def test_provides_missing(self):
context = DummyContext()
@@ -746,17 +745,16 @@ class TestAdapterDirective(unittest.TestCase):
provides=None, for_=(IDummy,))
def test_provides_obtained_via_implementedBy(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
self._callFUT(context, [DummyFactory], for_=(IDummy,))
regadapt = context.actions[0]
self.assertEqual(regadapt['discriminator'],
('adapter', (IDummy,), IFactory, ''))
- self.assertEqual(regadapt['callable'],
- handler)
+ self.assertEqual(regadapt['callable'].im_func,
+ Configurator.add_adapter.im_func)
self.assertEqual(regadapt['args'],
- ('registerAdapter', DummyFactory, (IDummy,), IFactory,
- '', None))
+ (DummyFactory, (IDummy,), IFactory, '', None))
def test_multiple_factories_multiple_for(self):
context = DummyContext()
@@ -774,7 +772,7 @@ class TestAdapterDirective(unittest.TestCase):
for_=(IDummy, IDummy))
def test_rolled_up_factories(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
factory = DummyFactory()
self._callFUT(context,
@@ -784,10 +782,9 @@ class TestAdapterDirective(unittest.TestCase):
regadapt = context.actions[0]
self.assertEqual(regadapt['discriminator'],
('adapter', (IDummy,), IFactory, ''))
- self.assertEqual(regadapt['callable'],
- handler)
- self.assertEqual(len(regadapt['args']), 6)
-
+ self.assertEqual(regadapt['callable'].im_func,
+ Configurator.add_adapter.im_func)
+ self.assertEqual(regadapt['args'][0].__module__, 'repoze.bfg.zcml')
class TestSubscriberDirective(unittest.TestCase):
def setUp(self):
@@ -833,7 +830,7 @@ class TestSubscriberDirective(unittest.TestCase):
factory=factory, handler=None, provides=IFactory)
def test_register_with_factory(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
factory = DummyFactory()
self._callFUT(context, for_=(IDummy,),
@@ -841,13 +838,13 @@ class TestSubscriberDirective(unittest.TestCase):
self.assertEqual(len(context.actions), 1)
subadapt = context.actions[0]
self.assertEqual(subadapt['discriminator'], None)
- self.assertEqual(subadapt['callable'], handler)
+ self.assertEqual(subadapt['callable'].im_func,
+ Configurator.add_subscription_adapter.im_func)
self.assertEqual(subadapt['args'],
- ('registerSubscriptionAdapter', factory,
- (IDummy,), IFactory, u'', None) )
+ (factory, (IDummy,), IFactory, None) )
def test_register_with_handler(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
factory = DummyFactory()
self._callFUT(context, for_=(IDummy,),
@@ -855,10 +852,9 @@ class TestSubscriberDirective(unittest.TestCase):
self.assertEqual(len(context.actions), 1)
subadapt = context.actions[0]
self.assertEqual(subadapt['discriminator'], None)
- self.assertEqual(subadapt['callable'], handler)
- self.assertEqual(subadapt['args'],
- ('registerHandler', factory,
- (IDummy,), u'', None) )
+ self.assertEqual(subadapt['callable'].im_func,
+ Configurator.add_subscriber.im_func)
+ self.assertEqual(subadapt['args'], (factory, (IDummy,), None) )
class TestUtilityDirective(unittest.TestCase):
def setUp(self):
@@ -881,30 +877,29 @@ class TestUtilityDirective(unittest.TestCase):
self.assertRaises(TypeError, self._callFUT, context, provides=None)
def test_provides_from_factory_implements(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
self._callFUT(context, factory=DummyFactory)
self.assertEqual(len(context.actions), 1)
utility = context.actions[0]
self.assertEqual(utility['discriminator'], ('utility', IFactory, ''))
- self.assertEqual(utility['callable'], handler)
+ self.assertEqual(utility['callable'].im_func,
+ Configurator.add_utility.im_func)
self.assertEqual(utility['args'],
- ('registerUtility', None, IFactory, ''))
- self.assertEqual(utility['kw'],
- {'factory': DummyFactory})
+ (None, IFactory, '', None, DummyFactory))
def test_provides_from_component_provides(self):
- from repoze.bfg.zcml import handler
+ from repoze.bfg.configuration import Configurator
context = DummyContext()
component = DummyFactory()
self._callFUT(context, component=component)
self.assertEqual(len(context.actions), 1)
utility = context.actions[0]
self.assertEqual(utility['discriminator'], ('utility', IFactory, ''))
- self.assertEqual(utility['callable'], handler)
+ self.assertEqual(utility['callable'].im_func,
+ Configurator.add_utility.im_func)
self.assertEqual(utility['args'],
- ('registerUtility', component, IFactory, ''))
- self.assertEqual(utility['kw'], {})
+ (component, IFactory, '', None, None))
class TestLoadZCML(unittest.TestCase):
def setUp(self):
@@ -918,25 +913,6 @@ class TestLoadZCML(unittest.TestCase):
import repoze.bfg.includes
xmlconfig.file('configure.zcml', package=repoze.bfg.includes)
-class TestHandler(unittest.TestCase):
- def setUp(self):
- testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def _callFUT(self, methodName, *arg, **kw):
- from repoze.bfg.zcml import handler
- return handler(methodName, *arg, **kw)
-
- def test_it(self):
- def foo():
- """ """
- from zope.interface import Interface
- class IWhatever(Interface):
- pass
- self._callFUT('registerUtility', foo, IWhatever)
-
class TestRolledUpFactory(unittest.TestCase):
def _callFUT(self, *factories):
from repoze.bfg.zcml import _rolledUpFactory
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 7ac32fae2..90f863fb3 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -543,35 +543,50 @@ def scan(_context, package):
args=(package, _context.info)
)
-def zcml_configure(name, package):
- """ Given a ZCML filename as ``name`` and a Python package as
- ``package`` which the filename should be relative to, load the
- ZCML into the current ZCML registry.
-
- .. note:: This feature is new as of :mod:`repoze.bfg` 1.1.
+class IAdapterDirective(Interface):
+ """
+ Register an adapter
"""
- context = ConfigurationMachine()
- xmlconfig.registerCommonDirectives(context)
- context.package = package
- xmlconfig.include(context, name, package)
- context.execute_actions(clear=False) # the raison d'etre
- return context.actions
-file_configure = zcml_configure # backwards compat (>0.8.1)
+ factory = Tokens(
+ title=u"Adapter factory/factories",
+ description=(u"A list of factories (usually just one) that create"
+ " the adapter instance."),
+ required=True,
+ value_type=GlobalObject()
+ )
-def handler(methodName, *args, **kwargs):
- registry = get_current_registry()
- method = getattr(registry, methodName)
- method(*args, **kwargs)
+ provides = GlobalInterface(
+ title=u"Interface the component provides",
+ description=(u"This attribute specifies the interface the adapter"
+ " instance must provide."),
+ required=False,
+ )
-def adapter(_context, factory, provides=None, for_=None, name=''):
+ for_ = Tokens(
+ title=u"Specifications to be adapted",
+ description=u"This should be a list of interfaces or classes",
+ required=False,
+ value_type=GlobalObject(
+ missing_value=object(),
+ ),
+ )
+
+ name = TextLine(
+ title=u"Name",
+ description=(u"Adapters can have names.\n\n"
+ "This attribute allows you to specify the name for"
+ " this adapter."),
+ required=False,
+ )
+def adapter(_context, factory, provides=None, for_=None, name=''):
if for_ is None:
if len(factory) == 1:
for_ = getattr(factory[0], '__component_adapts__', None)
if for_ is None:
- raise TypeError("No for attribute was provided and can't "
+ raise TypeError("No for argument was provided and can't "
"determine what the factory adapts.")
for_ = tuple(for_)
@@ -583,7 +598,7 @@ def adapter(_context, factory, provides=None, for_=None, name=''):
provides = p[0]
if provides is None:
- raise TypeError("Missing 'provides' attribute")
+ raise TypeError("Missing 'provided' argument")
# Generate a single factory from multiple factories:
factories = factory
@@ -592,31 +607,37 @@ def adapter(_context, factory, provides=None, for_=None, name=''):
elif len(factories) < 1:
raise ValueError("No factory specified")
elif len(factories) > 1 and len(for_) != 1:
- raise ValueError("Can't use multiple factories and multiple for")
+ raise ValueError("Can't use multiple factories and multiple "
+ "for")
else:
factory = _rolledUpFactory(factories)
-
+
+ reg = get_current_registry()
+ config = Configurator(reg, package=_context.package)
_context.action(
discriminator = ('adapter', for_, provides, name),
- callable = handler,
- args = ('registerAdapter',
- factory, for_, provides, name, _context.info),
+ callable = config.add_adapter,
+ args = (factory, for_, provides, name, _context.info),
)
-class IAdapterDirective(Interface):
+class ISubscriberDirective(Interface):
"""
- Register an adapter
+ Register a subscriber
"""
- factory = Tokens(
- title=u"Adapter factory/factories",
- description=(u"A list of factories (usually just one) that create"
- " the adapter instance."),
- required=True,
- value_type=GlobalObject()
+ factory = GlobalObject(
+ title=u"Subscriber factory",
+ description=u"A factory used to create the subscriber instance.",
+ required=False,
)
- provides = GlobalInterface(
+ handler = GlobalObject(
+ title=u"Handler",
+ description=u"A callable object that handles events.",
+ required=False,
+ )
+
+ provides = GlobalInterface(
title=u"Interface the component provides",
description=(u"This attribute specifies the interface the adapter"
" instance must provide."),
@@ -624,23 +645,14 @@ class IAdapterDirective(Interface):
)
for_ = Tokens(
- title=u"Specifications to be adapted",
+ title=u"Interfaces or classes that this subscriber depends on",
description=u"This should be a list of interfaces or classes",
required=False,
value_type=GlobalObject(
- missing_value=object(),
+ missing_value = object(),
),
)
- name = TextLine(
- title=u"Name",
- description=(u"Adapters can have names.\n\n"
- "This attribute allows you to specify the name for"
- " this adapter."),
- required=False,
- )
-
-_handler = handler
def subscriber(_context, for_=None, factory=None, handler=None, provides=None):
if factory is None:
if handler is None:
@@ -664,82 +676,22 @@ def subscriber(_context, for_=None, factory=None, handler=None, provides=None):
for_ = tuple(for_)
+ reg = get_current_registry()
+ config = Configurator(reg, _context.package)
+
if handler is not None:
_context.action(
discriminator = None,
- callable = _handler,
- args = ('registerHandler',
- handler, for_, u'', _context.info),
+ callable = config.add_subscriber,
+ args = (handler, for_, _context.info),
)
else:
_context.action(
discriminator = None,
- callable = _handler,
- args = ('registerSubscriptionAdapter',
- factory, for_, provides, u'', _context.info),
+ callable = config.add_subscription_adapter,
+ args = (factory, for_, provides, _context.info),
)
-class ISubscriberDirective(Interface):
- """
- Register a subscriber
- """
-
- factory = GlobalObject(
- title=u"Subscriber factory",
- description=u"A factory used to create the subscriber instance.",
- required=False,
- )
-
- handler = GlobalObject(
- title=u"Handler",
- description=u"A callable object that handles events.",
- required=False,
- )
-
- provides = GlobalInterface(
- title=u"Interface the component provides",
- description=(u"This attribute specifies the interface the adapter"
- " instance must provide."),
- required=False,
- )
-
- for_ = Tokens(
- title=u"Interfaces or classes that this subscriber depends on",
- description=u"This should be a list of interfaces or classes",
- required=False,
- value_type=GlobalObject(
- missing_value = object(),
- ),
- )
-
-def utility(_context, provides=None, component=None, factory=None, name=''):
- if factory and component:
- raise TypeError("Can't specify factory and component.")
-
- if provides is None:
- if factory:
- provides = list(implementedBy(factory))
- else:
- provides = list(providedBy(component))
- if len(provides) == 1:
- provides = provides[0]
- else:
- raise TypeError("Missing 'provides' attribute")
-
- if factory:
- kw = dict(factory=factory)
- else:
- # older component registries don't accept factory as a kwarg,
- # so if we don't need it, we don't pass it
- kw = {}
-
- _context.action(
- discriminator = ('utility', provides, name),
- callable = handler,
- args = ('registerUtility', component, provides, name),
- kw = kw,
- )
-
class IUtilityDirective(Interface):
"""Register a utility."""
@@ -775,14 +727,27 @@ class IUtilityDirective(Interface):
required=False,
)
-def _rolledUpFactory(factories):
- def factory(ob):
- for f in factories:
- ob = f(ob)
- return ob
- # Store the original factory for documentation
- factory.factory = factories[0]
- return factory
+def utility(_context, provides=None, component=None, factory=None, name=''):
+ if factory and component:
+ raise TypeError("Can't specify factory and component.")
+
+ if provides is None:
+ if factory:
+ provides = list(implementedBy(factory))
+ else:
+ provides = list(providedBy(component))
+ if len(provides) == 1:
+ provides = provides[0]
+ else:
+ raise TypeError("Missing 'provides' attribute")
+
+ reg = get_current_registry()
+ config = Configurator(reg, package=_context.package)
+ _context.action(
+ discriminator = ('utility', provides, name),
+ callable = config.add_utility,
+ args = (component, provides, name, _context.info, factory),
+ )
def path_spec(context, path):
# Convert an absolute path to a resource in a package to a
@@ -805,3 +770,28 @@ def path_spec(context, path):
relpath.replace(os.path.sep, '/'))
return abspath
+def zcml_configure(name, package):
+ """ Given a ZCML filename as ``name`` and a Python package as
+ ``package`` which the filename should be relative to, load the
+ ZCML into the current ZCML registry.
+
+ .. note:: This feature is new as of :mod:`repoze.bfg` 1.1.
+ """
+ context = ConfigurationMachine()
+ xmlconfig.registerCommonDirectives(context)
+ context.package = package
+ xmlconfig.include(context, name, package)
+ context.execute_actions(clear=False) # the raison d'etre
+ return context.actions
+
+file_configure = zcml_configure # backwards compat (>0.8.1)
+
+def _rolledUpFactory(factories):
+ def factory(ob):
+ for f in factories:
+ ob = f(ob)
+ return ob
+ # Store the original factory for documentation
+ factory.factory = factories[0]
+ return factory
+