summaryrefslogtreecommitdiff
path: root/repoze/bfg/zcml.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2008-12-21 03:33:08 +0000
committerChris McDonough <chrism@agendaless.com>2008-12-21 03:33:08 +0000
commit4e46a6f458fa31ca5f252dd31b1229fcb775299d (patch)
treec0e1edd7cd9aabbec53298b0db3c7868ac73db85 /repoze/bfg/zcml.py
parent6a530543757a92ed09b7ba624a868140f890511d (diff)
downloadpyramid-4e46a6f458fa31ca5f252dd31b1229fcb775299d.tar.gz
pyramid-4e46a6f458fa31ca5f252dd31b1229fcb775299d.tar.bz2
pyramid-4e46a6f458fa31ca5f252dd31b1229fcb775299d.zip
Backwards Incompatibilities (Major)
- Rather than prepare the "stock" implementations of the ZCML directives from the ``zope.configuration`` package for use under :mod:`repoze.bfg`, :mod:`repoze.bfg` now makes available the implementations of directives from the ``repoze.zcml`` package (see http://static.repoze.org/zcmldocs). As a result, the :mod:`repoze.bfg` package now depends on the ``repoze.zcml`` package, and no longer depends directly on the ``zope.component``, ``zope.configuration``, ``zope.interface``, or ``zope.proxy`` packages. The primary reason for this change is to enable us to eventually reduce the number of inappropriate :mod:`repoze.bfg` Zope package dependencies, as well as to shed features of dependent package directives that don't make sense for :mod:`repoze.bfg`. Note that currently the set of requirements necessary to use bfg has not changed. This is due to inappropriate Zope package requirements in ``chameleon.zpt``, which will hopefully be remedied soon. - BFG applications written prior to this release which expect the "stock" ``zope.component`` ZCML directive implementations (e.g. ``adapter``, ``subscriber``, or ``utility``) to function now must either 1) include the ``meta.zcml`` file from ``zope.component`` manually (e.g. ``<include package="zope.component" file="meta.zcml">``) and include the ``zope.security`` package as an ``install_requires`` dependency or 2) change the ZCML in their applications to use the declarations from `repoze.zcml <http://static.repoze.org/zcmldocs/>`_ instead of the stock declarations. ``repoze.zcml`` only makes available the ``adapter``, ``subscriber`` and ``utility`` directives. - The ``http://namespaces.repoze.org/bfg`` XML namespace is now the default XML namespace in ZCML for paster-generated applications. - The copies of BFG's ``meta.zcml`` and ``configure.zcml`` were removed from the root of the ``repoze.bfg`` package. In 0.3.6, a new package named ``repoze.bfg.includes`` was added, which contains the "correct" copies of these ZCML files; the ones that were removed were for backwards compatibility purposes. Other - The minimum requirement for ``chameleon.core`` is now 1.0b13. The minimum requirement for ``chameleon.zpt`` is now 1.0b7. The minimum requirement for ``chameleon.genshi`` is now 1.0b2.
Diffstat (limited to 'repoze/bfg/zcml.py')
-rw-r--r--repoze/bfg/zcml.py251
1 files changed, 250 insertions, 1 deletions
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 79d4c2561..91f5d9152 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -128,6 +128,246 @@ class IViewDirective(Interface):
required=False
)
+def adapter(_context, factory, provides=None, for_=None, name=''):
+
+ if for_ is None:
+ if len(factory) == 1:
+ for_ = zope.component.adaptedBy(factory[0])
+
+ if for_ is None:
+ raise TypeError("No for attribute was provided and can't "
+ "determine what the factory adapts.")
+
+ for_ = tuple(for_)
+
+ if provides is None:
+ if len(factory) == 1:
+ p = list(zope.interface.implementedBy(factory[0]))
+ if len(p) == 1:
+ provides = p[0]
+
+ if provides is None:
+ raise TypeError("Missing 'provides' attribute")
+
+ # Generate a single factory from multiple factories:
+ factories = factory
+ if len(factories) == 1:
+ factory = factories[0]
+ 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")
+ else:
+ factory = _rolledUpFactory(factories)
+
+ _context.action(
+ discriminator = ('adapter', for_, provides, name),
+ callable = handler,
+ args = ('registerAdapter',
+ factory, for_, provides, name, _context.info),
+ )
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', provides)
+ )
+ if for_:
+ for iface in for_:
+ if iface is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', iface)
+ )
+
+class IAdapterDirective(zope.interface.Interface):
+ """
+ Register an adapter
+ """
+
+ factory = zope.configuration.fields.Tokens(
+ title=u"Adapter factory/factories",
+ description=(u"A list of factories (usually just one) that create"
+ " the adapter instance."),
+ required=True,
+ value_type=zope.configuration.fields.GlobalObject()
+ )
+
+ provides = zope.configuration.fields.GlobalInterface(
+ title=u"Interface the component provides",
+ description=(u"This attribute specifies the interface the adapter"
+ " instance must provide."),
+ required=False,
+ )
+
+ for_ = zope.configuration.fields.Tokens(
+ title=u"Specifications to be adapted",
+ description=u"This should be a list of interfaces or classes",
+ required=False,
+ value_type=zope.configuration.fields.GlobalObject(
+ missing_value=object(),
+ ),
+ )
+
+ name = zope.schema.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:
+ raise TypeError("No factory or handler provided")
+ if provides is not None:
+ raise TypeError("Cannot use handler with provides")
+ factory = handler
+ else:
+ if handler is not None:
+ raise TypeError("Cannot use handler with factory")
+ if provides is None:
+ raise TypeError(
+ "You must specify a provided interface when registering "
+ "a factory")
+
+ 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 (or handler) adapts.")
+
+ for_ = tuple(for_)
+
+ if handler is not None:
+ _context.action(
+ discriminator = None,
+ callable = _handler,
+ args = ('registerHandler',
+ handler, for_, u'', _context.info),
+ )
+ else:
+ _context.action(
+ discriminator = None,
+ callable = _handler,
+ args = ('registerSubscriptionAdapter',
+ factory, for_, provides, u'', _context.info),
+ )
+
+ if provides is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', provides)
+ )
+
+ # For each interface, state that the adapter provides that interface.
+ for iface in for_:
+ if iface is not None:
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = ('', iface)
+ )
+
+class ISubscriberDirective(zope.interface.Interface):
+ """
+ Register a subscriber
+ """
+
+ factory = zope.configuration.fields.GlobalObject(
+ title=u"Subscriber factory",
+ description=u"A factory used to create the subscriber instance.",
+ required=False,
+ )
+
+ handler = zope.configuration.fields.GlobalObject(
+ title=u"Handler",
+ description=u"A callable object that handles events.",
+ required=False,
+ )
+
+ provides = zope.configuration.fields.GlobalInterface(
+ title=u"Interface the component provides",
+ description=(u"This attribute specifies the interface the adapter"
+ " instance must provide."),
+ required=False,
+ )
+
+ for_ = zope.configuration.fields.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=zope.configuration.fields.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(zope.interface.implementedBy(factory))
+ else:
+ provides = list(zope.interface.providedBy(component))
+ if len(provides) == 1:
+ provides = provides[0]
+ else:
+ raise TypeError("Missing 'provides' attribute")
+
+ _context.action(
+ discriminator = ('utility', provides, name),
+ callable = handler,
+ args = ('registerUtility', component, provides, name),
+ kw = dict(factory=factory),
+ )
+
+ _context.action(
+ discriminator = None,
+ callable = provideInterface,
+ args = (provides.__module__ + '.' + provides.getName(), provides)
+ )
+
+class IUtilityDirective(Interface):
+ """Register a utility."""
+
+ component = zope.configuration.fields.GlobalObject(
+ title=u"Component to use",
+ description=(u"Python name of the implementation object. This"
+ " must identify an object in a module using the"
+ " full dotted name. If specified, the"
+ " ``factory`` field must be left blank."),
+ required=False,
+ )
+
+ factory = zope.configuration.fields.GlobalObject(
+ title=u"Factory",
+ description=(u"Python name of a factory which can create the"
+ " implementation object. This must identify an"
+ " object in a module using the full dotted name."
+ " If specified, the ``component`` field must"
+ " be left blank."),
+ required=False,
+ )
+
+ provides = zope.configuration.fields.GlobalInterface(
+ title=u"Provided interface",
+ description=u"Interface provided by the utility.",
+ required=False,
+ )
+
+ name = zope.schema.TextLine(
+ title=u"Name",
+ description=(u"Name of the registration. This is used by"
+ " application code when locating a utility."),
+ required=False,
+ )
+
+
PVERSION = 1
def pickle_name(name, package):
@@ -216,4 +456,13 @@ def file_configure(name, package, dump=cPickle.dump):
return False
-
+def _rolledUpFactory(factories):
+ # This has to be named 'factory', aparently, so as not to confuse
+ # apidoc :(
+ def factory(ob):
+ for f in factories:
+ ob = f(ob)
+ return ob
+ # Store the original factory for documentation
+ factory.factory = factories[0]
+ return factory