[Checkins] SVN: zope.component/trunk/ Merge tseaver-test_cleanup branch.
Tres Seaver
cvs-admin at zope.org
Fri Jun 29 14:47:59 UTC 2012
Log message for revision 127192:
Merge tseaver-test_cleanup branch.
Changed:
_U zope.component/trunk/
U zope.component/trunk/.bzrignore
U zope.component/trunk/CHANGES.txt
A zope.component/trunk/docs/
U zope.component/trunk/docs/Makefile
U zope.component/trunk/docs/api/adapter.rst
U zope.component/trunk/docs/api/factory.rst
U zope.component/trunk/docs/api/interface.rst
U zope.component/trunk/docs/api/interfaces.rst
U zope.component/trunk/docs/api/persistent.rst
U zope.component/trunk/docs/api/security.rst
U zope.component/trunk/docs/api/sitemanager.rst
U zope.component/trunk/docs/api/utility.rst
U zope.component/trunk/docs/api.rst
U zope.component/trunk/docs/conf.py
U zope.component/trunk/docs/configure.rst
U zope.component/trunk/docs/event.rst
U zope.component/trunk/docs/factory.rst
U zope.component/trunk/docs/hooks.rst
U zope.component/trunk/docs/index.rst
U zope.component/trunk/docs/make.bat
U zope.component/trunk/docs/narr.rst
U zope.component/trunk/docs/persistentregistry.rst
U zope.component/trunk/docs/socketexample.rst
U zope.component/trunk/docs/testlayer.rst
U zope.component/trunk/docs/zcml.rst
A zope.component/trunk/setup.cfg
U zope.component/trunk/setup.py
D zope.component/trunk/src/zope/component/README.txt
U zope.component/trunk/src/zope/component/_api.py
A zope.component/trunk/src/zope/component/_compat.py
U zope.component/trunk/src/zope/component/_declaration.py
D zope.component/trunk/src/zope/component/configure.txt
U zope.component/trunk/src/zope/component/event.py
D zope.component/trunk/src/zope/component/event.txt
U zope.component/trunk/src/zope/component/eventtesting.py
U zope.component/trunk/src/zope/component/factory.py
D zope.component/trunk/src/zope/component/factory.txt
U zope.component/trunk/src/zope/component/globalregistry.py
U zope.component/trunk/src/zope/component/hooks.py
D zope.component/trunk/src/zope/component/hooks.txt
D zope.component/trunk/src/zope/component/index.txt
U zope.component/trunk/src/zope/component/interface.py
U zope.component/trunk/src/zope/component/interfaces.py
D zope.component/trunk/src/zope/component/nexttesting.py
U zope.component/trunk/src/zope/component/persistentregistry.py
D zope.component/trunk/src/zope/component/persistentregistry.txt
D zope.component/trunk/src/zope/component/registry.txt
U zope.component/trunk/src/zope/component/security.py
D zope.component/trunk/src/zope/component/socketexample.txt
U zope.component/trunk/src/zope/component/standalonetests.py
U zope.component/trunk/src/zope/component/testfiles/adapter.py
U zope.component/trunk/src/zope/component/testfiles/components.py
U zope.component/trunk/src/zope/component/testfiles/views.py
U zope.component/trunk/src/zope/component/testing.py
U zope.component/trunk/src/zope/component/testlayer.py
D zope.component/trunk/src/zope/component/testlayer.txt
A zope.component/trunk/src/zope/component/tests/
U zope.component/trunk/src/zope/component/tests/__init__.py
U zope.component/trunk/src/zope/component/tests/examples.py
U zope.component/trunk/src/zope/component/tests/test___init__.py
U zope.component/trunk/src/zope/component/tests/test__api.py
U zope.component/trunk/src/zope/component/tests/test__declaration.py
U zope.component/trunk/src/zope/component/tests/test_event.py
U zope.component/trunk/src/zope/component/tests/test_factory.py
U zope.component/trunk/src/zope/component/tests/test_globalregistry.py
U zope.component/trunk/src/zope/component/tests/test_hookable.py
U zope.component/trunk/src/zope/component/tests/test_hooks.py
U zope.component/trunk/src/zope/component/tests/test_interface.py
U zope.component/trunk/src/zope/component/tests/test_persistentregistry.py
U zope.component/trunk/src/zope/component/tests/test_registry.py
U zope.component/trunk/src/zope/component/tests/test_security.py
U zope.component/trunk/src/zope/component/tests/test_standalone.py
U zope.component/trunk/src/zope/component/tests/test_zcml.py
D zope.component/trunk/src/zope/component/tests.py
U zope.component/trunk/src/zope/component/zcml.py
D zope.component/trunk/src/zope/component/zcml.txt
D zope.component/trunk/src/zope/component/zcml_conditional.txt
A zope.component/trunk/tox.ini
-=-
Property changes on: zope.component/trunk
___________________________________________________________________
Added: svn:mergeinfo
+ /zope.component/tseaver-test_cleanup:126964-126965,126977-126979,126985-126993,127019-127036,127043-127050,127060-127065,127081-127090,127107-127128,127133-127140,127144
Added: svk:merge
+ 62d5b8a3-27da-0310-9561-8e5933582275:/zope.component/tseaver-test_cleanup:127144
Modified: zope.component/trunk/.bzrignore
===================================================================
--- zope.component/trunk/.bzrignore 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/.bzrignore 2012-06-29 14:47:56 UTC (rev 127192)
@@ -5,3 +5,9 @@
./docs
./parts
*.egg-info
+.coverage
+docs/_build
+.tox
+nosetests.xml
+coverage.xml
+__pycache__
Modified: zope.component/trunk/CHANGES.txt
===================================================================
--- zope.component/trunk/CHANGES.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/CHANGES.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,12 +1,34 @@
CHANGES
*******
-3.12.2 (unreleased)
-===================
+4.0.0 (unreleased)
+==================
-- Nothing changed yet.
+- Added PyPy and Python 3.2 support:
+ - Security support omitted until ``zope.security`` ported.
+ - Persistent registry support omitted until ``ZODB`` ported (or
+ ``persistent`` factored out).
+
+- 100% unit test coverage.
+
+- Removed the long-deprecated ``layer`` argument to the
+ ``zope.component.zcml.view`` and ``zope.component.zcml.resource``
+ ZCML directives.
+
+- Added support for continuous integration using ``tox`` and ``jenkins``.
+
+- Got tests to run using ``setup.py test``.
+
+- Added ``Sphinx`` documentation.
+
+- Added ``setup.py docs`` alias (installs ``Sphinx`` and dependencies).
+
+- Added ``setup.py dev`` alias (runs ``setup.py develop`` plus installs
+ ``nose`` and ``coverage``).
+
+
3.12.1 (2012-04-02)
===================
Copied: zope.component/trunk/setup.cfg (from rev 127144, zope.component/tseaver-test_cleanup/setup.cfg)
===================================================================
--- zope.component/trunk/setup.cfg (rev 0)
+++ zope.component/trunk/setup.cfg 2012-06-29 14:47:56 UTC (rev 127192)
@@ -0,0 +1,10 @@
+[nosetests]
+nocapture=1
+cover-package=zope.component
+cover-erase=1
+with-doctest=0
+where=src
+
+[aliases]
+dev = develop easy_install zope.component[testing]
+docs = easy_install zope.component[docs]
Modified: zope.component/trunk/setup.py
===================================================================
--- zope.component/trunk/setup.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/setup.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -23,14 +23,48 @@
from setuptools import setup, find_packages
-tests_require = [
- 'ZODB3',
- 'zope.hookable',
+TESTS_REQUIRE = [
'zope.testing',
- 'zope.testrunner',
+ 'zope.component[hook]',
+ 'zope.component[persistentregistry]',
+ 'zope.component[security]',
+ 'zope.component[zcml]',
]
+def _modname(path, base, name=''):
+ if path == base:
+ return name
+ dirname, basename = os.path.split(path)
+ return _modname(dirname, base, basename + '.' + name)
+def alltests():
+ import logging
+ import pkg_resources
+ import unittest
+
+ class NullHandler(logging.Handler):
+ level = 50
+
+ def emit(self, record):
+ pass
+
+ logging.getLogger().addHandler(NullHandler())
+
+ suite = unittest.TestSuite()
+ base = pkg_resources.working_set.find(
+ pkg_resources.Requirement.parse('zope.component')).location
+ for dirpath, dirnames, filenames in os.walk(base):
+ if os.path.basename(dirpath) == 'tests':
+ for filename in filenames:
+ if ( filename.endswith('.py') and
+ filename.startswith('test') ):
+ mod = __import__(
+ _modname(dirpath, base, os.path.splitext(filename)[0]),
+ {}, {}, ['*'])
+ suite.addTest(mod.test_suite())
+ return suite
+
+
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
@@ -45,25 +79,7 @@
long_description=(
read('README.txt')
+ '\n' +
- 'Detailed Documentation\n'
- '**********************\n'
- + '\n' +
- read('src', 'zope', 'component', 'README.txt')
- + '\n' +
- read('src', 'zope', 'component', 'event.txt')
- + '\n' +
- read('src', 'zope', 'component', 'factory.txt')
- + '\n' +
- read('src', 'zope', 'component', 'registry.txt')
- + '\n' +
- read('src', 'zope', 'component', 'persistentregistry.txt')
- + '\n' +
- read('src', 'zope', 'component', 'socketexample.txt')
- + '\n' +
read('CHANGES.txt')
- + '\n' +
- 'Download\n'
- '********\n'
),
packages = find_packages('src'),
package_dir = {'': 'src'},
@@ -75,29 +91,35 @@
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.2",
+ "Programming Language :: Python :: Implementation :: CPython",
+ "Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Software Development :: Libraries :: Python Modules",
],
namespace_packages=['zope',],
- tests_require = tests_require,
+ tests_require = TESTS_REQUIRE,
+ test_suite='__main__.alltests',
install_requires=['setuptools',
'zope.interface>=3.8.0',
'zope.event',
],
include_package_data = True,
zip_safe = False,
- extras_require = dict(
- hook = ['zope.hookable'],
- persistentregistry = ['ZODB3'],
- security = ['zope.location',
+ extras_require = {
+ 'hook': ['zope.hookable'],
+ 'persistentregistry': ['ZODB3'],
+ 'security': ['zope.location',
'zope.proxy',
'zope.security',
],
- zcml = ['zope.configuration',
+ 'zcml': ['zope.configuration',
'zope.i18nmessageid',
],
- test = tests_require,
- ),
+ 'test': TESTS_REQUIRE,
+ 'testing': TESTS_REQUIRE + ['nose', 'coverage'],
+ 'docs': ['Sphinx', 'repoze.sphinx.autointerface'],
+ },
)
Deleted: zope.component/trunk/src/zope/component/README.txt
===================================================================
--- zope.component/trunk/src/zope/component/README.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/README.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,402 +0,0 @@
-Zope Component Architecture
-===========================
-
-This package, together with `zope.interface`, provides facilities for
-defining, registering and looking up components. There are two basic
-kinds of components: adapters and utilities.
-
-Utilities
----------
-
-Utilities are just components that provide an interface and that are
-looked up by an interface and a name. Let's look at a trivial utility
-definition:
-
- >>> from zope import interface
-
- >>> class IGreeter(interface.Interface):
- ... def greet():
- ... "say hello"
-
- >>> class Greeter:
- ... interface.implements(IGreeter)
- ...
- ... def __init__(self, other="world"):
- ... self.other = other
- ...
- ... def greet(self):
- ... print "Hello", self.other
-
-We can register an instance this class using `provideUtility` [1]_:
-
- >>> from zope import component
- >>> greet = Greeter('bob')
- >>> component.provideUtility(greet, IGreeter, 'robert')
-
-In this example we registered the utility as providing the `IGreeter`
-interface with a name of 'bob'. We can look the interface up with
-either `queryUtility` or `getUtility`:
-
- >>> component.queryUtility(IGreeter, 'robert').greet()
- Hello bob
-
- >>> component.getUtility(IGreeter, 'robert').greet()
- Hello bob
-
-`queryUtility` and `getUtility` differ in how failed lookups are handled:
-
- >>> component.queryUtility(IGreeter, 'ted')
- >>> component.queryUtility(IGreeter, 'ted', 42)
- 42
- >>> component.getUtility(IGreeter, 'ted')
- ... # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<InterfaceClass ...IGreeter>, 'ted')
-
-If a component provides only one interface, as in the example above,
-then we can omit the provided interface from the call to `provideUtility`:
-
- >>> ted = Greeter('ted')
- >>> component.provideUtility(ted, name='ted')
- >>> component.queryUtility(IGreeter, 'ted').greet()
- Hello ted
-
-The name defaults to an empty string:
-
- >>> world = Greeter()
- >>> component.provideUtility(world)
- >>> component.queryUtility(IGreeter).greet()
- Hello world
-
-Adapters
---------
-
-Adapters are components that are computed from other components to
-adapt them to some interface. Because they are computed from other
-objects, they are provided as factories, usually classes. Here, we'll
-create a greeter for persons, so we can provide personalized greetings
-for different people:
-
- >>> class IPerson(interface.Interface):
- ... name = interface.Attribute("Name")
-
- >>> class PersonGreeter:
- ...
- ... component.adapts(IPerson)
- ... interface.implements(IGreeter)
- ...
- ... def __init__(self, person):
- ... self.person = person
- ...
- ... def greet(self):
- ... print "Hello", self.person.name
-
-The class defines a constructor that takes an argument for every
-object adapted.
-
-We used `component.adapts` to declare what we adapt. We can find
-out if an object declares that it adapts anything using adaptedBy:
-
- >>> list(component.adaptedBy(PersonGreeter)) == [IPerson]
- True
-
-If an object makes no declaration, then None is returned:
-
- >>> component.adaptedBy(Greeter()) is None
- True
-
-
-If we declare the interfaces adapted and if we provide only one
-interface, as in the example above, then we can provide the adapter
-very simply [1]_:
-
- >>> component.provideAdapter(PersonGreeter)
-
-For adapters that adapt a single interface to a single interface
-without a name, we can get the adapter by simply calling the
-interface:
-
- >>> class Person:
- ... interface.implements(IPerson)
- ...
- ... def __init__(self, name):
- ... self.name = name
-
- >>> IGreeter(Person("Sally")).greet()
- Hello Sally
-
-We can also provide arguments to be very specific about what
-how to register the adapter.
-
- >>> class BobPersonGreeter(PersonGreeter):
- ... name = 'Bob'
- ... def greet(self):
- ... print "Hello", self.person.name, "my name is", self.name
-
- >>> component.provideAdapter(
- ... BobPersonGreeter, [IPerson], IGreeter, 'bob')
-
-The arguments can also be provided as keyword arguments:
-
- >>> class TedPersonGreeter(BobPersonGreeter):
- ... name = "Ted"
-
- >>> component.provideAdapter(
- ... factory=TedPersonGreeter, adapts=[IPerson],
- ... provides=IGreeter, name='ted')
-
-For named adapters, use `queryAdapter`, or `getAdapter`:
-
- >>> component.queryAdapter(Person("Sally"), IGreeter, 'bob').greet()
- Hello Sally my name is Bob
-
- >>> component.getAdapter(Person("Sally"), IGreeter, 'ted').greet()
- Hello Sally my name is Ted
-
-If an adapter can't be found, `queryAdapter` returns a default value
-and `getAdapter` raises an error:
-
- >>> component.queryAdapter(Person("Sally"), IGreeter, 'frank')
- >>> component.queryAdapter(Person("Sally"), IGreeter, 'frank', 42)
- 42
- >>> component.getAdapter(Person("Sally"), IGreeter, 'frank')
- ... # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- ComponentLookupError: (...Person...>, <...IGreeter>, 'frank')
-
-Adapters can adapt multiple objects:
-
- >>> class TwoPersonGreeter:
- ...
- ... component.adapts(IPerson, IPerson)
- ... interface.implements(IGreeter)
- ...
- ... def __init__(self, person, greeter):
- ... self.person = person
- ... self.greeter = greeter
- ...
- ... def greet(self):
- ... print "Hello", self.person.name
- ... print "my name is", self.greeter.name
-
- >>> component.provideAdapter(TwoPersonGreeter)
-
-Note that the declaration-order of the Interfaces beeing adapted to is
-important for adapter look up. It must be the the same as the order of
-parameters given to the adapter and used to query the adapter. This is
-especially the case when different Interfaces are adapt to (opposed to
-this example).
-
-To look up a multi-adapter, use either `queryMultiAdapter` or
-`getMultiAdapter`:
-
- >>> component.queryMultiAdapter((Person("Sally"), Person("Bob")),
- ... IGreeter).greet()
- Hello Sally
- my name is Bob
-
-Adapters need not be classes. Any callable will do. We use the
-adapter decorator (in the Python 2.4 decorator sense) to declare that
-a callable object adapts some interfaces (or classes):
-
- >>> class IJob(interface.Interface):
- ... "A job"
-
- >>> class Job:
- ... interface.implements(IJob)
-
- >>> def personJob(person):
- ... return getattr(person, 'job', None)
- >>> personJob = interface.implementer(IJob)(personJob)
- >>> personJob = component.adapter(IPerson)(personJob)
-
-In Python 2.4, the example can be written:
-
- >>> @interface.implementer(IJob)
- ... @component.adapter(IPerson)
- ... def personJob(person):
- ... return getattr(person, 'job', None)
-
-which looks a bit nicer.
-
-In this example, the personJob function simply returns the person's
-`job` attribute if present, or None if it's not present. An adapter
-factory can return None to indicate that adaptation wasn't possible.
-Let's register this adapter and try it out:
-
- >>> component.provideAdapter(personJob)
- >>> sally = Person("Sally")
- >>> IJob(sally) # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- TypeError: ('Could not adapt', ...
-
-The adaptation failed because sally didn't have a job. Let's give her
-one:
-
- >>> job = Job()
- >>> sally.job = job
- >>> IJob(sally) is job
- True
-
-Subscription Adapters
----------------------
-
-Unlike regular adapters, subscription adapters are used when we want
-all of the adapters that adapt an object to a particular adapter.
-
-Consider a validation problem. We have objects and we want to assess
-whether they meet some sort of standards. We define a validation
-interface:
-
- >>> class IValidate(interface.Interface):
- ... def validate(ob):
- ... """Determine whether the object is valid
- ...
- ... Return a string describing a validation problem.
- ... An empty string is returned to indicate that the
- ... object is valid.
- ... """
-
-Perhaps we have documents:
-
- >>> class IDocument(interface.Interface):
- ... summary = interface.Attribute("Document summary")
- ... body = interface.Attribute("Document text")
-
- >>> class Document:
- ... interface.implements(IDocument)
- ... def __init__(self, summary, body):
- ... self.summary, self.body = summary, body
-
-Now, we may want to specify various validation rules for
-documents. For example, we might require that the summary be a single
-line:
-
- >>> class SingleLineSummary:
- ... component.adapts(IDocument)
- ... interface.implements(IValidate)
- ...
- ... def __init__(self, doc):
- ... self.doc = doc
- ...
- ... def validate(self):
- ... if '\n' in self.doc.summary:
- ... return 'Summary should only have one line'
- ... else:
- ... return ''
-
-Or we might require the body to be at least 1000 characters in length:
-
- >>> class AdequateLength:
- ... component.adapts(IDocument)
- ... interface.implements(IValidate)
- ...
- ... def __init__(self, doc):
- ... self.doc = doc
- ...
- ... def validate(self):
- ... if len(self.doc.body) < 1000:
- ... return 'too short'
- ... else:
- ... return ''
-
-We can register these as subscription adapters [1]_:
-
- >>> component.provideSubscriptionAdapter(SingleLineSummary)
- >>> component.provideSubscriptionAdapter(AdequateLength)
-
-We can then use the subscribers to validate objects:
-
- >>> doc = Document("A\nDocument", "blah")
- >>> [adapter.validate()
- ... for adapter in component.subscribers([doc], IValidate)
- ... if adapter.validate()]
- ['Summary should only have one line', 'too short']
-
- >>> doc = Document("A\nDocument", "blah" * 1000)
- >>> [adapter.validate()
- ... for adapter in component.subscribers([doc], IValidate)
- ... if adapter.validate()]
- ['Summary should only have one line']
-
- >>> doc = Document("A Document", "blah")
- >>> [adapter.validate()
- ... for adapter in component.subscribers([doc], IValidate)
- ... if adapter.validate()]
- ['too short']
-
-Handlers
---------
-
-Handlers are subscription adapter factories that don't produce
-anything. They do all of their work when called. Handlers
-are typically used to handle events.
-
-Event subscribers are different from other subscription adapters in
-that the caller of event subscribers doesn't expect to interact with
-them in any direct way. For example, an event publisher doesn't
-expect to get any return value. Because subscribers don't need to
-provide an API to their callers, it is more natural to define them
-with functions, rather than classes. For example, in a
-document-management system, we might want to record creation times for
-documents:
-
- >>> import datetime
-
- >>> def documentCreated(event):
- ... event.doc.created = datetime.datetime.utcnow()
-
-In this example, we have a function that takes an event and performs
-some processing. It doesn't actually return anything. This is a
-special case of a subscription adapter that adapts an event to
-nothing. All of the work is done when the adapter "factory" is
-called. We call subscribers that don't actually create anything
-"handlers". There are special APIs for registering and calling
-them.
-
-To register the subscriber above, we define a document-created event:
-
- >>> class IDocumentCreated(interface.Interface):
- ... doc = interface.Attribute("The document that was created")
-
- >>> class DocumentCreated:
- ... interface.implements(IDocumentCreated)
- ...
- ... def __init__(self, doc):
- ... self.doc = doc
-
-We'll also change our handler definition to:
-
- >>> def documentCreated(event):
- ... event.doc.created = datetime.datetime.utcnow()
-
- >>> documentCreated = component.adapter(IDocumentCreated)(documentCreated)
-
-Note that in Python 2.4, this can be written:
-
- >>> @component.adapter(IDocumentCreated)
- ... def documentCreated(event):
- ... event.doc.created = datetime.datetime.utcnow()
-
-This marks the handler as an adapter of `IDocumentCreated` events.
-
-Now we'll register the handler [1]_:
-
- >>> component.provideHandler(documentCreated)
-
-Now, if we can create an event and use the `handle` function to call
-handlers registered for the event:
-
- >>> component.handle(DocumentCreated(doc))
- >>> doc.created.__class__.__name__
- 'datetime'
-
-
-
-.. [1] CAUTION: This API should only be used from test or
- application-setup code. This API shouldn't be used by regular
- library modules, as component registration is a configuration
- activity.
Modified: zope.component/trunk/src/zope/component/_api.py
===================================================================
--- zope.component/trunk/src/zope/component/_api.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/_api.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -25,6 +25,7 @@
from zope.component.interfaces import IFactory
from zope.component.interfaces import ComponentLookupError
from zope.component.interfaces import IComponentLookup
+from zope.component._compat import _BLANK
from zope.component._declaration import adaptedBy
from zope.component._declaration import adapter
from zope.component._declaration import adapts
@@ -33,7 +34,7 @@
# to our Python version if not.
try:
from zope.hookable import hookable
-except ImportError:
+except ImportError: #pragma NO COVER
from zope.component.hookable import hookable
# getSiteManager() returns a component registry. Although the term
@@ -42,6 +43,8 @@
base = None
@hookable
def getSiteManager(context=None):
+ """ See IComponentArchitecture.
+ """
global base
if context is None:
if base is None:
@@ -52,7 +55,7 @@
# to avoid the recursion implied by using a local `getAdapter()` call.
try:
return IComponentLookup(context)
- except TypeError, error:
+ except TypeError as error:
raise ComponentLookupError(*error.args)
# Adapter API
@@ -90,26 +93,26 @@
return getSiteManager(context).queryAdapter(object, interface, '', default)
-def getAdapter(object, interface=Interface, name=u'', context=None):
+def getAdapter(object, interface=Interface, name=_BLANK, context=None):
adapter = queryAdapter(object, interface, name, None, context)
if adapter is None:
raise ComponentLookupError(object, interface, name)
return adapter
-def queryAdapter(object, interface=Interface, name=u'', default=None,
+def queryAdapter(object, interface=Interface, name=_BLANK, default=None,
context=None):
if context is None:
return adapter_hook(interface, object, name, default)
return getSiteManager(context).queryAdapter(object, interface, name,
default)
-def getMultiAdapter(objects, interface=Interface, name=u'', context=None):
+def getMultiAdapter(objects, interface=Interface, name=_BLANK, context=None):
adapter = queryMultiAdapter(objects, interface, name, context=context)
if adapter is None:
raise ComponentLookupError(objects, interface, name)
return adapter
-def queryMultiAdapter(objects, interface=Interface, name=u'', default=None,
+def queryMultiAdapter(objects, interface=Interface, name=_BLANK, default=None,
context=None):
try:
sitemanager = getSiteManager(context)
@@ -136,10 +139,7 @@
return sitemanager.subscribers(objects, interface)
def handle(*objects):
- sitemanager = getSiteManager(None)
- # iterating over subscribers assures they get executed
- for ignored in sitemanager.subscribers(objects, None):
- pass
+ getSiteManager(None).subscribers(objects, None)
#############################################################################
# Register the component architectures adapter hook, with the adapter hook
@@ -150,7 +150,7 @@
def adapter_hook(interface, object, name='', default=None):
try:
sitemanager = getSiteManager()
- except ComponentLookupError:
+ except ComponentLookupError: #pragma NO COVER w/o context, cannot test
# Oh blast, no site manager. This should *never* happen!
return None
return sitemanager.queryAdapter(object, interface, name, default)
@@ -216,13 +216,23 @@
# Factories
def createObject(__factory_name, *args, **kwargs):
+ """Invoke the named factory and return the result.
+
+ ``__factory_name`` is a positional-only argument.
+ """
context = kwargs.pop('context', None)
return getUtility(IFactory, __factory_name, context)(*args, **kwargs)
def getFactoryInterfaces(name, context=None):
+ """Return the interface provided by the named factory's objects
+
+ Result might be a single interface. XXX
+ """
return getUtility(IFactory, name, context).getInterfaces()
def getFactoriesFor(interface, context=None):
+ """Return info on all factories implementing the given interface.
+ """
utils = getSiteManager(context)
for (name, factory) in utils.getUtilitiesFor(IFactory):
interfaces = factory.getInterfaces()
Copied: zope.component/trunk/src/zope/component/_compat.py (from rev 127144, zope.component/tseaver-test_cleanup/src/zope/component/_compat.py)
===================================================================
--- zope.component/trunk/src/zope/component/_compat.py (rev 0)
+++ zope.component/trunk/src/zope/component/_compat.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -0,0 +1,42 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+
+import sys
+import types
+
+if sys.version_info[0] < 3: #pragma NO COVER
+
+ import cPickle as _pickle
+
+ def _u(s):
+ return unicode(s, 'unicode_escape')
+
+ CLASS_TYPES = (type, types.ClassType)
+
+ PYTHON3 = False
+ PYTHON2 = True
+
+else: #pragma NO COVER
+
+ import pickle as _pickle
+
+ def _u(s):
+ return s
+
+ CLASS_TYPES = (type,)
+
+ PYTHON3 = True
+ PYTHON2 = False
+
+_BLANK = _u('')
Modified: zope.component/trunk/src/zope/component/_declaration.py
===================================================================
--- zope.component/trunk/src/zope/component/_declaration.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/_declaration.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,16 +13,17 @@
##############################################################################
"""Adapter declarations
"""
-import types
import sys
-class adapter:
+from zope.component._compat import CLASS_TYPES
+class adapter(object):
+
def __init__(self, *interfaces):
self.interfaces = interfaces
def __call__(self, ob):
- if isinstance(ob, _class_types):
+ if isinstance(ob, CLASS_TYPES):
ob.__component_adapts__ = _adapts_descr(self.interfaces)
else:
ob.__component_adapts__ = self.interfaces
@@ -33,11 +34,8 @@
frame = sys._getframe(1)
locals = frame.f_locals
- # Try to make sure we were called from a class def. In 2.2.0 we can't
- # check for __module__ since it doesn't seem to be added to the locals
- # until later on.
- if (locals is frame.f_globals) or (
- ('__module__' not in locals) and sys.version_info[:3] > (2, 2, 0)):
+ # Ensure we were called from a class def.
+ if locals is frame.f_globals or '__module__' not in locals:
raise TypeError("adapts can be used only from a class definition.")
if '__component_adapts__' in locals:
@@ -48,8 +46,6 @@
def adaptedBy(ob):
return getattr(ob, '__component_adapts__', None)
-_class_types = type, types.ClassType
-
class _adapts_descr(object):
def __init__(self, interfaces):
self.interfaces = interfaces
Deleted: zope.component/trunk/src/zope/component/configure.txt
===================================================================
--- zope.component/trunk/src/zope/component/configure.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/configure.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,13 +0,0 @@
-Package configuration
-=====================
-
-The ``zope.component`` package provides a ZCML file that configures some basic
-components:
-
- >>> from zope.configuration.xmlconfig import XMLConfig
- >>> import zope.component
-
- >>> XMLConfig('configure.zcml', zope.component)()
-
- >>> len(list(zope.component.getGlobalSiteManager().registeredHandlers()))
- 5
Modified: zope.component/trunk/src/zope/component/event.py
===================================================================
--- zope.component/trunk/src/zope/component/event.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/event.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -11,22 +11,26 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Implement Component Architecture-specific event dispatching, based
-on subscription adapters / handlers.
+"""Component Architecture-specific event dispatching
+
+Based on subscription adapters / handlers.
"""
-__docformat__ = 'restructuredtext'
-import zope.component.interfaces
-import zope.event
+from zope.event import subscribers as event_subscribers
+from zope.component.interfaces import IObjectEvent
+from zope.component._api import subscribers as component_subscribers
+from zope.component._declaration import adapter
+
def dispatch(*event):
- zope.component.subscribers(event, None)
+ component_subscribers(event, None)
-zope.event.subscribers.append(dispatch)
+event_subscribers.append(dispatch)
- at zope.component.adapter(zope.component.interfaces.IObjectEvent)
+ at adapter(IObjectEvent)
def objectEventNotify(event):
- """Event subscriber to dispatch ObjectEvents to interested adapters."""
- zope.component.subscribers((event.object, event), None)
+ """Dispatch ObjectEvents to interested adapters.
+ """
+ component_subscribers((event.object, event), None)
Deleted: zope.component/trunk/src/zope/component/event.txt
===================================================================
--- zope.component/trunk/src/zope/component/event.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/event.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,142 +0,0 @@
-Events
-======
-
-The Component Architecture provides a way to dispatch events to event
-handlers. Event handlers are registered as *subscribers*
-a.k.a. *handlers*.
-
-Before we can start we need to import ``zope.component.event`` to make
-the dispatching effective:
-
- >>> import zope.component.event
-
-Consider two event classes:
-
- >>> class Event1(object):
- ... pass
-
- >>> class Event2(Event1):
- ... pass
-
-Now consider two handlers for these event classes:
-
- >>> called = []
-
- >>> import zope.component
- >>> @zope.component.adapter(Event1)
- ... def handler1(event):
- ... called.append(1)
-
- >>> @zope.component.adapter(Event2)
- ... def handler2(event):
- ... called.append(2)
-
-We can register them with the Component Architecture:
-
- >>> zope.component.provideHandler(handler1)
- >>> zope.component.provideHandler(handler2)
-
-Now let's go through the events. We'll see that the handlers have been
-called accordingly:
-
- >>> from zope.event import notify
- >>> notify(Event1())
- >>> called
- [1]
-
- >>> del called[:]
- >>> notify(Event2())
- >>> called.sort()
- >>> called
- [1, 2]
-
-
-
-Object events
--------------
-
-
-The ``objectEventNotify`` function is a subscriber to dispatch
-ObjectEvents to interested adapters.
-
-First create an object class:
-
- >>> class IUseless(zope.interface.Interface):
- ... """Useless object"""
-
- >>> class UselessObject(object):
- ... """Useless object"""
- ... zope.interface.implements(IUseless)
-
-Then create an event class:
-
- >>> class IObjectThrownEvent(zope.component.interfaces.IObjectEvent):
- ... """An object has been thrown away"""
-
- >>> class ObjectThrownEvent(zope.component.interfaces.ObjectEvent):
- ... """An object has been thrown away"""
- ... zope.interface.implements(IObjectThrownEvent)
-
-Create an object and an event:
-
- >>> hammer = UselessObject()
- >>> event = ObjectThrownEvent(hammer)
-
-Then notify the event to the subscribers.
-Since the subscribers list is empty, nothing happens.
-
- >>> zope.component.event.objectEventNotify(event)
-
-Now create an handler for the event:
-
- >>> events = []
- >>> def record(*args):
- ... events.append(args)
-
- >>> zope.component.provideHandler(record, [IUseless, IObjectThrownEvent])
-
-The event is notified to the subscriber:
-
- >>> zope.component.event.objectEventNotify(event)
- >>> events == [(hammer, event)]
- True
-
-Following test demonstrates how a subscriber can raise an exception
-to prevent an action.
-
- >>> zope.component.provideHandler(zope.component.event.objectEventNotify)
-
-Let's create a container:
-
- >>> class ToolBox(dict):
- ... def __delitem__(self, key):
- ... notify(ObjectThrownEvent(self[key]))
- ... return super(ToolBox,self).__delitem__(key)
-
- >>> container = ToolBox()
-
-And put the object into the container:
-
- >>> container['Red Hammer'] = hammer
-
-Create an handler function that will raise an error when called:
-
- >>> class Veto(Exception):
- ... pass
-
- >>> def callback(item, event):
- ... assert(item == event.object)
- ... raise Veto
-
-Register the handler:
-
- >>> zope.component.provideHandler(callback, [IUseless, IObjectThrownEvent])
-
-Then if we try to remove the object, an ObjectThrownEvent is fired:
-
- >>> del container['Red Hammer']
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- raise Veto
- Veto
Modified: zope.component/trunk/src/zope/component/eventtesting.py
===================================================================
--- zope.component/trunk/src/zope/component/eventtesting.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/eventtesting.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -20,10 +20,14 @@
from zope.component.registry import (
dispatchSubscriptionAdapterRegistrationEvent)
from zope.component.registry import dispatchHandlerRegistrationEvent
-from zope.testing import cleanup
+try:
+ from zope.testing.cleanup import addCleanUp
+except ImportError: #pragma NO COVER
+ def addCleanUp(x):
+ pass
events = []
-def getEvents(event_type=None, filter=None):
+def getEvents(event_type=None, filter=None): #pragma NO COVER going aaway
r = []
for event in events:
if event_type is not None and not event_type.providedBy(event):
@@ -34,11 +38,11 @@
return r
-def clearEvents():
+def clearEvents(): #pragma NO COVER going aaway
del events[:]
-cleanup.addCleanUp(clearEvents)
+addCleanUp(clearEvents)
-class PlacelessSetup:
+class PlacelessSetup: #pragma NO COVER going aaway
def setUp(self):
provideHandler(objectEventNotify)
@@ -48,5 +52,5 @@
provideHandler(dispatchHandlerRegistrationEvent)
provideHandler(events.append, (None,))
-def setUp(test=None):
+def setUp(test=None): #pragma NO COVER going aaway
PlacelessSetup().setUp()
Modified: zope.component/trunk/src/zope/component/factory.py
===================================================================
--- zope.component/trunk/src/zope/component/factory.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/factory.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,17 +13,19 @@
##############################################################################
"""Factory object
"""
-from zope.interface import implements, implementedBy
+from zope.interface import implementer
+from zope.interface import implementedBy
from zope.interface.declarations import Implements
from zope.component.interfaces import IFactory
+
+ at implementer(IFactory)
class Factory(object):
"""Generic factory implementation.
The purpose of this implementation is to provide a quick way of creating
factories for classes, functions and other objects.
"""
- implements(IFactory)
def __init__(self, callable, title='', description='', interfaces=None):
self._callable = callable
@@ -41,5 +43,5 @@
return spec
return implementedBy(self._callable)
- def __repr__(self):
+ def __repr__(self): #pragma NO COVER
return '<%s for %s>' % (self.__class__.__name__, repr(self._callable))
Deleted: zope.component/trunk/src/zope/component/factory.txt
===================================================================
--- zope.component/trunk/src/zope/component/factory.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/factory.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,131 +0,0 @@
-Factories
-=========
-
-
-The Factory Class
------------------
-
- >>> from zope.interface import Interface
- >>> class IFunction(Interface):
- ... pass
-
- >>> class IKlass(Interface):
- ... pass
-
- >>> from zope.interface import implements
- >>> class Klass(object):
- ... implements(IKlass)
- ...
- ... def __init__(self, *args, **kw):
- ... self.args = args
- ... self.kw = kw
-
- >>> from zope.component.factory import Factory
- >>> factory = Factory(Klass, 'Klass', 'Klassier')
- >>> factory2 = Factory(lambda x: x, 'Func', 'Function')
- >>> factory3 = Factory(lambda x: x, 'Func', 'Function', (IFunction,))
-
-Calling a Factory
-~~~~~~~~~~~~~~~~~
-
-Here we test whether the factory correctly creates the objects and
-including the correct handling of constructor elements.
-
-First we create a factory that creates instanace of the `Klass` class:
-
- >>> factory = Factory(Klass, 'Klass', 'Klassier')
-
-Now we use the factory to create the instance
-
- >>> kl = factory(1, 2, foo=3, bar=4)
-
-and make sure that the correct class was used to create the object:
-
- >>> kl.__class__
- <class 'Klass'>
-
-Since we passed in a couple positional and keyword arguments
-
- >>> kl.args
- (1, 2)
- >>> kl.kw
- {'foo': 3, 'bar': 4}
-
- >>> factory2(3)
- 3
- >>> factory3(3)
- 3
-
-
-Title and Description
-~~~~~~~~~~~~~~~~~~~~~
-
- >>> factory.title
- 'Klass'
- >>> factory.description
- 'Klassier'
- >>> factory2.title
- 'Func'
- >>> factory2.description
- 'Function'
- >>> factory3.title
- 'Func'
- >>> factory3.description
- 'Function'
-
-
-Provided Interfaces
-~~~~~~~~~~~~~~~~~~~
-
- >>> implemented = factory.getInterfaces()
- >>> implemented.isOrExtends(IKlass)
- True
- >>> list(implemented)
- [<InterfaceClass __builtin__.IKlass>]
-
- >>> implemented2 = factory2.getInterfaces()
- >>> list(implemented2)
- []
-
- >>> implemented3 = factory3.getInterfaces()
- >>> list(implemented3)
- [<InterfaceClass __builtin__.IFunction>]
-
-
-The Component Architecture Factory API
---------------------------------------
-
- >>> import zope.component
- >>> factory = Factory(Klass, 'Klass', 'Klassier')
- >>> gsm = zope.component.getGlobalSiteManager()
-
- >>> from zope.component.interfaces import IFactory
- >>> gsm.registerUtility(factory, IFactory, 'klass')
-
-Creating an Object
-~~~~~~~~~~~~~~~~~~
-
- >>> kl = zope.component.createObject('klass', 1, 2, foo=3, bar=4)
- >>> isinstance(kl, Klass)
- True
- >>> kl.args
- (1, 2)
- >>> kl.kw
- {'foo': 3, 'bar': 4}
-
-Accessing Provided Interfaces
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- >>> implemented = zope.component.getFactoryInterfaces('klass')
- >>> implemented.isOrExtends(IKlass)
- True
- >>> [iface for iface in implemented]
- [<InterfaceClass __builtin__.IKlass>]
-
-List of All Factories
-~~~~~~~~~~~~~~~~~~~~~
-
- >>> [(name, fac.__class__) for name, fac in
- ... zope.component.getFactoriesFor(IKlass)]
- [(u'klass', <class 'zope.component.factory.Factory'>)]
-
Modified: zope.component/trunk/src/zope/component/globalregistry.py
===================================================================
--- zope.component/trunk/src/zope/component/globalregistry.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/globalregistry.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,10 +13,12 @@
##############################################################################
"""Global components support
"""
-from zope.interface import implements
+from zope.interface import implementer
from zope.interface.adapter import AdapterRegistry
from zope.interface.registry import Components
+
from zope.component.interfaces import IComponentLookup
+from zope.component._compat import _BLANK
def GAR(components, registryName):
return getattr(components, registryName)
@@ -35,8 +37,8 @@
def __reduce__(self):
return GAR, (self.__parent__, self.__name__)
+ at implementer(IComponentLookup)
class BaseGlobalComponents(Components):
- implements(IComponentLookup)
def _init_registries(self):
self.adapters = GlobalAdapterRegistry(self, 'adapters')
@@ -50,7 +52,7 @@
try:
from zope.testing.cleanup import addCleanUp
-except ImportError:
+except ImportError: #pragma NO COVER
pass
else:
addCleanUp(lambda: base.__init__('base'))
@@ -64,10 +66,10 @@
# We eventually want to deprecate these in favor of using the global
# component registry directly.
-def provideUtility(component, provides=None, name=u''):
+def provideUtility(component, provides=None, name=_BLANK):
base.registerUtility(component, provides, name, event=False)
-def provideAdapter(factory, adapts=None, provides=None, name=''):
+def provideAdapter(factory, adapts=None, provides=None, name=_BLANK):
base.registerAdapter(factory, adapts, provides, name, event=False)
def provideSubscriptionAdapter(factory, adapts=None, provides=None):
@@ -75,12 +77,3 @@
def provideHandler(factory, adapts=None):
base.registerHandler(factory, adapts, event=False)
-
-import zope.component._api # see http://www.zope.org/Collectors/Zope3-dev/674
-# Ideally, we will switch to an explicit adapter hook registration. For now,
-# if you provide an adapter, we want to make sure that the adapter hook is
-# registered, and that registration depends on code in _api, which itself
-# depends on code in this module. So, for now, we do another of these nasty
-# circular import workarounds. See also standalonetests.py, as run by
-# tests.py in StandaloneTests, for a test that fails without this hack, and
-# succeeds with it.
Modified: zope.component/trunk/src/zope/component/hooks.py
===================================================================
--- zope.component/trunk/src/zope/component/hooks.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/hooks.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -17,17 +17,24 @@
import contextlib
import threading
-import zope.component
try:
- import zope.security.proxy
-except ImportError:
- SECURITY_SUPPORT = False
-else:
- SECURITY_SUPPORT = True
+ from zope.security.proxy import removeSecurityProxy
+except ImportError: #pragma NO COVER
+ def removeSecurityProxy(x):
+ return x
+from zope.component.globalregistry import getGlobalSiteManager
+from zope.component.interfaces import ComponentLookupError
+from zope.component.interfaces import IComponentLookup
+
class read_property(object):
+ """Descriptor for property-like computed attributes.
+
+ Unlike the standard 'property', this descriptor allows assigning a
+ value to the instance, shadowing the property getter function.
+ """
def __init__(self, func):
self.func = func
@@ -39,20 +46,19 @@
class SiteInfo(threading.local):
site = None
- sm = zope.component.getGlobalSiteManager()
+ sm = getGlobalSiteManager()
+ @read_property
def adapter_hook(self):
adapter_hook = self.sm.adapters.adapter_hook
self.adapter_hook = adapter_hook
return adapter_hook
- adapter_hook = read_property(adapter_hook)
-
siteinfo = SiteInfo()
def setSite(site=None):
if site is None:
- sm = zope.component.getGlobalSiteManager()
+ sm = getGlobalSiteManager()
else:
# We remove the security proxy because there's no way for
@@ -62,8 +68,7 @@
# once site managers do less. There's probably no good reason why
# they can't be proxied. Well, except maybe for performance.
- if SECURITY_SUPPORT:
- site = zope.security.proxy.removeSecurityProxy(site)
+ site = removeSecurityProxy(site)
# The getSiteManager method is defined by IPossibleSite.
sm = site.getSiteManager()
@@ -103,34 +108,35 @@
# We should really look look at this again though, especially
# once site managers do less. There's probably no good reason why
# they can't be proxied. Well, except maybe for performance.
- sm = zope.component.interfaces.IComponentLookup(
- context, zope.component.getGlobalSiteManager())
- if SECURITY_SUPPORT:
- sm = zope.security.proxy.removeSecurityProxy(sm)
+ sm = IComponentLookup(
+ context, getGlobalSiteManager())
+ sm = removeSecurityProxy(sm)
return sm
def adapter_hook(interface, object, name='', default=None):
try:
return siteinfo.adapter_hook(interface, object, name, default)
- except zope.component.interfaces.ComponentLookupError:
+ except ComponentLookupError:
return default
def setHooks():
- zope.component.adapter_hook.sethook(adapter_hook)
- zope.component.getSiteManager.sethook(getSiteManager)
+ from zope.component import _api
+ _api.adapter_hook.sethook(adapter_hook)
+ _api.getSiteManager.sethook(getSiteManager)
def resetHooks():
# Reset hookable functions to original implementation.
- zope.component.adapter_hook.reset()
- zope.component.getSiteManager.reset()
+ from zope.component import _api
+ _api.adapter_hook.reset()
+ _api.getSiteManager.reset()
# Clear the site thread global
clearSite = setSite
try:
from zope.testing.cleanup import addCleanUp
-except ImportError:
+except ImportError: #pragma NO COVER
pass
else:
addCleanUp(resetHooks)
Deleted: zope.component/trunk/src/zope/component/hooks.txt
===================================================================
--- zope.component/trunk/src/zope/component/hooks.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/hooks.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,97 +0,0 @@
-==============================
-The current component registry
-==============================
-
-There can be any number of component registries in an application. One of them
-is the global component registry, and there is also the concept of a currently
-used component registry. Component registries other than the global one are
-associated with objects called sites. The ``zope.component.hooks`` module
-provides an API to set and access the current site as well as manipulate the
-adapter hook associated with it.
-
-As long as we haven't set a site, none is being considered current:
-
->>> from zope.component.hooks import getSite
->>> print getSite()
-None
-
-We can also ask for the current component registry (aka site manager
-historically); it will return the global one if no current site is set:
-
->>> from zope.component.hooks import getSiteManager
->>> getSiteManager()
-<BaseGlobalComponents base>
-
-Let's set a site now. A site has to be an object that provides the
-``getSiteManager`` method, which is specified by
-``zope.component.interfaces.IPossibleSite``:
-
->>> from zope.interface.registry import Components
->>> class Site(object):
-... def __init__(self):
-... self.registry = Components('components')
-... def getSiteManager(self):
-... return self.registry
-
->>> from zope.component.hooks import setSite
->>> site1 = Site()
->>> setSite(site1)
-
-After this, the newly set site is considered the currently active one:
-
->>> getSite() is site1
-True
->>> getSiteManager() is site1.registry
-True
-
-If we set another site, that one will be considered current:
-
->>> site2 = Site()
->>> site2.registry is not site1.registry
-True
->>> setSite(site2)
-
->>> getSite() is site2
-True
->>> getSiteManager() is site2.registry
-True
-
-Finally we can unset the site and the global component registry is used again:
-
->>> setSite()
->>> print getSite()
-None
->>> getSiteManager()
-<BaseGlobalComponents base>
-
-
-Context manager
-===============
-
-There also is a context manager for setting the site, which is especially
-useful when writing tests:
-
->>> import zope.component.hooks
->>> dummy = with_statement # support for Python-2.5
->>> print getSite()
-None
->>> with zope.component.hooks.site(site2):
-... getSite() is site2
-True
->>> print getSite()
-None
-
-The site is properly restored even if the body of the with statement
-raises an exception:
-
->>> print getSite()
-None
->>> with zope.component.hooks.site(site2):
-... getSite() is site2
-... raise ValueError('An error in the body')
-Traceback (most recent call last):
- ...
-ValueError: An error in the body
->>> print getSite()
-None
-
Deleted: zope.component/trunk/src/zope/component/index.txt
===================================================================
--- zope.component/trunk/src/zope/component/index.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/index.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,22 +0,0 @@
-Welcome to zope.component's documentation!
-==========================================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- README
- socketexample
- event
- factory
- registry
- persistentregistry
- zcml
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
Modified: zope.component/trunk/src/zope/component/interface.py
===================================================================
--- zope.component/trunk/src/zope/component/interface.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/interface.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,78 +13,22 @@
##############################################################################
"""Interface utility functions
"""
-__docformat__ = 'restructuredtext'
-
-from types import ClassType
-
-import zope.component
-from zope.component.interfaces import ComponentLookupError
from zope.interface import alsoProvides
from zope.interface.interfaces import IInterface
-def provideInterface(id, interface, iface_type=None, info=''):
- """register Interface with global site manager as utility
+from zope.component.globalregistry import getGlobalSiteManager
+from zope.component.interfaces import ComponentLookupError
+from zope.component._api import queryUtility
+from zope.component._compat import CLASS_TYPES
- >>> gsm = zope.component.getGlobalSiteManager()
-
- >>> from zope.interface import Interface
- >>> from zope.interface.interfaces import IInterface
- >>> from zope.component.tests import ITestType
-
- >>> class I(Interface):
- ... pass
- >>> IInterface.providedBy(I)
- True
- >>> ITestType.providedBy(I)
- False
- >>> interfaces = gsm.getUtilitiesFor(ITestType)
- >>> list(interfaces)
- []
-
- # provide first interface type
- >>> provideInterface('', I, ITestType)
- >>> ITestType.providedBy(I)
- True
- >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
- >>> [name for (name, iface) in interfaces]
- [u'zope.component.interface.I']
- >>> [iface.__name__ for (name, iface) in interfaces]
- ['I']
-
- # provide second interface type
- >>> class IOtherType(IInterface):
- ... pass
- >>> provideInterface('', I, IOtherType)
-
- >>> ITestType.providedBy(I)
- True
- >>> IOtherType.providedBy(I)
- True
- >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
- >>> [name for (name, iface) in interfaces]
- [u'zope.component.interface.I']
- >>> interfaces = list(gsm.getUtilitiesFor(IOtherType))
- >>> [name for (name, iface) in interfaces]
- [u'zope.component.interface.I']
-
- >>> class I1(Interface):
- ... pass
- >>> provideInterface('', I1)
- >>> IInterface.providedBy(I1)
- True
- >>> ITestType.providedBy(I1)
- False
- >>> interfaces = list(gsm.getUtilitiesFor(ITestType))
- >>> [name for (name, iface) in interfaces]
- [u'zope.component.interface.I']
- >>> [iface.__name__ for (name, iface) in interfaces]
- ['I']
+def provideInterface(id, interface, iface_type=None, info=''):
+ """ Mark 'interface' as a named utilty providing 'iface_type'.
"""
if not id:
id = "%s.%s" % (interface.__module__, interface.__name__)
if not IInterface.providedBy(interface):
- if not isinstance(interface, (type, ClassType)):
+ if not isinstance(interface, CLASS_TYPES):
raise TypeError(id, "is not an interface or class")
return
@@ -95,33 +39,12 @@
else:
iface_type = IInterface
- gsm = zope.component.getGlobalSiteManager()
+ gsm = getGlobalSiteManager()
gsm.registerUtility(interface, iface_type, id, info)
def getInterface(context, id):
"""Return interface or raise ComponentLookupError
-
- >>> from zope.interface import Interface
- >>> from zope.component.tests import ITestType
-
- >>> class I4(Interface):
- ... pass
- >>> IInterface.providedBy(I4)
- True
- >>> ITestType.providedBy(I4)
- False
- >>> getInterface(None, 'zope.component.interface.I4')
- Traceback (most recent call last):
- ...
- ComponentLookupError: zope.component.interface.I4
- >>> provideInterface('', I4, ITestType)
- >>> ITestType.providedBy(I4)
- True
- >>> iface = queryInterface( """\
- """ 'zope.component.interface.I4')
- >>> iface.__name__
- 'I4'
"""
iface = queryInterface(id, None)
if iface is None:
@@ -130,51 +53,13 @@
def queryInterface(id, default=None):
- """return interface or ``None``
-
- >>> from zope.interface import Interface
- >>> from zope.interface.interfaces import IInterface
- >>> from zope.component.tests import ITestType
-
- >>> class I3(Interface):
- ... pass
- >>> IInterface.providedBy(I3)
- True
- >>> ITestType.providedBy(I3)
- False
- >>> queryInterface('zope.component.interface.I3')
-
- >>> provideInterface('', I3, ITestType)
- >>> ITestType.providedBy(I3)
- True
- >>> iface = queryInterface('zope.component.interface.I3')
- >>> iface.__name__
- 'I3'
+ """Return an interface or ``None``
"""
- return zope.component.queryUtility(IInterface, id, default)
+ return queryUtility(IInterface, id, default)
def searchInterface(context, search_string=None, base=None):
"""Interfaces search
-
- >>> from zope.interface import Interface
- >>> from zope.interface.interfaces import IInterface
- >>> from zope.component.tests import ITestType
-
- >>> class I5(Interface):
- ... pass
- >>> IInterface.providedBy(I5)
- True
- >>> ITestType.providedBy(I5)
- False
- >>> searchInterface(None, 'zope.component.interface.I5')
- []
- >>> provideInterface('', I5, ITestType)
- >>> ITestType.providedBy(I5)
- True
- >>> iface = searchInterface(None, 'zope.component.interface.I5')
- >>> iface[0].__name__
- 'I5'
"""
return [iface_util[1] for iface_util in
searchInterfaceUtilities(context, search_string, base)]
@@ -182,32 +67,13 @@
def searchInterfaceIds(context, search_string=None, base=None):
"""Interfaces search
-
- >>> from zope.interface import Interface
- >>> from zope.interface.interfaces import IInterface
- >>> from zope.component.tests import ITestType
-
- >>> class I5(Interface):
- ... pass
- >>> IInterface.providedBy(I5)
- True
- >>> ITestType.providedBy(I5)
- False
- >>> searchInterface(None, 'zope.component.interface.I5')
- []
- >>> provideInterface('', I5, ITestType)
- >>> ITestType.providedBy(I5)
- True
- >>> iface = searchInterfaceIds(None, 'zope.component.interface.I5')
- >>> iface
- [u'zope.component.interface.I5']
"""
return [iface_util[0] for iface_util in
searchInterfaceUtilities(context, search_string, base)]
def searchInterfaceUtilities(context, search_string=None, base=None):
- gsm = zope.component.getGlobalSiteManager()
+ gsm = getGlobalSiteManager()
iface_utilities = gsm.getUtilitiesFor(IInterface)
if search_string:
@@ -217,7 +83,7 @@
find(search_string) >= 0)]
if base:
res = [iface_util for iface_util in iface_utilities
- if iface_util[1].extends(base)]
+ if iface_util[1].isOrExtends(base)]
else:
res = [iface_util for iface_util in iface_utilities]
return res
@@ -245,6 +111,8 @@
def interfaceToName(context, interface):
if interface is None:
return 'None'
+ # XXX this search is pointless: we are always going to return the
+ # same value whether or not we find anything.
items = searchInterface(context, base=interface)
ids = [('%s.%s' %(iface.__module__, iface.__name__))
for iface in items
Modified: zope.component/trunk/src/zope/component/interfaces.py
===================================================================
--- zope.component/trunk/src/zope/component/interfaces.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/interfaces.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -38,6 +38,9 @@
from zope.interface.interfaces import IComponentRegistry
from zope.interface.interfaces import IComponents
+from zope.component._compat import _BLANK
+
+
class IComponentArchitecture(Interface):
"""The Component Architecture is defined by two key components: Adapters
and Utiltities. Both are managed by site managers. All other components
@@ -112,7 +115,7 @@
# Adapter API
def getAdapter(object,
- interface=Interface, name=u'',
+ interface=Interface, name=_BLANK,
context=None):
"""Get a named adapter to an interface for an object
@@ -167,7 +170,7 @@
named adapter methods with an empty string for a name.
"""
- def queryAdapter(object, interface=Interface, name=u'',
+ def queryAdapter(object, interface=Interface, name=_BLANK,
default=None, context=None):
"""Look for a named adapter to an interface for an object
@@ -204,7 +207,7 @@
"""
def queryMultiAdapter(objects,
- interface=Interface, name=u'',
+ interface=Interface, name=_BLANK,
default=None,
context=None):
"""Look for a multi-adapter to an interface for objects
@@ -316,7 +319,7 @@
activity.
"""
- def provideUtility(component, provides=None, name=u''):
+ def provideUtility(component, provides=None, name=_BLANK):
"""Register a utility globally
A utility is registered to provide an interface with a
@@ -332,7 +335,7 @@
"""
- def provideAdapter(factory, adapts=None, provides=None, name=u''):
+ def provideAdapter(factory, adapts=None, provides=None, name=_BLANK):
"""Register an adapter globally
An adapter is registered to provide an interface with a name
Deleted: zope.component/trunk/src/zope/component/nexttesting.py
===================================================================
--- zope.component/trunk/src/zope/component/nexttesting.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/nexttesting.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,104 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2009 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Helper functions for testing utilities that use get/queryNextUtility.
-"""
-import zope.interface
-from zope.component.interfaces import IComponentLookup, IComponents
-
-
-class SiteManagerStub(object):
- zope.interface.implements(IComponents)
-
- __bases__ = ()
-
- def __init__(self):
- self._utils = {}
-
- def setNext(self, next):
- self.__bases__ = (next, )
-
- def provideUtility(self, iface, util, name=''):
- self._utils[(iface, name)] = util
-
- def queryUtility(self, iface, name='', default=None):
- return self._utils.get((iface, name), default)
-
-
-def testingNextUtility(utility, nextutility, interface, name='',
- sitemanager=None, nextsitemanager=None):
- """Provide a next utility for testing.
-
- This function sets up two utilities, so the get/queryNextUtility functions
- will see the second one as the "next" to the first one.
-
- To test it, we need to create a utility interface and implementation:
-
- >>> from zope.interface import Interface, implements
- >>> class IAnyUtility(Interface):
- ... pass
-
- >>> class AnyUtility(object):
- ... implements(IAnyUtility)
- ... def __init__(self, id):
- ... self.id = id
-
- >>> any1 = AnyUtility(1)
- >>> any1next = AnyUtility(2)
-
- Now, we can make the "any1next" be next to "any1".
-
- >>> testingNextUtility(any1, any1next, IAnyUtility)
-
- >>> from zope.component import getNextUtility
- >>> getNextUtility(any1, IAnyUtility) is any1next
- True
-
- It will work for named utilities as well.
-
- >>> testingNextUtility(any1, any1next, IAnyUtility, 'any')
- >>> getNextUtility(any1, IAnyUtility, 'any') is any1next
- True
-
- We can also provide our custom component registries:
-
- >>> sm = SiteManagerStub()
- >>> nextsm = SiteManagerStub()
-
- >>> testingNextUtility(any1, any1next, IAnyUtility,
- ... sitemanager=sm, nextsitemanager=nextsm)
-
- >>> IComponentLookup(any1) is sm
- True
- >>> IComponentLookup(any1next) is nextsm
- True
- >>> getNextUtility(any1, IAnyUtility) is any1next
- True
-
- """
- if sitemanager is None:
- sitemanager = SiteManagerStub()
- if nextsitemanager is None:
- nextsitemanager = SiteManagerStub()
- sitemanager.setNext(nextsitemanager)
-
- sitemanager.provideUtility(interface, utility, name)
- utility.__conform__ = (
- lambda iface:
- iface.isOrExtends(IComponentLookup) and sitemanager or None
- )
- nextsitemanager.provideUtility(interface, nextutility, name)
- nextutility.__conform__ = (
- lambda iface:
- iface.isOrExtends(IComponentLookup) and nextsitemanager or None
- )
Modified: zope.component/trunk/src/zope/component/persistentregistry.py
===================================================================
--- zope.component/trunk/src/zope/component/persistentregistry.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/persistentregistry.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,16 +13,13 @@
##############################################################################
"""Persistent component managers
"""
-import persistent.mapping
-import persistent.list
-import zope.interface.adapter
-
+from persistent import Persistent
+from persistent.mapping import PersistentMapping
+from persistent.list import PersistentList
+from zope.interface.adapter import VerifyingAdapterRegistry
from zope.interface.registry import Components
-class PersistentAdapterRegistry(
- zope.interface.adapter.VerifyingAdapterRegistry,
- persistent.Persistent,
- ):
+class PersistentAdapterRegistry(VerifyingAdapterRegistry, Persistent):
def changed(self, originally_changed):
if originally_changed is self:
@@ -48,7 +45,7 @@
self.utilities = PersistentAdapterRegistry()
def _init_registrations(self):
- self._utility_registrations = persistent.mapping.PersistentMapping()
- self._adapter_registrations = persistent.mapping.PersistentMapping()
- self._subscription_registrations = persistent.list.PersistentList()
- self._handler_registrations = persistent.list.PersistentList()
+ self._utility_registrations = PersistentMapping()
+ self._adapter_registrations = PersistentMapping()
+ self._subscription_registrations = PersistentList()
+ self._handler_registrations = PersistentList()
Deleted: zope.component/trunk/src/zope/component/persistentregistry.txt
===================================================================
--- zope.component/trunk/src/zope/component/persistentregistry.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/persistentregistry.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,6 +0,0 @@
-Persistent Component Management
-===============================
-
-Persistent component management allows persistent management of
-components. From a usage point of view, there shouldn't be any new
-behavior beyond what's described in registry.txt.
Deleted: zope.component/trunk/src/zope/component/registry.txt
===================================================================
--- zope.component/trunk/src/zope/component/registry.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/registry.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,1117 +0,0 @@
-Component-Management objects
-============================
-
-Component-management objects provide a higher-level
-component-management API over the basic adapter-registration API
-provided by the zope.interface package. In particular, it provides:
-
-- utilities
-
-- support for computing adapters, rather than just looking up adapter
- factories.
-
-- management of registration comments
-
-The zope.component.registry.Components class provides an
-implementation of zope.component.interfaces.IComponents that provides
-these features.
-
- >>> from zope.component import registry
- >>> from zope.component import tests
- >>> components = registry.Components('comps')
-
-As components are registered, events are generated. Let's register
-an event subscriber, so we can see the events generated:
-
- >>> import zope.event
- >>> def logevent(event):
- ... print event
- >>> zope.event.subscribers.append(logevent)
-
-Utilities
----------
-
-You can register Utilities using registerUtility:
-
- >>> components.registerUtility(tests.U1(1))
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 1, None, u'')
-
-Here we didn't specify an interface or name. An unnamed utility was
-registered for interface I1, since that is only interface implemented
-by the U1 class:
-
- >>> components.getUtility(tests.I1)
- U1(1)
-
-You can also register a utility using a factory instead of a utility instance:
-
- >>> def factory():
- ... return tests.U1(1)
- >>> components.registerUtility(factory=factory)
- Unregistered event:
- UtilityRegistration(<Components comps>, I1, u'', 1, None, u'')
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 1, <function factory at <SOME ADDRESS>>, u'')
-
-
-If a component implements other than one interface or no interface,
-then an error will be raised:
-
- >>> components.registerUtility(tests.U12(2))
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The utility doesn't provide a single interface and
- no provided interface was specified.
-
- >>> components.registerUtility(tests.A)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The utility doesn't provide a single interface and
- no provided interface was specified.
-
-
-We can provide an interface if desired:
-
- >>> components.registerUtility(tests.U12(2), tests.I2)
- Registered event:
- UtilityRegistration(<Components comps>, I2, u'', 2, None, u'')
-
-and we can specify a name:
-
- >>> components.registerUtility(tests.U12(3), tests.I2, u'three')
- Registered event:
- UtilityRegistration(<Components comps>, I2, u'three', 3, None, u'')
-
- >>> components.getUtility(tests.I2)
- U12(2)
-
- >>> components.getUtility(tests.I2, 'three')
- U12(3)
-
-If you try to get a utility that doesn't exist, you'll get a component
-lookup error:
-
- >>> components.getUtility(tests.I3)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- (<InterfaceClass zope.component.tests.I3>, u'')
-
-Unless you use queryUtility:
-
- >>> components.queryUtility(tests.I3)
- >>> components.queryUtility(tests.I3, default=42)
- 42
-
-You can get information about registered utilities with the
-registeredUtilities method:
-
- >>> for registration in sorted(components.registeredUtilities()):
- ... print registration.provided, registration.name
- ... print registration.component, registration.info
- <InterfaceClass zope.component.tests.I1>
- U1(1)
- <InterfaceClass zope.component.tests.I2>
- U12(2)
- <InterfaceClass zope.component.tests.I2> three
- U12(3)
-
-Duplicate registrations replace existing ones:
-
- >>> components.registerUtility(tests.U1(4), info=u'use 4 now')
- Unregistered event:
- UtilityRegistration(<Components comps>, I1, u'', 1, <function factory at <SOME ADDRESS>>, u'')
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 4, None, u'use 4 now')
- >>> components.getUtility(tests.I1)
- U1(4)
-
- >>> for registration in sorted(components.registeredUtilities()):
- ... print registration.provided, registration.name
- ... print registration.component, registration.info
- <InterfaceClass zope.component.tests.I1>
- U1(4) use 4 now
- <InterfaceClass zope.component.tests.I2>
- U12(2)
- <InterfaceClass zope.component.tests.I2> three
- U12(3)
-
-As shown in the this example, you can provide an "info" argumemnt when
-registering utilities. This provides extra documentation about the
-registration itself that is shown when listing registrations.
-
-You can also unregister utilities:
-
- >>> components.unregisterUtility(provided=tests.I1)
- Unregistered event:
- UtilityRegistration(<Components comps>, I1, u'', 4, None, u'use 4 now')
- True
-
-A boolean is returned indicating whether anything changed:
-
- >>> components.queryUtility(tests.I1)
- >>> for registration in sorted(components.registeredUtilities()):
- ... print registration.provided, registration.name
- ... print registration.component, registration.info
- <InterfaceClass zope.component.tests.I2>
- U12(2)
- <InterfaceClass zope.component.tests.I2> three
- U12(3)
-
-When you unregister, you can specify a component. If the component
-doesn't match the one registered, then nothing happens:
-
- >>> u5 = tests.U1(5)
- >>> components.registerUtility(u5)
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
- >>> components.unregisterUtility(tests.U1(6))
- False
- >>> components.queryUtility(tests.I1)
- U1(5)
- >>> components.unregisterUtility(u5)
- Unregistered event:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
- True
- >>> components.queryUtility(tests.I1)
-
-You can get the name and utility for all of the utilities that provide
-an interface using getUtilitiesFor:
-
- >>> sorted(components.getUtilitiesFor(tests.I2))
- [(u'', U12(2)), (u'three', U12(3))]
-
-getAllUtilitiesRegisteredFor is similar to getUtilitiesFor except that
-it includes utilities that are overridden. For example, we'll
-register a utility that for an extending interface of I2:
-
- >>> util = tests.U('ext')
- >>> components.registerUtility(util, tests.I2e)
- Registered event:
- UtilityRegistration(<Components comps>, I2e, u'', ext, None, u'')
-
-We don't get the new utility for getUtilitiesFor:
-
- >>> sorted(components.getUtilitiesFor(tests.I2))
- [(u'', U12(2)), (u'three', U12(3))]
-
-but we do get it from getAllUtilitiesRegisteredFor:
-
- >>> sorted(map(str, components.getAllUtilitiesRegisteredFor(tests.I2)))
- ['U(ext)', 'U12(2)', 'U12(3)']
-
-Removing a utility also makes it disappear from getUtilitiesFor:
-
- >>> components.unregisterUtility(util, tests.I2e)
- Unregistered event:
- UtilityRegistration(<Components comps>, I2e, u'', ext, None, u'')
- True
- >>> list(components.getAllUtilitiesRegisteredFor(tests.I2e))
- []
-
-Adapters
---------
-
-You can register adapters with registerAdapter:
-
- >>> components.registerAdapter(tests.A12_1)
- Registered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
-
-Here, we didn't specify required interfaces, a provided interface, or
-a name. The required interfaces were determined from the factory
-s __component_adapts__ attribute and the provided interface was
-determined by introspecting what the factory implements.
-
- >>> components.getMultiAdapter((tests.U1(6), tests.U12(7)), tests.IA1)
- A12_1(U1(6), U12(7))
-
-If a factory implements more than one interface, an exception will be
-raised:
-
- >>> components.registerAdapter(tests.A1_12)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
-Unless the provided interface is specified:
-
- >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
- Registered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
-
-If a factory doesn't declare an implemented interface, an exception will be
-raised:
-
- >>> components.registerAdapter(tests.A12_)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
-Unless the provided interface is specified:
-
- >>> components.registerAdapter(tests.A12_, provided=tests.IA2)
- Registered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA2, u'', A12_, u'')
-
-The required interface needs to be specified in the registration if
-the factory doesn't have a __component_adapts__ attribute:
-
- >>> components.registerAdapter(tests.A_2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't have a __component_adapts__
- attribute and no required specifications were specified
-
-Unless the required specifications specified:
-
- >>> components.registerAdapter(tests.A_2, required=[tests.I3])
- Registered event:
- AdapterRegistration(<Components comps>, [I3], IA2, u'', A_2, u'')
-
-Classes can be specified in place of specifications, in which case the
-implementedBy specification for the class is used:
-
- >>> components.registerAdapter(tests.A_3, required=[tests.U],
- ... info="Really class specific")
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- AdapterRegistration(<Components comps>, [zope.component.tests.U], IA3, u'',
- A_3, 'Really class specific')
-
-We can see the adapters that have been registered using the
-registeredAdapters method:
-
- >>> for registration in sorted(components.registeredAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<InterfaceClass zope.component.tests.I1>,
- <InterfaceClass zope.component.tests.I2>)
- <InterfaceClass zope.component.tests.IA1>
- zope.component.tests.A12_1
- (<InterfaceClass zope.component.tests.I1>,
- <InterfaceClass zope.component.tests.I2>)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A12_
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_12
- (<InterfaceClass zope.component.tests.I3>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A_2
- (<implementedBy zope.component.tests.U>,)
- <InterfaceClass zope.component.tests.IA3>
- zope.component.tests.A_3 Really class specific
-
-As with utilities, we can provide registration information when
-registering adapters.
-
-If you try to fetch an adapter that isn't registered, you'll get a
-component-lookup error:
-
- >>> components.getMultiAdapter((tests.U(8), ), tests.IA1)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: ((U(8),),
- <InterfaceClass zope.component.tests.IA1>, u'')
-
-unless you use queryAdapter:
-
- >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1)
- >>> components.queryMultiAdapter((tests.U(8), ), tests.IA1, default=42)
- 42
-
-When looking up an adapter for a single object, you can use the
-slightly simpler getAdapter and queryAdapter calls:
-
- >>> components.getAdapter(tests.U1(9), tests.IA2)
- A1_12(U1(9))
-
- >>> components.queryAdapter(tests.U1(9), tests.IA2)
- A1_12(U1(9))
-
- >>> components.getAdapter(tests.U(8), tests.IA1)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: (U(8),
- <InterfaceClass zope.component.tests.IA1>, u'')
-
- >>> components.queryAdapter(tests.U(8), tests.IA2)
- >>> components.queryAdapter(tests.U(8), tests.IA2, default=42)
- 42
-
-You can unregister an adapter. If a factory is provided and if the
-rewuired and provided interfaces, can be infered, then they need not
-be provided:
-
- >>> components.unregisterAdapter(tests.A12_1)
- Unregistered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
- True
-
- >>> for registration in sorted(components.registeredAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<InterfaceClass zope.component.tests.I1>,
- <InterfaceClass zope.component.tests.I2>)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A12_
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_12
- (<InterfaceClass zope.component.tests.I3>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A_2
- (<implementedBy zope.component.tests.U>,)
- <InterfaceClass zope.component.tests.IA3>
- zope.component.tests.A_3 Really class specific
-
-A boolean is returned indicating whether a change was made.
-
-If a factory implements more than one interface, an exception will be
-raised:
-
- >>> components.unregisterAdapter(tests.A1_12)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
-Unless the provided interface is specified:
-
- >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
- Unregistered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
- True
-
-If a factory doesn't declare an implemented interface, an exception will be
-raised:
-
- >>> components.unregisterAdapter(tests.A12_)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
-Unless the provided interface is specified:
-
- >>> components.unregisterAdapter(tests.A12_, provided=tests.IA2)
- Unregistered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA2, u'', A12_, u'')
- True
-
-The required interface needs to be specified if the factory doesn't
-have a __component_adapts__ attribute:
-
- >>> components.unregisterAdapter(tests.A_2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't have a __component_adapts__
- attribute and no required specifications were specified
-
- >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
- Unregistered event:
- AdapterRegistration(<Components comps>, [I3], IA2, u'', A_2, u'')
- True
-
- >>> for registration in sorted(components.registeredAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<implementedBy zope.component.tests.U>,)
- <InterfaceClass zope.component.tests.IA3>
- zope.component.tests.A_3 Really class specific
-
-If a factory is unregistered that is not registered, False is
-returned:
-
-
- >>> components.unregisterAdapter(tests.A_2, required=[tests.I3])
- False
- >>> components.unregisterAdapter(tests.A12_1, required=[tests.U])
- False
-
-The factory can be omitted, to unregister *any* factory that matches
-specified required and provided interfaces:
-
- >>> components.unregisterAdapter(required=[tests.U], provided=tests.IA3)
- ... # doctest: +NORMALIZE_WHITESPACE
- Unregistered event:
- AdapterRegistration(<Components comps>, [zope.component.tests.U],
- IA3, u'', A_3, 'Really class specific')
- True
-
- >>> for registration in sorted(components.registeredAdapters()):
- ... print registration
-
-Adapters can be named:
-
- >>> components.registerAdapter(tests.A1_12, provided=tests.IA2,
- ... name=u'test')
- Registered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'test', A1_12, u'')
-
- >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2)
- >>> components.queryMultiAdapter((tests.U1(9), ), tests.IA2, name=u'test')
- A1_12(U1(9))
-
- >>> components.queryAdapter(tests.U1(9), tests.IA2)
- >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test')
- A1_12(U1(9))
- >>> components.getAdapter(tests.U1(9), tests.IA2, name=u'test')
- A1_12(U1(9))
-
-It is possible to look up all of the adapters that provide an
-interface:
-
- >>> components.registerAdapter(tests.A1_23, provided=tests.IA2,
- ... name=u'test 2')
- Registered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'test 2', A1_23, u'')
-
- >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
- Registered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
-
- >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ),
- ... tests.IA2)):
- ... print name, adapter
- A1_12(U1(9))
- test A1_12(U1(9))
- test 2 A1_23(U1(9))
-
-
-getAdapters is most commonly used as the basis of menu systems.
-
-If an adapter factory returns None, it is equivalent to there being no
-factory:
-
- >>> components.registerAdapter(tests.noop,
- ... required=[tests.IA1], provided=tests.IA2,
- ... name=u'test noop')
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- AdapterRegistration(<Components comps>, [IA1], IA2, u'test noop',
- noop, u'')
- >>> components.queryAdapter(tests.U1(9), tests.IA2, name=u'test noop')
-
- >>> components.registerAdapter(tests.A1_12, provided=tests.IA2)
- Registered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
-
- >>> for name, adapter in sorted(components.getAdapters((tests.U1(9), ),
- ... tests.IA2)):
- ... print name, adapter
- A1_12(U1(9))
- test A1_12(U1(9))
- test 2 A1_23(U1(9))
-
-
- >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2,
- ... name=u'test')
- Unregistered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'test', A1_12, u'')
- True
- >>> components.unregisterAdapter(tests.A1_12, provided=tests.IA2)
- Unregistered event:
- AdapterRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
- True
- >>> for registration in sorted(components.registeredAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2> test 2
- zope.component.tests.A1_23
- (<InterfaceClass zope.component.tests.IA1>,)
- <InterfaceClass zope.component.tests.IA2> test noop
- <function noop at 0xb79a1064>
-
-
-Subscribers
------------
-
-Subscribers provide a way to get multiple adapters of a given type.
-In this regard, subscribers are like named adapters, except that there
-isn't any concept of the most specific adapter for a given name.
-
-Subscribers are registered by calling registerSubscriptionAdapter:
-
- >>> components.registerSubscriptionAdapter(tests.A1_2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
-
- >>> components.registerSubscriptionAdapter(
- ... tests.A1_12, provided=tests.IA2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_12, u'')
-
- >>> components.registerSubscriptionAdapter(
- ... tests.A, [tests.I1], tests.IA2,
- ... info='a sample comment')
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'',
- A, 'a sample comment')
-
-The same rules, with regard to when required and provided interfaces
-have to be specified apply as with adapters:
-
- >>> components.registerSubscriptionAdapter(tests.A1_12)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
- >>> components.registerSubscriptionAdapter(tests.A)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single interface and
- no provided interface was specified.
-
- >>> components.registerSubscriptionAdapter(tests.A, required=[tests.IA1])
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single interface
- and no provided interface was specified.
-
-Note that we provided the info argument as a keyword argument above.
-That's because there is a name argument that's reserved for future
-use. We can give a name, as long as it is an empty string:
-
- >>> components.registerSubscriptionAdapter(
- ... tests.A, [tests.I1], tests.IA2, u'', 'a sample comment')
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'',
- A, 'a sample comment')
-
- >>> components.registerSubscriptionAdapter(
- ... tests.A, [tests.I1], tests.IA2, u'oops', 'a sample comment')
- Traceback (most recent call last):
- ...
- TypeError: Named subscribers are not yet supported
-
-Subscribers are looked up using the subscribers method:
-
- >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
- ... print s
- A1_2(U1(1))
- A1_12(U1(1))
- A(U1(1),)
- A(U1(1),)
-
-Note that, because we created multiple subscriptions for A, we got multiple
-subscriber instances.
-
-As with normal adapters, if a factory returns None, the result is skipped:
-
- >>> components.registerSubscriptionAdapter(
- ... tests.noop, [tests.I1], tests.IA2)
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', noop, u'')
-
- >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
- ... print s
- A1_2(U1(1))
- A1_12(U1(1))
- A(U1(1),)
- A(U1(1),)
-
-We can get registration information for subscriptions:
-
- >>> for registration in sorted(
- ... components.registeredSubscriptionAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A a sample comment
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A a sample comment
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_12
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_2
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- <function noop at 0xb796ff7c>
-
-We can also unregister subscriptions in much the same way we can for adapters:
-
- >>> components.unregisterSubscriptionAdapter(tests.A1_2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Unregistered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, '')
- True
-
- >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
- ... print s
- A1_12(U1(1))
- A(U1(1),)
- A(U1(1),)
-
- >>> for registration in sorted(
- ... components.registeredSubscriptionAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A a sample comment
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A a sample comment
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_12
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- <function noop at 0xb796ff7c>
-
- >>> components.unregisterSubscriptionAdapter(
- ... tests.A, [tests.I1], tests.IA2)
- Unregistered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A, '')
- True
-
- >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
- ... print s
- A1_12(U1(1))
-
- >>> for registration in sorted(
- ... components.registeredSubscriptionAdapters()):
- ... print registration.required
- ... print registration.provided, registration.name
- ... print registration.factory, registration.info
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- zope.component.tests.A1_12
- (<InterfaceClass zope.component.tests.I1>,)
- <InterfaceClass zope.component.tests.IA2>
- <function noop at 0xb796ff7c>
-
-Note here that both registrations for A were removed.
-
-If we omit the factory, we must specify the required and provided interfaces:
-
- >>> components.unregisterSubscriptionAdapter(required=[tests.I1])
- Traceback (most recent call last):
- ...
- TypeError: Must specify one of factory and provided
-
- >>> components.unregisterSubscriptionAdapter(provided=tests.IA2)
- Traceback (most recent call last):
- ...
- TypeError: Must specify one of factory and required
-
- >>> components.unregisterSubscriptionAdapter(
- ... required=[tests.I1], provided=tests.IA2)
- Unregistered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', None, '')
- True
-
- >>> for s in components.subscribers((tests.U1(1), ), tests.IA2):
- ... print s
-
- >>> for registration in sorted(
- ... components.registeredSubscriptionAdapters()):
- ... print registration.factory
-
-As when registering, an error is raised if the registration
-information can't be determined from the factory and isn't specified:
-
- >>> components.unregisterSubscriptionAdapter(tests.A1_12)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single
- interface and no provided interface was specified.
-
- >>> components.unregisterSubscriptionAdapter(tests.A)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single interface and
- no provided interface was specified.
-
- >>> components.unregisterSubscriptionAdapter(tests.A, required=[tests.IA1])
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't implement a single interface
- and no provided interface was specified.
-
-If you unregister something that's not registered, nothing will be
-changed and False will be returned:
-
-
- >>> components.unregisterSubscriptionAdapter(
- ... required=[tests.I1], provided=tests.IA2)
- False
-
-Handlers
---------
-
-Handlers are used when you want to perform some function in response
-to an event. Handlers aren't expected to return anything when called
-and are not registered to provide any interface.
-
- >>> from zope import component
- >>> @component.adapter(tests.I1)
- ... def handle1(x):
- ... print 'handle1', x
-
- >>> components.registerHandler(handle1, info="First handler")
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- HandlerRegistration(<Components comps>, [I1], u'',
- handle1, 'First handler')
- >>> components.handle(tests.U1(1))
- handle1 U1(1)
-
- >>> @component.adapter(tests.I1, tests.I2)
- ... def handle12(x, y):
- ... print 'handle12', x, y
-
- >>> components.registerHandler(handle12)
- Registered event:
- HandlerRegistration(<Components comps>, [I1, I2], u'', handle12, u'')
- >>> components.handle(tests.U1(1), tests.U12(2))
- handle12 U1(1) U12(2)
-
-If a handler doesn't document interfaces it handles, then
-the required interfaces must be specified:
-
- >>> def handle(*objects):
- ... print 'handle', objects
-
- >>> components.registerHandler(handle)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't have a __component_adapts__
- attribute and no required specifications were specified
-
- >>> components.registerHandler(handle, required=[tests.I1],
- ... info="a comment")
- Registered event:
- HandlerRegistration(<Components comps>, [I1], u'', handle, 'a comment')
-
-Handlers can also be registered for classes:
-
- >>> components.registerHandler(handle, required=[tests.U],
- ... info="handle a class")
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- HandlerRegistration(<Components comps>, [zope.component.tests.U], u'',
- handle, 'handle a class')
-
-
- >>> components.handle(tests.U1(1))
- handle (U1(1),)
- handle1 U1(1)
- handle (U1(1),)
-
-We can list the handler registrations:
-
- >>> for registration in components.registeredHandlers():
- ... print registration.required
- ... print registration.handler, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle1 at 0xb78f5bfc> First handler
- (<InterfaceClass zope.component.tests.I1>,
- <InterfaceClass zope.component.tests.I2>)
- <function handle12 at 0xb78f5c34>
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle at 0xb78f5ca4> a comment
- (<implementedBy zope.component.tests.U>,)
- <function handle at 0xb78f5ca4> handle a class
-
-and we can unregister handlers:
-
- >>> components.unregisterHandler(required=[tests.U])
- ... # doctest: +NORMALIZE_WHITESPACE
- Unregistered event:
- HandlerRegistration(<Components comps>, [zope.component.tests.U], u'',
- None, '')
- True
-
- >>> for registration in components.registeredHandlers():
- ... print registration.required
- ... print registration.handler, registration.info
- ... # doctest: +NORMALIZE_WHITESPACE
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle1 at 0xb78f5bfc> First handler
- (<InterfaceClass zope.component.tests.I1>,
- <InterfaceClass zope.component.tests.I2>)
- <function handle12 at 0xb78f5c34>
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle at 0xb78f5ca4> a comment
-
- >>> components.unregisterHandler(handle12)
- Unregistered event:
- HandlerRegistration(<Components comps>, [I1, I2], u'', handle12, '')
- True
-
- >>> for registration in components.registeredHandlers():
- ... print registration.required
- ... print registration.handler, registration.info
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle1 at 0xb78f5bfc> First handler
- (<InterfaceClass zope.component.tests.I1>,)
- <function handle at 0xb78f5ca4> a comment
-
- >>> components.unregisterHandler(handle12)
- False
-
- >>> components.unregisterHandler()
- Traceback (most recent call last):
- ...
- TypeError: Must specify one of factory and required
-
- >>> components.registerHandler(handle)
- ... # doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: The adapter factory doesn't have a __component_adapts__
- attribute and no required specifications were specified
-
-Extending
----------
-
-Component-management objects can extend other component-management
-objects.
-
- >>> c1 = registry.Components('1')
- >>> c1.__bases__
- ()
-
- >>> c2 = registry.Components('2', (c1, ))
- >>> c2.__bases__ == (c1, )
- True
-
- >>> c1.registerUtility(tests.U1(1))
- Registered event:
- UtilityRegistration(<Components 1>, I1, u'', 1, None, u'')
-
- >>> c1.queryUtility(tests.I1)
- U1(1)
- >>> c2.queryUtility(tests.I1)
- U1(1)
- >>> c1.registerUtility(tests.U1(2))
- Unregistered event:
- UtilityRegistration(<Components 1>, I1, u'', 1, None, u'')
- Registered event:
- UtilityRegistration(<Components 1>, I1, u'', 2, None, u'')
-
- >>> c2.queryUtility(tests.I1)
- U1(2)
-
-We can use multiple inheritence:
-
- >>> c3 = registry.Components('3', (c1, ))
- >>> c4 = registry.Components('4', (c2, c3))
- >>> c4.queryUtility(tests.I1)
- U1(2)
-
- >>> c1.registerUtility(tests.U12(1), tests.I2)
- Registered event:
- UtilityRegistration(<Components 1>, I2, u'', 1, None, u'')
-
- >>> c4.queryUtility(tests.I2)
- U12(1)
-
- >>> c3.registerUtility(tests.U12(3), tests.I2)
- Registered event:
- UtilityRegistration(<Components 3>, I2, u'', 3, None, u'')
- >>> c4.queryUtility(tests.I2)
- U12(3)
-
- >>> c1.registerHandler(handle1, info="First handler")
- Registered event:
- HandlerRegistration(<Components 1>, [I1], u'', handle1, 'First handler')
-
- >>> c2.registerHandler(handle, required=[tests.U])
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- HandlerRegistration(<Components 2>, [zope.component.tests.U], u'',
- handle, u'')
-
- >>> @component.adapter(tests.I1)
- ... def handle3(x):
- ... print 'handle3', x
- >>> c3.registerHandler(handle3)
- Registered event:
- HandlerRegistration(<Components 3>, [I1], u'', handle3, u'')
-
- >>> @component.adapter(tests.I1)
- ... def handle4(x):
- ... print 'handle4', x
- >>> c4.registerHandler(handle4)
- Registered event:
- HandlerRegistration(<Components 4>, [I1], u'', handle4, u'')
-
- >>> c4.handle(tests.U1(1))
- handle1 U1(1)
- handle3 U1(1)
- handle (U1(1),)
- handle4 U1(1)
-
-Redispatch of registration events
----------------------------------
-
-Some handlers are available that, if registered, redispatch
-registration events to the objects being registered. They depend on
-being dispatched to by the object-event dispatcher:
-
- >>> from zope import component
- >>> import zope.component.event
- >>> zope.component.getGlobalSiteManager().registerHandler(
- ... zope.component.event.objectEventNotify)
- ... # doctest: +NORMALIZE_WHITESPACE
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [IObjectEvent], u'', objectEventNotify, u'')
-
-To see this, we'll first register a multi-handler to show is when
-handlers are called on 2 objects:
-
- >>> @zope.component.adapter(None, None)
- ... def double_handler(o1, o2):
- ... print 'Double dispatch:'
- ... print ' ', o1
- ... print ' ', o2
- >>> zope.component.getGlobalSiteManager().registerHandler(double_handler)
- ... # doctest: +NORMALIZE_WHITESPACE
- Double dispatch:
- HandlerRegistration(<BaseGlobalComponents base>,
- [Interface, Interface], u'', double_handler, u'')
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [Interface, Interface], u'', double_handler, u'')
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [Interface, Interface], u'', double_handler, u'')
-
-In the example above, the double_handler reported it's own registration. :)
-
-Now we'll register our handlers:
-
- >>> zope.component.getGlobalSiteManager().registerHandler(
- ... registry.dispatchUtilityRegistrationEvent)
- ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
- Double dispatch:
- ...
-
- >>> zope.component.getGlobalSiteManager().registerHandler(
- ... registry.dispatchAdapterRegistrationEvent)
- ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
- Double dispatch:
- ...
-
- >>> zope.component.getGlobalSiteManager().registerHandler(
- ... registry.dispatchSubscriptionAdapterRegistrationEvent)
- ... # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
- Double dispatch:
- ...
-
- >>> zope.component.getGlobalSiteManager().registerHandler(
- ... registry.dispatchHandlerRegistrationEvent)
- ... # doctest: +NORMALIZE_WHITESPACE
- Double dispatch:
- HandlerRegistration(<BaseGlobalComponents base>,
- [IHandlerRegistration, IRegistrationEvent], u'',
- dispatchHandlerRegistrationEvent, u'')
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [IHandlerRegistration, IRegistrationEvent], u'',
- dispatchHandlerRegistrationEvent, u'')
- Double dispatch:
- <function dispatchHandlerRegistrationEvent at 0xb799f72c>
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [IHandlerRegistration, IRegistrationEvent], u'',
- dispatchHandlerRegistrationEvent, u'')
- Registered event:
- HandlerRegistration(<BaseGlobalComponents base>,
- [IHandlerRegistration, IRegistrationEvent], u'',
- dispatchHandlerRegistrationEvent, u'')
-
-In the last example above, we can see that the registration of
-dispatchHandlerRegistrationEvent was handled by
-dispatchHandlerRegistrationEvent and redispatched. This can be seen
-in the second double-dispatch output, where the first argument is the
-object being registered, which is dispatchHandlerRegistrationEvent.
-
-If we change some other registrations, we can the double dispatch
-taking place:
-
- >>> components.registerUtility(u5)
- ... # doctest: +NORMALIZE_WHITESPACE
- Double dispatch:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
- Double dispatch:
- U1(5)
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
- Registered event:
- UtilityRegistration(<Components comps>, I1, u'', 5, None, u'')
-
- >>> components.registerAdapter(tests.A12_1)
- ... # doctest: +NORMALIZE_WHITESPACE
- Double dispatch:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
- Registered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
- Double dispatch:
- zope.component.tests.A12_1
- Registered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
- Registered event:
- AdapterRegistration(<Components comps>, [I1, I2], IA1, u'', A12_1, u'')
-
- >>> components.registerSubscriptionAdapter(tests.A1_2)
- ... # doctest: +NORMALIZE_WHITESPACE
- Double dispatch:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
- Double dispatch:
- zope.component.tests.A1_2
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
- Registered event:
- SubscriptionRegistration(<Components comps>, [I1], IA2, u'', A1_2, u'')
Modified: zope.component/trunk/src/zope/component/security.py
===================================================================
--- zope.component/trunk/src/zope/component/security.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/security.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,13 +13,15 @@
##############################################################################
"""zope.security support for the configuration handlers
"""
-__docformat__ = "reStructuredText"
-
from zope.interface import providedBy
-from zope.proxy import ProxyBase, getProxiedObject
-from zope.security.adapter import LocatingTrustedAdapterFactory, \
- LocatingUntrustedAdapterFactory, TrustedAdapterFactory
-from zope.security.checker import Checker, CheckerPublic, InterfaceChecker
+from zope.proxy import ProxyBase
+from zope.proxy import getProxiedObject
+from zope.security.adapter import LocatingTrustedAdapterFactory
+from zope.security.adapter import LocatingUntrustedAdapterFactory
+from zope.security.adapter import TrustedAdapterFactory
+from zope.security.checker import Checker
+from zope.security.checker import CheckerPublic
+from zope.security.checker import InterfaceChecker
from zope.security.proxy import Proxy
@@ -60,7 +62,8 @@
if checker is None:
if provides is None or permission is None:
- raise ValueError, 'Required arguments: checker or both provides and permissions'
+ raise ValueError('Required arguments: '
+ 'checker or both provides and permissions')
if permission == PublicPermission:
permission = CheckerPublic
checker = InterfaceChecker(provides, permission)
@@ -84,82 +87,6 @@
return factory
def securityAdapterFactory(factory, permission, locate, trusted):
- """
- If a permission is provided when wrapping the adapter, it will be
- wrapped in a LocatingAdapterFactory.
-
- >>> class Factory:
- ... pass
-
- If both locate and trusted are False and a non-public
- permission is provided, then the factory is wrapped into a
- LocatingUntrustedAdapterFactory:
-
- >>> factory = securityAdapterFactory(Factory, 'zope.AnotherPermission',
- ... locate=False, trusted=False)
-
- >>> isinstance(factory, LocatingUntrustedAdapterFactory)
- True
-
- If a PublicPermission is provided, then the factory is not touched.
-
- >>> factory = securityAdapterFactory(Factory, PublicPermission,
- ... locate=False, trusted=False)
-
- >>> factory is Factory
- True
-
- Same for CheckerPublic:
-
- >>> factory = securityAdapterFactory(Factory, CheckerPublic,
- ... locate=False, trusted=False)
-
- >>> factory is Factory
- True
-
- If the permission is None, the factory isn't touched:
-
- >>> factory = securityAdapterFactory(Factory, None,
- ... locate=False, trusted=False)
-
- >>> factory is Factory
- True
-
- If the factory is trusted and a no permission is provided then the
- adapter is wrapped into a TrustedAdapterFactory:
-
- >>> factory = securityAdapterFactory(Factory, None,
- ... locate=False, trusted=True)
-
- >>> isinstance(factory, TrustedAdapterFactory)
- True
-
- Same for PublicPermission:
-
- >>> factory = securityAdapterFactory(Factory, PublicPermission,
- ... locate=False, trusted=True)
-
- >>> isinstance(factory, TrustedAdapterFactory)
- True
-
- Same for CheckerPublic:
-
- >>> factory = securityAdapterFactory(Factory, CheckerPublic,
- ... locate=False, trusted=True)
-
- >>> isinstance(factory, TrustedAdapterFactory)
- True
-
- If the factory is trusted and a locate is true, then the
- adapter is wrapped into a LocatingTrustedAdapterFactory:
-
- >>> factory = securityAdapterFactory(Factory, 'zope.AnotherPermission',
- ... locate=True, trusted=True)
-
- >>> isinstance(factory, LocatingTrustedAdapterFactory)
- True
-
- """
if permission == PublicPermission:
permission = CheckerPublic
if locate or (permission is not None and permission is not CheckerPublic):
Deleted: zope.component/trunk/src/zope/component/socketexample.txt
===================================================================
--- zope.component/trunk/src/zope/component/socketexample.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/socketexample.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,597 +0,0 @@
-The Zope 3 Component Architecture (Socket Example)
-==================================================
-
-The component architecture provides an application framework that provides its
-functionality through loosely-connected components. A *component* can be any
-Python object and has a particular purpose associated with it. Thus, in a
-component-based applications you have many small component in contrast to
-classical object-oriented development, where you have a few big objects.
-
-Components communicate via specific APIs, which are formally defined by
-interfaces, which are provided by the `zope.interface` package. *Interfaces*
-describe the methods and properties that a component is expected to
-provide. They are also used as a primary mean to provide developer-level
-documentation for the components. For more details about interfaces see
-`zope/interface/README.txt`.
-
-The two main types of components are *adapters* and *utilities*. They will be
-discussed in detail later in this document. Both component types are managed
-by the *site manager*, with which you can register and access these
-components. However, most of the site manager's functionality is hidden behind
-the component architecture's public API, which is documented in
-`IComponentArchitecture`.
-
-
-Adapters
---------
-
-Adapters are a well-established pattern. An *adapter* uses an object providing
-one interface to produce an object that provides another interface. Here an
-example: Imagine that you purchased an electric shaver in the US, and thus
-you require the US socket type. You are now traveling in Germany, where another
-socket style is used. You will need a device, an adapter, that converts from
-the German to the US socket style.
-
-The functionality of adapters is actually natively provided by the
-`zope.interface` package and is thus well documented there. The `human.txt`
-file provides a gentle introduction to adapters, whereby `adapter.txt` is
-aimed at providing a comprehensive insight into adapters, but is too abstract
-for many as an initial read. Thus, we will only explain adapters in the context
-of the component architecture's API.
-
-So let's say that we have a German socket
-
- >>> from zope.interface import Interface, implements
-
- >>> class IGermanSocket(Interface):
- ... pass
-
- >>> class Socket(object):
- ... def __repr__(self):
- ... return '<instance of %s>' %self.__class__.__name__
-
- >>> class GermanSocket(Socket):
- ... """German wall socket."""
- ... implements(IGermanSocket)
-
-and we want to convert it to an US socket
-
- >>> class IUSSocket(Interface):
- ... pass
-
-so that our shaver can be used in Germany. So we go to a German electronics
-store to look for an adapter that we can plug in the wall:
-
- >>> class GermanToUSSocketAdapter(Socket):
- ... implements(IUSSocket)
- ... __used_for__ = IGermanSocket
- ...
- ... def __init__(self, socket):
- ... self.context = socket
-
-Note that I could have called the passed in socket any way I like, but
-`context` is the standard name accepted.
-
-
-Single Adapters
-~~~~~~~~~~~~~~~
-
-Before we can use the adapter, we have to buy it and make it part of our
-inventory. In the component architecture we do this by registering the adapter
-with the framework, more specifically with the global site manager:
-
- >>> import zope.component
- >>> gsm = zope.component.getGlobalSiteManager()
- >>> gsm.registerAdapter(GermanToUSSocketAdapter, (IGermanSocket,), IUSSocket)
-
-`zope.component` is the component architecture API that is being
-presented by this file. You registered an adapter from `IGermanSocket`
-to `IUSSocket` having no name (thus the empty string).
-
-Anyways, you finally get back to your hotel room and shave, since you have not
-been able to shave in the plane. In the bathroom you discover a socket:
-
- >>> bathroomDE = GermanSocket()
- >>> IGermanSocket.providedBy(bathroomDE)
- True
-
-You now insert the adapter in the German socket
-
- >>> bathroomUS = zope.component.getAdapter(bathroomDE, IUSSocket, '')
-
-so that the socket now provides the US version:
-
- >>> IUSSocket.providedBy(bathroomUS)
- True
-
-Now you can insert your shaver and get on with your day.
-
-After a week you travel for a couple of days to the Prague and you notice that
-the Czech have yet another socket type:
-
- >>> class ICzechSocket(Interface):
- ... pass
-
- >>> class CzechSocket(Socket):
- ... implements(ICzechSocket)
-
- >>> czech = CzechSocket()
-
-You try to find an adapter for your shaver in your bag, but you fail, since
-you do not have one:
-
- >>> zope.component.getAdapter(czech, IUSSocket, '') \
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<instance of CzechSocket>,
- <InterfaceClass __builtin__.IUSSocket>,
- '')
-
-or the more graceful way:
-
- >>> marker = object()
- >>> socket = zope.component.queryAdapter(czech, IUSSocket, '', marker)
- >>> socket is marker
- True
-
-In the component architecture API any `get*` method will fail with a specific
-exception, if a query failed, whereby methods starting with `query*` will
-always return a `default` value after a failure.
-
-
-Named Adapters
-~~~~~~~~~~~~~~
-
-You are finally back in Germany. You also brought your DVD player and a couple
-DVDs with you, which you would like to watch. Your shaver was able to convert
-automatically from 110 volts to 240 volts, but your DVD player cannot. So you
-have to buy another adapter that also handles converting the voltage and the
-frequency of the AC current:
-
- >>> class GermanToUSSocketAdapterAndTransformer(object):
- ... implements(IUSSocket)
- ... __used_for__ = IGermanSocket
- ...
- ... def __init__(self, socket):
- ... self.context = socket
-
-Now, we need a way to keep the two adapters apart. Thus we register them with
-a name:
-
- >>> gsm.registerAdapter(GermanToUSSocketAdapter,
- ... (IGermanSocket,), IUSSocket, 'shaver',)
- >>> gsm.registerAdapter(GermanToUSSocketAdapterAndTransformer,
- ... (IGermanSocket,), IUSSocket, 'dvd')
-
-Now we simply look up the adapters using their labels (called *name*):
-
- >>> socket = zope.component.getAdapter(bathroomDE, IUSSocket, 'shaver')
- >>> socket.__class__ is GermanToUSSocketAdapter
- True
-
- >>> socket = zope.component.getAdapter(bathroomDE, IUSSocket, 'dvd')
- >>> socket.__class__ is GermanToUSSocketAdapterAndTransformer
- True
-
-Clearly, we do not have an adapter for the MP3 player
-
- >>> zope.component.getAdapter(bathroomDE, IUSSocket, 'mp3') \
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<instance of GermanSocket>,
- <InterfaceClass __builtin__.IUSSocket>,
- 'mp3')
-
-but you could use the 'dvd' adapter in this case of course. ;)
-
-Sometimes you want to know all adapters that are available. Let's say you want
-to know about all the adapters that convert a German to a US socket type:
-
- >>> sockets = list(zope.component.getAdapters((bathroomDE,), IUSSocket))
- >>> len(sockets)
- 3
- >>> names = [name for name, socket in sockets]
- >>> names.sort()
- >>> names
- [u'', u'dvd', u'shaver']
-
-`zope.component.getAdapters()` returns a list of tuples. The first
-entry of the tuple is the name of the adapter and the second is the
-adapter itself.
-
-
-Multi-Adapters
-~~~~~~~~~~~~~~
-
-After watching all the DVDs you brought at least twice, you get tired of them
-and you want to listen to some music using your MP3 player. But darn, the MP3
-player plug has a ground pin and all the adapters you have do not support
-that:
-
- >>> class IUSGroundedSocket(IUSSocket):
- ... pass
-
-So you go out another time to buy an adapter. This time, however, you do not
-buy yet another adapter, but a piece that provides the grounding plug:
-
- >>> class IGrounder(Interface):
- ... pass
-
- >>> class Grounder(object):
- ... implements(IGrounder)
- ... def __repr__(self):
- ... return '<instance of Grounder>'
-
-
-Then together they will provided a grounded us socket:
-
- >>> class GroundedGermanToUSSocketAdapter(object):
- ... implements(IUSGroundedSocket)
- ... __used_for__ = (IGermanSocket, IGrounder)
- ... def __init__(self, socket, grounder):
- ... self.socket, self.grounder = socket, grounder
-
-You now register the combination, so that you know you can create a
-`IUSGroundedSocket`:
-
- >>> gsm.registerAdapter(GroundedGermanToUSSocketAdapter,
- ... (IGermanSocket, IGrounder), IUSGroundedSocket, 'mp3')
-
-Given the grounder
-
- >>> grounder = Grounder()
-
-and a German socket
-
- >>> livingroom = GermanSocket()
-
-we can now get a grounded US socket:
-
- >>> socket = zope.component.getMultiAdapter((livingroom, grounder),
- ... IUSGroundedSocket, 'mp3')
-
- >>> socket.__class__ is GroundedGermanToUSSocketAdapter
- True
- >>> socket.socket is livingroom
- True
- >>> socket.grounder is grounder
- True
-
-Of course, you do not have a 'dvd' grounded US socket available:
-
- >>> zope.component.getMultiAdapter((livingroom, grounder),
- ... IUSGroundedSocket, 'dvd') \
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: ((<instance of GermanSocket>,
- <instance of Grounder>),
- <InterfaceClass __builtin__.IUSGroundedSocket>,
- 'dvd')
-
-
- >>> socket = zope.component.queryMultiAdapter(
- ... (livingroom, grounder), IUSGroundedSocket, 'dvd', marker)
- >>> socket is marker
- True
-
-Again, you might want to read `adapter.txt` in `zope.interface` for a more
-comprehensive coverage of multi-adapters.
-
-Subscribers
------------
-
-While subscribers are directly supported by the adapter registry and are
-adapters for all theoretical purposes, practically it might be better to think
-of them as separate components. Subscribers are particularly useful for
-events.
-
-Let's say one of our adapters overheated and caused a small fire:
-
- >>> class IFire(Interface):
- ... pass
-
- >>> class Fire(object):
- ... implements(IFire)
-
- >>> fire = Fire()
-
-We want to use all available objects to put out the fire:
-
- >>> class IFireExtinguisher(Interface):
- ... def extinguish():
- ... pass
-
- >>> class FireExtinguisher(object):
- ... def __init__(self, fire):
- ... pass
- ... def extinguish(self):
- ... "Place extinguish code here."
- ... print 'Used ' + self.__class__.__name__ + '.'
-
-Here some specific methods to put out the fire:
-
- >>> class PowderExtinguisher(FireExtinguisher):
- ... pass
- >>> gsm.registerSubscriptionAdapter(PowderExtinguisher,
- ... (IFire,), IFireExtinguisher)
-
- >>> class Blanket(FireExtinguisher):
- ... pass
- >>> gsm.registerSubscriptionAdapter(Blanket, (IFire,), IFireExtinguisher)
-
- >>> class SprinklerSystem(FireExtinguisher):
- ... pass
- >>> gsm.registerSubscriptionAdapter(SprinklerSystem,
- ... (IFire,), IFireExtinguisher)
-
-Now let use all these things to put out the fire:
-
- >>> extinguishers = zope.component.subscribers((fire,), IFireExtinguisher)
- >>> extinguishers.sort()
- >>> for extinguisher in extinguishers:
- ... extinguisher.extinguish()
- Used Blanket.
- Used PowderExtinguisher.
- Used SprinklerSystem.
-
-If no subscribers are found for a particular object, then an empty list is
-returned:
-
- >>> zope.component.subscribers((object(),), IFireExtinguisher)
- []
-
-
-Utilities
----------
-
-Utilities are the second type of component, the component architecture
-implements. *Utilities* are simply components that provide an interface. When
-you register an utility, you always register an instance (in contrast to a
-factory for adapters) since the initialization and setup process of a utility
-might be complex and is not well defined. In some ways a utility is much more
-fundamental than an adapter, because an adapter cannot be used without another
-component, but a utility is always self-contained. I like to think of
-utilities as the foundation of your application and adapters as components
-extending beyond this foundation.
-
-Back to our story...
-
-After your vacation is over you fly back home to Tampa, Florida. But it is
-August now, the middle of the Hurricane season. And, believe it or not, you are
-worried that you will not be able to shave when the power goes out for several
-days. (You just hate wet shavers.)
-
-So you decide to go to your favorite hardware store and by a Diesel-powered
-electric generator. The generator provides of course a US-style socket:
-
- >>> class Generator(object):
- ... implements(IUSSocket)
- ... def __repr__(self):
- ... return '<instance of Generator>'
-
- >>> generator = Generator()
-
-Like for adapters, we now have to add the newly-acquired generator to our
-inventory by registering it as a utility:
-
- >>> gsm.registerUtility(generator, IUSSocket)
-
-We can now get the utility using
-
- >>> utility = zope.component.getUtility(IUSSocket)
- >>> utility is generator
- True
-
-As you can see, it is very simple to register and retrieve utilities. If a
-utility does not exist for a particular interface, such as the German socket,
-then the lookup fails
-
- >>> zope.component.getUtility(IGermanSocket)
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<InterfaceClass __builtin__.IGermanSocket>, '')
-
-or more gracefully when specifying a default value:
-
- >>> default = object()
- >>> utility = zope.component.queryUtility(IGermanSocket, default=default)
- >>> utility is default
- True
-
-Note: The only difference between `getUtility()` and `queryUtility()` is the
-fact that you can specify a default value for the latter function, so that it
-will never cause a `ComponentLookupError`.
-
-
-Named Utilities
-~~~~~~~~~~~~~~~
-
-It is often desirable to have several utilities providing the same interface
-per site. This way you can implement any sort of registry using utilities. For
-this reason, utilities -- like adapters -- can be named.
-
-In the context of our story, we might want to do the following: You really do
-not trust gas stations either. What if the roads are blocked after a hurricane
-and the gas stations run out of oil. So you look for another renewable power
-source. Then you think about solar panels! After a storm there is usually very
-nice weather, so why not? Via the Web you order a set of 110V/120W solar
-panels that provide a regular US-style socket as output:
-
- >>> class SolarPanel(object):
- ... implements(IUSSocket)
- ... def __repr__(self):
- ... return '<instance of Solar Panel>'
-
- >>> panel = SolarPanel()
-
-Once it arrives, we add it to our inventory:
-
- >>> gsm.registerUtility(panel, IUSSocket, 'Solar Panel')
-
-You can now access the solar panel using
-
- >>> utility = zope.component.getUtility(IUSSocket, 'Solar Panel')
- >>> utility is panel
- True
-
-Of course, if a utility is not available, then the lookup will simply fail
-
- >>> zope.component.getUtility(IUSSocket, 'Wind Mill')
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<InterfaceClass __builtin__.IUSSocket>, 'Wind Mill')
-
-or more gracefully when specifying a default value:
-
- >>> default = object()
- >>> utility = zope.component.queryUtility(IUSSocket, 'Wind Mill',
- ... default=default)
- >>> utility is default
- True
-
-Now you want to look at all the utilities you have for a particular kind. The
-following API function will return a list of name/utility pairs:
-
- >>> utils = list(zope.component.getUtilitiesFor(IUSSocket))
- >>> utils.sort()
- >>> utils #doctest: +NORMALIZE_WHITESPACE
- [(u'', <instance of Generator>),
- (u'Solar Panel', <instance of Solar Panel>)]
-
-Another method of looking up all utilities is by using
-`getAllUtilitiesRegisteredFor(iface)`. This function will return an iterable
-of utilities (without names); however, it will also return overridden
-utilities. If you are not using multiple site managers, you will not actually
-need this method.
-
- >>> utils = list(zope.component.getAllUtilitiesRegisteredFor(IUSSocket))
- >>> utils.sort()
- >>> utils
- [<instance of Generator>, <instance of Solar Panel>]
-
-
-Factories
-~~~~~~~~~
-
-A *factory* is a special kind of utility that exists to create other
-components. A factory is always identified by a name. It also provides a title
-and description and is able to tell the developer what interfaces the created
-object will provide. The advantage of using a factory to create an object
-instead of directly instantiating a class or executing any other callable is
-that we can refer to the factory by name. As long as the name stays fixed, the
-implementation of the callable can be renamed or moved without a breakage in
-code.
-
-Let's say that our solar panel comes in parts and they have to be
-assembled. This assembly would be done by a factory, so let's create one for
-the solar panel. To do this, we can use a standard implementation of the
-`IFactory` interface:
-
- >>> from zope.component.factory import Factory
- >>> factory = Factory(SolarPanel,
- ... 'Solar Panel',
- ... 'This factory creates a solar panel.')
-
-Optionally, I could have also specified the interfaces that the created object
-will provide, but the factory class is smart enough to determine the
-implemented interface from the class. We now register the factory:
-
- >>> from zope.component.interfaces import IFactory
- >>> gsm.registerUtility(factory, IFactory, 'SolarPanel')
-
-We can now get a list of interfaces the produced object will provide:
-
- >>> ifaces = zope.component.getFactoryInterfaces('SolarPanel')
- >>> IUSSocket in ifaces
- True
-
-By the way, this is equivalent to
-
- >>> ifaces2 = factory.getInterfaces()
- >>> ifaces is ifaces2
- True
-
-Of course you can also just create an object:
-
- >>> panel = zope.component.createObject('SolarPanel')
- >>> panel.__class__ is SolarPanel
- True
-
-Note: Ignore the first argument (`None`) for now; it is the context of the
-utility lookup, which is usually an optional argument, but cannot be in this
-case, since all other arguments beside the `name` are passed in as arguments
-to the specified callable.
-
-Once you register several factories
-
- >>> gsm.registerUtility(Factory(Generator), IFactory, 'Generator')
-
-you can also determine, which available factories will create objects
-providing a certain interface:
-
- >>> factories = zope.component.getFactoriesFor(IUSSocket)
- >>> factories = [(name, factory.__class__) for name, factory in factories]
- >>> factories.sort()
- >>> factories #doctest: +NORMALIZE_WHITESPACE
- [(u'Generator', <class 'zope.component.factory.Factory'>),
- (u'SolarPanel', <class 'zope.component.factory.Factory'>)]
-
-
-Site Managers
--------------
-
-Why do we need site managers? Why is the component architecture API not
-sufficient? Some applications, including Zope 3, have a concept of
-locations. It is often desirable to have different configurations for these
-location; this can be done by overwriting existing or adding new component
-registrations. Site managers in locations below the root location, should be
-able to delegate requests to their parent locations. The root site manager is
-commonly known as *global site manager*, since it is always available. You can
-always get the global site manager using the API:
-
- >>> gsm = zope.component.getGlobalSiteManager()
-
- >>> from zope.component import globalSiteManager
- >>> gsm is globalSiteManager
- True
- >>> from zope.component.interfaces import IComponentLookup
- >>> IComponentLookup.providedBy(gsm)
- True
- >>> from zope.component.interfaces import IComponents
- >>> IComponents.providedBy(gsm)
- True
-
-You can also lookup at site manager in a given context. The only requirement
-is that the context can be adapted to a site manager. So let's create a
-special site manager:
-
- >>> from zope.component.globalregistry import BaseGlobalComponents
- >>> sm = BaseGlobalComponents()
-
-Now we create a context that adapts to the site manager via the `__conform__`
-method as specified in PEP 246.
-
- >>> class Context(object):
- ... def __init__(self, sm):
- ... self.sm = sm
- ... def __conform__(self, interface):
- ... if interface.isOrExtends(IComponentLookup):
- ... return self.sm
-
-We now instantiate the `Context` with our special site manager:
-
- >>> context = Context(sm)
- >>> context.sm is sm
- True
-
-We can now ask for the site manager of this context:
-
- >>> lsm = zope.component.getSiteManager(context)
- >>> lsm is sm
- True
-
-The site manager instance `lsm` is formally known as a *local site manager* of
-`context`.
Modified: zope.component/trunk/src/zope/component/standalonetests.py
===================================================================
--- zope.component/trunk/src/zope/component/standalonetests.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/standalonetests.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,54 +1,49 @@
"""
-Standalone Tests
+See: https://bugs.launchpad.net/zope3/+bug/98401
"""
-import unittest
-import doctest
import sys
import pickle
-if __name__ == "__main__":
- sys.path = pickle.loads(sys.stdin.read())
+def write(x):
+ sys.stdout.write('%s\n' % x)
-from zope import interface
-from zope.component.testing import setUp, tearDown
+if __name__ == "__main__": #pragma NO COVER (runs in subprocess)
+ #sys.path = pickle.loads(sys.stdin.read())
+ write('XXXXXXXXXX')
+ for p in sys.path:
+ write('- %s' % p)
+ write('XXXXXXXXXX')
-class I1(interface.Interface):
- pass
+ import zope
+ from zope.interface import Interface
+ from zope.interface import implementer
-class I2(interface.Interface):
- pass
+ class I1(Interface):
+ pass
-class Ob(object):
- interface.implements(I1)
- def __repr__(self):
- return '<instance Ob>'
+ class I2(Interface):
+ pass
-ob = Ob()
+ @implementer(I1)
+ class Ob(object):
+ def __repr__(self):
+ return '<instance Ob>'
-class Comp(object):
- interface.implements(I2)
- def __init__(self, context):
- self.context = context
+ ob = Ob()
-def providing_adapter_sets_adapter_hook():
- """
- A side effect of importing installs the adapter hook. See
- http://www.zope.org/Collectors/Zope3-dev/674.
+ @implementer(I2)
+ class Comp(object):
+ def __init__(self, context):
+ self.context = context
- >>> import zope.component
- >>> zope.component.provideAdapter(Comp, (I1,), I2)
- >>> adapter = I2(ob)
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is ob
- True
- """
+ write('YYYYYYYYY')
+ for p in zope.__path__:
+ write('- %s' % p)
+ write('YYYYYYYYY')
+ import zope.component
-
-def test_suite():
- return unittest.TestSuite((
- doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
- ))
-
-if __name__ == "__main__":
- unittest.main(defaultTest='test_suite')
+ zope.component.provideAdapter(Comp, (I1,), I2)
+ adapter = I2(ob)
+ write('ZZZZZZZZ')
+ assert adapter.__class__ is Comp
+ assert adapter.context is ob
Modified: zope.component/trunk/src/zope/component/testfiles/adapter.py
===================================================================
--- zope.component/trunk/src/zope/component/testfiles/adapter.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testfiles/adapter.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,22 +13,25 @@
##############################################################################
"""Sample adapter class for testing
"""
-import zope.interface
-import zope.component
-import components
-class I1(zope.interface.Interface):
+from zope.interface import Interface
+from zope.interface import implementer
+
+from zope.component import adapter
+from zope.component.testfiles import components
+
+class I1(Interface):
pass
-class I2(zope.interface.Interface):
+class I2(Interface):
pass
-class I3(zope.interface.Interface):
+class I3(Interface):
def f1(): pass
def f2(): pass
def f3(): pass
-class IS(zope.interface.Interface):
+class IS(Interface):
pass
@@ -36,23 +39,27 @@
def __init__(self, *args):
self.context = args
+ at implementer(I1)
class A1(Adapter):
- zope.interface.implements(I1)
+ pass
+ at implementer(I2)
class A2(Adapter):
- zope.interface.implements(I2)
+ pass
+ at adapter(components.IContent, I1, I2)
+ at implementer(I3)
class A3(Adapter):
- zope.component.adapts(components.IContent, I1, I2)
- zope.interface.implements(I3)
+ pass
class A4:
pass
a4 = A4()
+ at implementer(I1, I2)
class A5:
- zope.interface.implements(I1, I2)
+ pass
a5 = A5()
Modified: zope.component/trunk/src/zope/component/testfiles/components.py
===================================================================
--- zope.component/trunk/src/zope/component/testfiles/components.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testfiles/components.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,8 +13,10 @@
##############################################################################
"""Components for testing
"""
-from zope.interface import Interface, Attribute, implements
-from zope.component import adapts
+from zope.interface import Interface
+from zope.interface import Attribute
+from zope.interface import implementer
+from zope.component import adapter
class IAppb(Interface):
a = Attribute('test attribute')
@@ -31,12 +33,14 @@
class IContent(Interface): pass
+ at implementer(IContent)
class Content(object):
- implements(IContent)
+ pass
+ at adapter(IContent)
+ at implementer(IApp)
class Comp(object):
- adapts(IContent)
- implements(IApp)
+ pass
def __init__(self, *args):
# Ignore arguments passed to constructor
Modified: zope.component/trunk/src/zope/component/testfiles/views.py
===================================================================
--- zope.component/trunk/src/zope/component/testfiles/views.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testfiles/views.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,8 +13,11 @@
##############################################################################
"""Views test.
"""
-from zope.interface import Interface, implements, directlyProvides
+from zope.interface import Interface
+from zope.interface import implementer
+from zope.interface import directlyProvides
+
class Request(object):
def __init__(self, type):
@@ -29,8 +32,8 @@
class IC(Interface): pass
+ at implementer(IV)
class V1(object):
- implements(IV)
def __init__(self, context, request):
self.context = context
@@ -46,6 +49,7 @@
def index(self):
return 'ZMI here'
+ at implementer(IV)
class R1(object):
def index(self):
@@ -57,7 +61,6 @@
def __init__(self, request):
pass
- implements(IV)
class RZMI(R1):
pass
Modified: zope.component/trunk/src/zope/component/testing.py
===================================================================
--- zope.component/trunk/src/zope/component/testing.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testing.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -18,7 +18,17 @@
import zope.component.event
# we really don't need special setup now:
-from zope.testing.cleanup import CleanUp as PlacelessSetup
+try:
+ from zope.testing.cleanup import CleanUp as PlacelessSetup
+except ImportError:
+ class PlacelessSetup(object):
+ def cleanUp(self):
+ from zope.component.globalregistry import base
+ base.__init__('base')
+ def setUp(self):
+ self.cleanUp()
+ def tearDown(self):
+ self.cleanUp()
def setUp(test=None):
PlacelessSetup().setUp()
Modified: zope.component/trunk/src/zope/component/testlayer.py
===================================================================
--- zope.component/trunk/src/zope/component/testlayer.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testlayer.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -15,7 +15,12 @@
import os
from zope.configuration import xmlconfig, config
-from zope.testing.cleanup import cleanUp
+try:
+ from zope.testing.cleanup import cleanUp
+except ImportError:
+ def cleanUp():
+ pass
+
from zope.component import provideHandler
from zope.component.hooks import setHooks
from zope.component.eventtesting import events, clearEvents
Deleted: zope.component/trunk/src/zope/component/testlayer.txt
===================================================================
--- zope.component/trunk/src/zope/component/testlayer.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/testlayer.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,100 +0,0 @@
-Layers
-======
-
-zope.component.testlayer defines two things:
-
-* a LayerBase that makes it easier and saner to use zope.testing's
- test layers.
-
-* a ZCMLLayer which lets you implement a layer that loads up some
- ZCML.
-
-LayerBase
----------
-
-We check whether our LayerBase can be used to create layers of our
-own. We do this simply by subclassing:
-
- >>> from zope.component.testlayer import LayerBase
- >>> class OurLayer(LayerBase):
- ... def setUp(self):
- ... super(OurLayer, self).setUp()
- ... print "setUp called"
- ... def tearDown(self):
- ... super(OurLayer, self).tearDown()
- ... print "tearDown called"
- ... def testSetUp(self):
- ... super(OurLayer, self).testSetUp()
- ... print "testSetUp called"
- ... def testTearDown(self):
- ... super(OurLayer, self).testTearDown()
- ... print "testTearDown called"
-
-Note that if we wanted to ensure that the methods of the superclass
-were called we have to use super(). In this case we actually wouldn't
-need to, as these methods do nothing at all, but we just ensure that
-they are there in the first place.
-
-Let's instantiate our layer. We need to supply it with the package the
-layer is defined in::
-
- >>> import zope.component
- >>> layer = OurLayer(zope.component)
-
-Now we run some tests with this layer:
-
- >>> import unittest
- >>> class TestCase(unittest.TestCase):
- ... layer = layer
- ...
- ... def testFoo(self):
- ... print "testFoo"
- >>> suite = unittest.TestSuite()
- >>> suite.addTest(unittest.makeSuite(TestCase))
- >>> from zope.testrunner.runner import Runner
- >>> runner = Runner(args=[], found_suites=[suite])
- >>> succeeded = runner.run()
- Running zope.component.OurLayer tests:
- Set up zope.component.OurLayer setUp called
- in ... seconds.
- testSetUp called
- testFoo
- testTearDown called
- Ran 1 tests with 0 failures and 0 errors in ... seconds.
- Tearing down left over layers:
- Tear down zope.component.OurLayer tearDown called
- in ... seconds.
-
-ZCMLLayer
----------
-
-We now want a layer that loads up some ZCML from a file. The default
-is ``ftesting.zcml``, but here we'll load a test ``testlayer.zcml``.
-
- >>> from zope.component.testlayer import ZCMLFileLayer
- >>> zcml_file_layer = ZCMLFileLayer(
- ... zope.component.testfiles,
- ... 'testlayer.zcml')
-
- >>> class TestCase(unittest.TestCase):
- ... layer = zcml_file_layer
- ...
- ... def testFoo(self):
- ... # we should now have the adapter registered
- ... from zope import component
- ... from zope.component.testfiles import components
- ... self.assert_(isinstance(
- ... components.IApp2(components.content), components.Comp2))
-
-Since the ZCML sets up an adapter, we expect the tests to pass::
-
- >>> suite = unittest.TestSuite()
- >>> suite.addTest(unittest.makeSuite(TestCase))
- >>> runner = Runner(args=[], found_suites=[suite])
- >>> succeeded = runner.run()
- Running zope.component.testfiles.ZCMLFileLayer tests:
- Set up zope.component.testfiles.ZCMLFileLayer in ... seconds.
- Ran 1 tests with 0 failures and 0 errors in ... seconds.
- Tearing down left over layers:
- Tear down zope.component.testfiles.ZCMLFileLayer in ... seconds.
-
Deleted: zope.component/trunk/src/zope/component/tests.py
===================================================================
--- zope.component/trunk/src/zope/component/tests.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/tests.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,1748 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2001, 2002, 2009 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Component Architecture Tests
-"""
-
-import __future__
-
-import doctest
-import persistent
-import re
-import sys
-import unittest
-import transaction
-from cStringIO import StringIO
-
-from zope import interface, component
-from zope.interface.verify import verifyObject
-from zope.interface.interfaces import IInterface
-from zope.testing import renormalizing
-from zope.testrunner.layer import UnitTests
-
-from zope.component.interfaces import ComponentLookupError
-from zope.component.interfaces import IComponentArchitecture
-from zope.component.interfaces import IComponentLookup
-from zope.component.testing import setUp, tearDown, PlacelessSetup
-import zope.component.persistentregistry
-import zope.component.globalregistry
-
-from zope.configuration.xmlconfig import XMLConfig, xmlconfig
-from zope.configuration.exceptions import ConfigurationError
-from zope.security.checker import ProxyFactory
-
-from zope.component.testfiles.adapter import A1, A2, A3
-from zope.component.testfiles.components import IContent, Content
-from zope.component.testfiles.components import IApp
-from zope.component.testfiles.views import Request, IC, IV, V1, R1, IR
-
-# side effect gets component-based event dispatcher installed.
-# we should obviously make this more explicit
-import zope.component.event
-
-class I1(interface.Interface):
- pass
-class I2(interface.Interface):
- pass
-class I2e(I2):
- pass
-class I3(interface.Interface):
- pass
-
-class ITestType(IInterface):
- pass
-
-class U:
-
- def __init__(self, name):
- self.__name__ = name
-
- def __repr__(self):
- return "%s(%s)" % (self.__class__.__name__, self.__name__)
-
-class U1(U):
- interface.implements(I1)
-
-class U12(U):
- interface.implements(I1, I2)
-
-class IA1(interface.Interface):
- pass
-
-class IA2(interface.Interface):
- pass
-
-class IA3(interface.Interface):
- pass
-
-class A:
-
- def __init__(self, *context):
- self.context = context
-
- def __repr__(self):
- return "%s%r" % (self.__class__.__name__, self.context)
-
-class A12_1(A):
- component.adapts(I1, I2)
- interface.implements(IA1)
-
-class A12_(A):
- component.adapts(I1, I2)
-
-class A_2(A):
- interface.implements(IA2)
-
-class A_3(A):
- interface.implements(IA3)
-
-class A1_12(U):
- component.adapts(I1)
- interface.implements(IA1, IA2)
-
-class A1_2(U):
- component.adapts(I1)
- interface.implements(IA2)
-
-class A1_23(U):
- component.adapts(I1)
- interface.implements(IA1, IA3)
-
-def noop(*args):
- pass
-
- at component.adapter(I1)
-def handle1(x):
- print 'handle1', x
-
-def handle(*objects):
- print 'handle', objects
-
- at component.adapter(I1)
-def handle3(x):
- print 'handle3', x
-
- at component.adapter(I1)
-def handle4(x):
- print 'handle4', x
-
-class Ob(object):
- interface.implements(I1)
- def __repr__(self):
- return '<instance Ob>'
-
-
-ob = Ob()
-
-class Ob2(object):
- interface.implements(I2)
- def __repr__(self):
- return '<instance Ob2>'
-
-class Comp(object):
- interface.implements(I2)
- def __init__(self, context):
- self.context = context
-
-comp = Comp(1)
-
-class Comp2(object):
- interface.implements(I3)
- def __init__(self, context):
- self.context = context
-
-
-class ConformsToIComponentLookup(object):
- """This object allows the sitemanager to conform/adapt to
- `IComponentLookup` and thus to itself."""
-
- def __init__(self, sitemanager):
- self.sitemanager = sitemanager
-
- def __conform__(self, interface):
- """This method is specified by the adapter PEP to do the adaptation."""
- if interface is IComponentLookup:
- return self.sitemanager
-
-
-def testInterfaces():
- """Ensure that the component architecture API is provided by
- `zope.component`.
-
- >>> verifyObject(IComponentArchitecture, component)
- True
- """
-
-def test_getGlobalSiteManager():
- """One of the most important functions is to get the global site manager.
-
- >>> from zope.component.interfaces import IComponentLookup
- >>> from zope.component.globalregistry import base
-
- Get the global site manager via the CA API function:
-
- >>> gsm = component.getGlobalSiteManager()
-
- Make sure that the global site manager implements the correct interface
- and is the global site manager instance we expect to get.
-
- >>> IComponentLookup.providedBy(gsm)
- True
- >>> base is gsm
- True
-
- Finally, ensure that we always get the same global site manager, otherwise
- our component registry will always be reset.
-
- >>> component.getGlobalSiteManager() is gsm
- True
- """
-
-def test_getSiteManager():
- """Make sure that `getSiteManager()` always returns the correct site
- manager instance.
-
- We don't know anything about the default service manager, except that it
- is an `IComponentLookup`.
-
- >>> from zope.component.interfaces import IComponentLookup
- >>> IComponentLookup.providedBy(component.getSiteManager())
- True
-
- Calling `getSiteManager()` with no args is equivalent to calling it with a
- context of `None`.
-
- >>> component.getSiteManager() is component.getSiteManager(None)
- True
-
- If the context passed to `getSiteManager()` is not `None`, it is
- adapted to `IComponentLookup` and this adapter returned. So, we
- create a context that can be adapted to `IComponentLookup` using
- the `__conform__` API.
-
- Let's create the simplest stub-implementation of a site manager possible:
-
- >>> sitemanager = object()
-
- Now create a context that knows how to adapt to our newly created site
- manager.
-
- >>> context = ConformsToIComponentLookup(sitemanager)
-
- Now make sure that the `getSiteManager()` API call returns the correct
- site manager.
-
- >>> component.getSiteManager(context) is sitemanager
- True
-
- Using a context that is not adaptable to `IComponentLookup` should fail.
-
- >>> component.getSiteManager(ob) #doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
- Traceback (most recent call last):
- ...
- ComponentLookupError: ('Could not adapt', <instance Ob>,
- <InterfaceClass zope...interfaces.IComponentLookup>)
- """
-
-def testAdapterInContext(self):
- """The `getAdapterInContext()` and `queryAdapterInContext()` API functions
- do not only use the site manager to look up the adapter, but first tries
- to use the `__conform__()` method of the object to find an adapter as
- specified by PEP 246.
-
- Let's start by creating a component that support's the PEP 246's
- `__conform__()` method:
-
- >>> class Component(object):
- ... interface.implements(I1)
- ... def __conform__(self, iface, default=None):
- ... if iface == I2:
- ... return 42
- ... def __repr__(self):
- ... return '''<Component implementing 'I1'>'''
-
- >>> ob = Component()
-
- We also gave the component a custom representation, so it will be easier
- to use in these tests.
-
- We now have to create a site manager (other than the default global one)
- with which we can register adapters for `I1`.
-
- >>> from zope.component.globalregistry import BaseGlobalComponents
- >>> sitemanager = BaseGlobalComponents()
-
- Now we create a new `context` that knows how to get to our custom site
- manager.
-
- >>> context = ConformsToIComponentLookup(sitemanager)
-
- We now register an adapter from `I1` to `I3`:
-
- >>> sitemanager.registerAdapter(lambda x: 43, (I1,), I3, '')
-
- If an object implements the interface you want to adapt to,
- `getAdapterInContext()` should simply return the object.
-
- >>> component.getAdapterInContext(ob, I1, context)
- <Component implementing 'I1'>
- >>> component.queryAdapterInContext(ob, I1, context)
- <Component implementing 'I1'>
-
- If an object conforms to the interface you want to adapt to,
- `getAdapterInContext()` should simply return the conformed object.
-
- >>> component.getAdapterInContext(ob, I2, context)
- 42
- >>> component.queryAdapterInContext(ob, I2, context)
- 42
-
- If an adapter isn't registered for the given object and interface, and you
- provide no default, raise ComponentLookupError...
-
- >>> class I4(interface.Interface):
- ... pass
-
- >>> component.getAdapterInContext(ob, I4, context) \\
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<Component implementing 'I1'>,
- <InterfaceClass zope.component.tests.I4>)
-
- ...otherwise, you get the default:
-
- >>> component.queryAdapterInContext(ob, I4, context, 44)
- 44
-
- If you ask for an adapter for which something's registered you get the
- registered adapter
-
- >>> component.getAdapterInContext(ob, I3, context)
- 43
- >>> component.queryAdapterInContext(ob, I3, context)
- 43
- """
-
-def testAdapter():
- """The `getAdapter()` and `queryAdapter()` API functions are similar to
- `{get|query}AdapterInContext()` functions, except that they do not care
- about the `__conform__()` but also handle named adapters. (Actually, the
- name is a required argument.)
-
- If an adapter isn't registered for the given object and interface, and you
- provide no default, raise `ComponentLookupError`...
-
- >>> component.getAdapter(ob, I2, '') #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: (<instance Ob>,
- <InterfaceClass zope.component.tests.I2>,
- '')
-
- ...otherwise, you get the default
-
- >>> component.queryAdapter(ob, I2, '', '<default>')
- '<default>'
-
- Now get the global site manager and register an adapter from `I1` to `I2`
- without a name:
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, (I1,), I2, '')
-
- You should get a sensible error message if you forget that the 'requires'
- argument is supposed to be a sequence
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, I1, I2, '')
- Traceback (most recent call last):
- ...
- TypeError: the required argument should be a list of interfaces, not a single interface
-
- You can now simply access the adapter using the `getAdapter()` API
- function:
-
- >>> adapter = component.getAdapter(ob, I2, '')
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is ob
- True
- """
-
-def testInterfaceCall():
- """Here we test the `adapter_hook()` function that we registered with the
- `zope.interface` adapter hook registry, so that we can call interfaces to
- do adaptation.
-
- First, we need to register an adapter:
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, [I1], I2, '')
-
- Then we try to adapt `ob` to provide an `I2` interface by calling the `I2`
- interface with the obejct as first argument:
-
- >>> adapter = I2(ob)
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is ob
- True
-
- If no adapter is found, a `TypeError is raised...
-
- >>> I1(Ob2()) #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: ('Could not adapt', <instance Ob2>,
- <InterfaceClass zope.component.tests.I1>)
-
- ...unless we specify an alternative adapter:
-
- >>> marker = object()
- >>> I2(object(), marker) is marker
- True
- """
-
-def testNamedAdapter():
- """Make sure that adapters with names are correctly selected from the
- registry.
-
- First we register some named adapter:
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... lambda x: 0, [I1], I2, 'foo')
-
- If an adapter isn't registered for the given object and interface,
- and you provide no default, raise `ComponentLookupError`...
-
- >>> component.getAdapter(ob, I2, 'bar') \\
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- (<instance Ob>, <InterfaceClass zope.component.tests.I2>, 'bar')
-
- ...otherwise, you get the default
-
- >>> component.queryAdapter(ob, I2, 'bar', '<default>')
- '<default>'
-
- But now we register an adapter for the object having the correct name
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, [I1], I2, 'bar')
-
- so that the lookup succeeds:
-
- >>> adapter = component.getAdapter(ob, I2, 'bar')
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is ob
- True
- """
-
-def testMultiAdapter():
- """Adapting a combination of 2 objects to an interface
-
- Multi-adapters adapt one or more objects to another interface. To make
- this demonstration non-trivial, we need to create a second object to be
- adapted:
-
- >>> ob2 = Ob2()
-
- Like for regular adapters, if an adapter isn't registered for the given
- objects and interface, and you provide no default, raise
- `ComponentLookupError`...
-
- >>> component.getMultiAdapter((ob, ob2), I3) \\
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- ((<instance Ob>, <instance Ob2>),
- <InterfaceClass zope.component.tests.I3>,
- u'')
-
- ...otherwise, you get the default
-
- >>> component.queryMultiAdapter((ob, ob2), I3, default='<default>')
- '<default>'
-
- Note that the name is not a required attribute here.
-
- To test multi-adapters, we also have to create an adapter class that
- handles to context objects:
-
- >>> class DoubleAdapter(object):
- ... interface.implements(I3)
- ... def __init__(self, first, second):
- ... self.first = first
- ... self.second = second
-
- Now we can register the multi-adapter using
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... DoubleAdapter, (I1, I2), I3, '')
-
- Notice how the required interfaces are simply provided by a tuple. Now we
- can get the adapter:
-
- >>> adapter = component.getMultiAdapter((ob, ob2), I3)
- >>> adapter.__class__ is DoubleAdapter
- True
- >>> adapter.first is ob
- True
- >>> adapter.second is ob2
- True
- """
-
-def testAdapterForInterfaceNone():
- """Providing an adapter for None says that your adapter can adapt anything
- to `I2`.
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, (None,), I2, '')
-
- >>> adapter = I2(ob)
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is ob
- True
-
- It can really adapt any arbitrary object:
-
- >>> something = object()
- >>> adapter = I2(something)
- >>> adapter.__class__ is Comp
- True
- >>> adapter.context is something
- True
- """
-
-def testGetAdapters():
- """It is sometimes desireable to get a list of all adapters that are
- registered for a particular output interface, given a set of
- objects.
-
- Let's register some adapters first:
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, [I1], I2, '')
- >>> component.getGlobalSiteManager().registerAdapter(
- ... Comp, [None], I2, 'foo')
-
- Now we get all the adapters that are registered for `ob` that provide
- `I2`:
-
- >>> adapters = sorted(component.getAdapters((ob,), I2))
- >>> [(name, adapter.__class__.__name__) for name, adapter in adapters]
- [(u'', 'Comp'), (u'foo', 'Comp')]
-
- Note that the output doesn't include None values. If an adapter
- factory returns None, it is as if it wasn't present.
-
- >>> component.getGlobalSiteManager().registerAdapter(
- ... lambda context: None, [I1], I2, 'nah')
- >>> adapters = sorted(component.getAdapters((ob,), I2))
- >>> [(name, adapter.__class__.__name__) for name, adapter in adapters]
- [(u'', 'Comp'), (u'foo', 'Comp')]
-
- """
-
-def testUtility():
- """Utilities are components that simply provide an interface. They are
- instantiated at the time or before they are registered. Here we test the
- simple query interface.
-
- Before we register any utility, there is no utility available, of
- course. The pure instatiation of an object does not make it a utility. If
- you do not specify a default, you get a `ComponentLookupError`...
-
- >>> component.getUtility(I1) #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError: \
- (<InterfaceClass zope.component.tests.I1>, '')
-
- ...otherwise, you get the default
-
- >>> component.queryUtility(I1, default='<default>')
- '<default>'
- >>> component.queryUtility(I2, default='<default>')
- '<default>'
-
- Now we declare `ob` to be the utility providing `I1`
-
- >>> component.getGlobalSiteManager().registerUtility(ob, I1)
-
- so that the component is now available:
-
- >>> component.getUtility(I1) is ob
- True
- """
-
-def testNamedUtility():
- """Like adapters, utilities can be named.
-
- Just because you register an utility having no name
-
- >>> component.getGlobalSiteManager().registerUtility(ob, I1)
-
- does not mean that they are available when you specify a name:
-
- >>> component.getUtility(I1, name='foo') \\
- ... #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- (<InterfaceClass zope.component.tests.I1>, 'foo')
-
-
- ...otherwise, you get the default
-
- >>> component.queryUtility(I1, name='foo', default='<default>')
- '<default>'
-
- Registering the utility under the correct name
-
- >>> component.getGlobalSiteManager().registerUtility(
- ... ob, I1, name='foo')
-
- really helps:
-
- >>> component.getUtility(I1, 'foo') is ob
- True
- """
-
-def test_getAllUtilitiesRegisteredFor():
- """Again, like for adapters, it is often useful to get a list of all
- utilities that have been registered for a particular interface. Utilities
- providing a derived interface are also listed.
-
- Thus, let's create a derivative interface of `I1`:
-
- >>> class I11(I1):
- ... pass
-
- >>> class Ob11(Ob):
- ... interface.implements(I11)
-
- >>> ob11 = Ob11()
- >>> ob_bob = Ob()
-
- Now we register the new utilities:
-
- >>> gsm = component.getGlobalSiteManager()
- >>> gsm.registerUtility(ob, I1)
- >>> gsm.registerUtility(ob11, I11)
- >>> gsm.registerUtility(ob_bob, I1, name='bob')
- >>> gsm.registerUtility(Comp(2), I2)
-
- We can now get all the utilities that provide interface `I1`:
-
- >>> uts = list(component.getAllUtilitiesRegisteredFor(I1))
- >>> uts = sorted([util.__class__.__name__ for util in uts])
- >>> uts
- ['Ob', 'Ob', 'Ob11']
-
- Note that `getAllUtilitiesRegisteredFor()` does not return the names of
- the utilities.
- """
-
-def testNotBrokenWhenNoSiteManager():
- """Make sure that the adapter lookup is not broken, when no site manager
- is available.
-
- Both of those things emit `DeprecationWarnings`.
-
- >>> I2(ob) #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- TypeError: ('Could not adapt',
- <instance Ob>,
- <InterfaceClass zope.component.tests.I2>)
-
-
- >>> I2(ob, 42)
- 42
- """
-
-
-def testNo__component_adapts__leakage():
- """
- We want to make sure that an `adapts()` call in a class definition
- doesn't affect instances.
-
- >>> class C:
- ... component.adapts()
-
- >>> C.__component_adapts__
- ()
- >>> C().__component_adapts__
- Traceback (most recent call last):
- ...
- AttributeError: __component_adapts__
- """
-
-def test_ability_to_pickle_globalsitemanager():
- """
- We need to make sure that it is possible to pickle the global site manager
- and its two global adapter registries.
-
- >>> from zope.component import globalSiteManager
- >>> import cPickle
- >>> pickle = cPickle.dumps(globalSiteManager)
- >>> sm = cPickle.loads(pickle)
- >>> sm is globalSiteManager
- True
-
- Now let's ensure that the registries themselves can be pickled as well:
-
- >>> pickle = cPickle.dumps(globalSiteManager.adapters)
- >>> adapters = cPickle.loads(pickle)
- >>> adapters is globalSiteManager.adapters
- True
- """
-
-def test_persistent_component_managers():
- """
-Here, we'll demonstrate that changes work even when data are stored in
-a database and when accessed from multiple connections.
-
-Start by setting up a database and creating two transaction
-managers and database connections to work with.
-
- >>> import ZODB.tests.util
- >>> db = ZODB.tests.util.DB()
- >>> import transaction
- >>> t1 = transaction.TransactionManager()
- >>> c1 = db.open(transaction_manager=t1)
- >>> r1 = c1.root()
- >>> t2 = transaction.TransactionManager()
- >>> c2 = db.open(transaction_manager=t2)
- >>> r2 = c2.root()
-
-Create a set of components registries in the database, alternating
-connections.
-
- >>> from zope.component.persistentregistry import PersistentComponents
-
- >>> _ = t1.begin()
- >>> r1[1] = PersistentComponents('1')
- >>> t1.commit()
-
- >>> _ = t2.begin()
- >>> r2[2] = PersistentComponents('2', (r2[1], ))
- >>> t2.commit()
-
- >>> _ = t1.begin()
- >>> r1[3] = PersistentComponents('3', (r1[1], ))
- >>> t1.commit()
-
- >>> _ = t2.begin()
- >>> r2[4] = PersistentComponents('4', (r2[2], r2[3]))
- >>> t2.commit()
-
- >>> _ = t1.begin()
- >>> r1[1].__bases__
- ()
- >>> r1[2].__bases__ == (r1[1], )
- True
-
- >>> r1[1].registerUtility(U1(1))
- >>> r1[1].queryUtility(I1)
- U1(1)
- >>> r1[2].queryUtility(I1)
- U1(1)
- >>> t1.commit()
-
- >>> _ = t2.begin()
- >>> r2[1].registerUtility(U1(2))
- >>> r2[2].queryUtility(I1)
- U1(2)
-
- >>> r2[4].queryUtility(I1)
- U1(2)
- >>> t2.commit()
-
-
- >>> _ = t1.begin()
- >>> r1[1].registerUtility(U12(1), I2)
- >>> r1[4].queryUtility(I2)
- U12(1)
- >>> t1.commit()
-
-
- >>> _ = t2.begin()
- >>> r2[3].registerUtility(U12(3), I2)
- >>> r2[4].queryUtility(I2)
- U12(3)
- >>> t2.commit()
-
- >>> _ = t1.begin()
-
- >>> r1[1].registerHandler(handle1, info="First handler")
- >>> r1[2].registerHandler(handle, required=[U])
-
- >>> r1[3].registerHandler(handle3)
-
- >>> r1[4].registerHandler(handle4)
-
- >>> r1[4].handle(U1(1))
- handle1 U1(1)
- handle3 U1(1)
- handle (U1(1),)
- handle4 U1(1)
-
- >>> t1.commit()
-
- >>> _ = t2.begin()
- >>> r2[4].handle(U1(1))
- handle1 U1(1)
- handle3 U1(1)
- handle (U1(1),)
- handle4 U1(1)
- >>> t2.abort()
-
- >>> db.close()
- """
-
-def persistent_registry_doesnt_scew_up_subsribers():
- """
- >>> import ZODB.tests.util
- >>> db = ZODB.tests.util.DB()
- >>> import transaction
- >>> t1 = transaction.TransactionManager()
- >>> c1 = db.open(transaction_manager=t1)
- >>> r1 = c1.root()
- >>> t2 = transaction.TransactionManager()
- >>> c2 = db.open(transaction_manager=t2)
- >>> r2 = c2.root()
-
- >>> from zope.component.persistentregistry import PersistentComponents
-
- >>> _ = t1.begin()
- >>> r1[1] = PersistentComponents('1')
- >>> r1[1].registerHandler(handle1)
- >>> r1[1].registerSubscriptionAdapter(handle1, provided=I2)
- >>> _ = r1[1].unregisterHandler(handle1)
- >>> _ = r1[1].unregisterSubscriptionAdapter(handle1, provided=I2)
- >>> t1.commit()
- >>> _ = t1.begin()
- >>> r1[1].registerHandler(handle1)
- >>> r1[1].registerSubscriptionAdapter(handle1, provided=I2)
- >>> t1.commit()
-
- >>> _ = t2.begin()
- >>> len(list(r2[1].registeredHandlers()))
- 1
- >>> len(list(r2[1].registeredSubscriptionAdapters()))
- 1
- >>> t2.abort()
-
- """
-
-
-
-class GlobalRegistry:
- pass
-
-base = zope.component.globalregistry.GlobalAdapterRegistry(
- GlobalRegistry, 'adapters')
-GlobalRegistry.adapters = base
-def clear_base():
- base.__init__(GlobalRegistry, 'adapters')
-
-class IFoo(interface.Interface):
- pass
-class Foo(persistent.Persistent):
- interface.implements(IFoo)
- name = ''
- def __init__(self, name=''):
- self.name = name
-
- def __repr__(self):
- return 'Foo(%r)' % self.name
-
-def test_deghostification_of_persistent_adapter_registries():
- """
-
-We want to make sure that we see updates corrextly.
-
- >>> len(base._v_subregistries)
- 0
-
- >>> import ZODB.tests.util
- >>> db = ZODB.tests.util.DB()
- >>> tm1 = transaction.TransactionManager()
- >>> c1 = db.open(transaction_manager=tm1)
- >>> r1 = zope.component.persistentregistry.PersistentAdapterRegistry(
- ... (base,))
- >>> r2 = zope.component.persistentregistry.PersistentAdapterRegistry((r1,))
- >>> c1.root()[1] = r1
- >>> c1.root()[2] = r2
- >>> tm1.commit()
- >>> r1._p_deactivate()
-
- >>> len(base._v_subregistries)
- 0
-
- >>> tm2 = transaction.TransactionManager()
- >>> c2 = db.open(transaction_manager=tm2)
- >>> r1 = c2.root()[1]
- >>> r2 = c2.root()[2]
-
- >>> r1.lookup((), IFoo, '')
-
- >>> base.register((), IFoo, '', Foo(''))
- >>> r1.lookup((), IFoo, '')
- Foo('')
-
- >>> r2.lookup((), IFoo, '1')
-
- >>> r1.register((), IFoo, '1', Foo('1'))
-
- >>> r2.lookup((), IFoo, '1')
- Foo('1')
-
- >>> r1.lookup((), IFoo, '2')
- >>> r2.lookup((), IFoo, '2')
-
- >>> base.register((), IFoo, '2', Foo('2'))
-
- >>> r1.lookup((), IFoo, '2')
- Foo('2')
-
- >>> r2.lookup((), IFoo, '2')
- Foo('2')
-
-Cleanup:
-
- >>> db.close()
- >>> clear_base()
-
- """
-
-
-def test_multi_handler_unregistration():
- """
- There was a bug where multiple handlers for the same required
- specification would all be removed when one of them was
- unregistered:
-
- >>> class I(zope.interface.Interface):
- ... pass
- >>> def factory1(event):
- ... print "| Factory 1 is here"
- >>> def factory2(event):
- ... print "| Factory 2 is here"
- >>> class Event(object):
- ... zope.interface.implements(I)
- >>> from zope.interface.registry import Components
- >>> registry = Components()
- >>> registry.registerHandler(factory1, [I,])
- >>> registry.registerHandler(factory2, [I,])
- >>> registry.handle(Event())
- | Factory 1 is here
- | Factory 2 is here
- >>> registry.unregisterHandler(factory1, [I,])
- True
- >>> registry.handle(Event())
- | Factory 2 is here
- """
-
-def test_next_utilities():
- """
- It is common for a utility to delegate its answer to a utility
- providing the same interface in one of the component registry's
- bases. Let's first create a global utility::
-
- >>> import zope.interface
- >>> class IMyUtility(zope.interface.Interface):
- ... pass
-
- >>> class MyUtility(ConformsToIComponentLookup):
- ... zope.interface.implements(IMyUtility)
- ... def __init__(self, id, sm):
- ... self.id = id
- ... self.sitemanager = sm
- ... def __repr__(self):
- ... return "%s('%s')" % (self.__class__.__name__, self.id)
-
- >>> from zope.component import getGlobalSiteManager
- >>> gsm = getGlobalSiteManager()
-
- >>> gutil = MyUtility('global', gsm)
- >>> gsm.registerUtility(gutil, IMyUtility, 'myutil')
-
- Now, let's create two registries and set up the bases hierarchy::
-
- >>> from zope.interface.registry import Components
- >>> sm1 = Components('sm1', bases=(gsm, ))
- >>> sm1_1 = Components('sm1_1', bases=(sm1, ))
-
- Now we create two utilities and insert them in our folder hierarchy:
-
- >>> util1 = MyUtility('one', sm1)
- >>> sm1.registerUtility(util1, IMyUtility, 'myutil')
- >>> IComponentLookup(util1) is sm1
- True
-
- >>> util1_1 = MyUtility('one-one', sm1_1)
- >>> sm1_1.registerUtility(util1_1, IMyUtility, 'myutil')
- >>> IComponentLookup(util1_1) is sm1_1
- True
-
- Now, if we ask `util1_1` for its next available utility we get the
- ``one`` utility::
-
- >>> from zope.component import getNextUtility
- >>> getNextUtility(util1_1, IMyUtility, 'myutil')
- MyUtility('one')
-
- Next we ask `util1` for its next utility and we should get the global version:
-
- >>> getNextUtility(util1, IMyUtility, 'myutil')
- MyUtility('global')
-
- However, if we ask the global utility for the next one, an error is raised
-
- >>> getNextUtility(gutil, IMyUtility,
- ... 'myutil') #doctest: +NORMALIZE_WHITESPACE
- Traceback (most recent call last):
- ...
- ComponentLookupError:
- No more utilities for <InterfaceClass zope.component.tests.IMyUtility>,
- 'myutil' have been found.
-
- You can also use `queryNextUtility` and specify a default:
-
- >>> from zope.component import queryNextUtility
- >>> queryNextUtility(gutil, IMyUtility, 'myutil', 'default')
- 'default'
-
- Let's now ensure that the function also works with multiple registries. First
- we create another base registry:
-
- >>> myregistry = Components()
-
- We now set up another utility into that registry:
-
- >>> custom_util = MyUtility('my_custom_util', myregistry)
- >>> myregistry.registerUtility(custom_util, IMyUtility, 'my_custom_util')
-
- We add it as a base to the local site manager:
-
- >>> sm1.__bases__ = (myregistry,) + sm1.__bases__
-
- Both the ``myregistry`` and global utilities should be available:
-
- >>> queryNextUtility(sm1, IMyUtility, 'my_custom_util')
- MyUtility('my_custom_util')
- >>> queryNextUtility(sm1, IMyUtility, 'myutil')
- MyUtility('global')
-
- Note, if the context cannot be converted to a site manager, the default is
- retruned:
-
- >>> queryNextUtility(object(), IMyUtility, 'myutil', 'default')
- 'default'
- """
-
-def dont_leak_utility_registrations_in__subscribers():
- """
-
- We've observed utilities getting left in _subscribers when they
- get unregistered.
-
- >>> import zope.interface.registry
- >>> reg = zope.interface.registry.Components()
- >>> class C:
- ... def __init__(self, name):
- ... self.name = name
- ... def __repr__(self):
- ... return "C(%s)" % self.name
-
- >>> c1 = C(1)
- >>> reg.registerUtility(c1, I1)
- >>> reg.registerUtility(c1, I1)
- >>> list(reg.getAllUtilitiesRegisteredFor(I1))
- [C(1)]
-
- >>> reg.unregisterUtility(provided=I1)
- True
- >>> list(reg.getAllUtilitiesRegisteredFor(I1))
- []
-
- >>> reg.registerUtility(c1, I1)
- >>> reg.registerUtility(C(2), I1)
-
- >>> list(reg.getAllUtilitiesRegisteredFor(I1))
- [C(2)]
-
- """
-
-def test_zcml_handler_site_manager():
- """
- The ZCML directives provided by zope.component use the ``getSiteManager``
- method to get the registry where to register the components. This makes
- possible to hook ``getSiteManager`` before loading a ZCML file:
-
- >>> from zope.interface.registry import Components
- >>> registry = Components()
- >>> def dummy(context=None):
- ... return registry
- >>> from zope.component import getSiteManager
- >>> ignore = getSiteManager.sethook(dummy)
-
- >>> from zope.component.testfiles.components import comp, IApp
- >>> from zope.component.zcml import handler
- >>> handler('registerUtility', comp, IApp, u'')
- >>> registry.getUtility(IApp) is comp
- True
- >>> ignore = getSiteManager.reset()
-
- """
-
-class StandaloneTests(unittest.TestCase):
- def testStandalone(self):
- import subprocess
- import sys
- import os
- import tempfile
- import pickle
-
- executable = os.path.abspath(sys.executable)
- program = os.path.join(os.path.dirname(__file__), 'standalonetests.py')
- process = subprocess.Popen([executable, program],
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- stdin=subprocess.PIPE)
- pickle.dump(sys.path, process.stdin)
- process.stdin.close()
-
- try:
- process.wait()
- except OSError, e:
- if e.errno != 4: # MacIntel raises apparently unimportant EINTR?
- raise # TODO verify sanity of a pass on EINTR :-/
- lines = process.stdout.readlines()
- process.stdout.close()
- success = True
- # Interpret the result: We scan the output from the end backwards
- # until we find either a line that says 'OK' (which means the tests
- # ran successfully) or a line that starts with quite a few dashes
- # (which means we didn't find a line that says 'OK' within the summary
- # of the test runner and the tests did not run successfully.)
- for l in reversed(lines):
- l = l.strip()
- if not l:
- continue
- if l.startswith('-----'):
- break
- if l.endswith('OK'):
- sucess = True
- if not success:
- self.fail(''.join(lines))
-
-class HookableTests(unittest.TestCase):
-
- def test_ctor_no_func(self):
- from zope.component.hookable import hookable
- self.assertRaises(TypeError, hookable)
-
- def test_ctor_simple(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- hooked = hookable(foo)
- self.failUnless(hooked.original is foo)
- self.failUnless(hooked.implementation is foo)
-
- def test_ctor_extra_arg(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- self.assertRaises(TypeError, hookable, foo, foo)
-
- def test_ctor_extra_arg(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- self.assertRaises(TypeError, hookable, foo, nonesuch=foo)
-
- def test_sethook(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- def bar():
- pass
- hooked = hookable(foo)
- hooked.sethook(bar)
- self.failUnless(hooked.original is foo)
- self.failUnless(hooked.implementation is bar)
-
- def test_reset(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- def bar():
- pass
- hooked = hookable(foo)
- hooked.sethook(bar)
- hooked.reset()
- self.failUnless(hooked.original is foo)
- self.failUnless(hooked.implementation is foo)
-
- def test_cant_assign_original(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- def bar():
- pass
- hooked = hookable(foo)
- try:
- hooked.original = bar
- except TypeError:
- pass
- except AttributeError:
- pass
- else:
- self.fail('Assigned original')
-
- def test_cant_delete_original(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- hooked = hookable(foo)
- try:
- del hooked.original
- except TypeError:
- pass
- except AttributeError:
- pass
- else:
- self.fail('Deleted original')
-
- def test_cant_assign_original(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- def bar():
- pass
- hooked = hookable(foo)
- try:
- hooked.implementation = bar
- except TypeError:
- pass
- except AttributeError:
- pass
- else:
- self.fail('Assigned implementation')
-
- def test_readonly_original(self):
- from zope.component.hookable import hookable
- def foo():
- pass
- hooked = hookable(foo)
- try:
- del hooked.implementation
- except TypeError:
- pass
- except AttributeError:
- pass
- else:
- self.fail('Deleted implementation')
-
-class Ob3(object):
- interface.implements(IC)
-
-template = """<configure
- xmlns='http://namespaces.zope.org/zope'
- i18n_domain='zope'>
- %s
- </configure>"""
-
-
-class ResourceViewTests(PlacelessSetup, unittest.TestCase):
-
- def setUp(self):
- super(ResourceViewTests, self).setUp()
- XMLConfig('meta.zcml', zope.component)()
- XMLConfig('meta.zcml', zope.security)()
-
- def testView(self):
- ob = Ob3()
- request = Request(IV)
- self.assertEqual(
- zope.component.queryMultiAdapter((ob, request), name=u'test'), None)
-
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"/>
- '''
- ))
-
- self.assertEqual(
- zope.component.queryMultiAdapter((ob, request),
- name=u'test').__class__,
- V1)
-
-
- def testMultiView(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.adapter.A3"
- for="zope.component.testfiles.views.IC
- zope.component.testfiles.adapter.I1
- zope.component.testfiles.adapter.I2"
- type="zope.component.testfiles.views.IV"/>
- '''
- ))
-
-
- ob = Ob3()
- a1 = A1()
- a2 = A2()
- request = Request(IV)
- view = zope.component.queryMultiAdapter((ob, a1, a2, request),
- name=u'test')
- self.assertEqual(view.__class__, A3)
- self.assertEqual(view.context, (ob, a1, a2, request))
-
-
- def testMultiView_fails_w_multiple_factories(self):
- self.assertRaises(
- ConfigurationError,
- xmlconfig,
- StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.adapter.A3
- zope.component.testfiles.adapter.A2"
- for="zope.component.testfiles.views.IC
- zope.component.testfiles.adapter.I1
- zope.component.testfiles.adapter.I2"
- type="zope.component.testfiles.views.IV"/>
- '''
- )
- )
-
- def testView_w_multiple_factories(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.adapter.A1
- zope.component.testfiles.adapter.A2
- zope.component.testfiles.adapter.A3
- zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"/>
- '''
- ))
-
- ob = Ob3()
-
- # The view should be a V1 around an A3, around an A2, around
- # an A1, anround ob:
- view = zope.component.queryMultiAdapter((ob, Request(IV)), name=u'test')
- self.assertEqual(view.__class__, V1)
- a3 = view.context
- self.assertEqual(a3.__class__, A3)
- a2 = a3.context[0]
- self.assertEqual(a2.__class__, A2)
- a1 = a2.context[0]
- self.assertEqual(a1.__class__, A1)
- self.assertEqual(a1.context[0], ob)
-
- def testView_fails_w_no_factories(self):
- self.assertRaises(ConfigurationError,
- xmlconfig,
- StringIO(template %
- '''
- <view name="test"
- factory=""
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"/>
- '''
- ),
- )
-
-
- def testViewThatProvidesAnInterface(self):
- ob = Ob3()
- self.assertEqual(
- zope.component.queryMultiAdapter((ob, Request(IR)), IV, u'test'),
- None)
-
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IR"
- />
- '''
- ))
-
- self.assertEqual(
- zope.component.queryMultiAdapter((ob, Request(IR)), IV, u'test'),
- None)
-
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IR"
- provides="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.queryMultiAdapter((ob, Request(IR)), IV, u'test')
- self.assertEqual(v.__class__, V1)
-
-
- def testUnnamedViewThatProvidesAnInterface(self):
- ob = Ob3()
- self.assertEqual(
- zope.component.queryMultiAdapter((ob, Request(IR)), IV), None)
-
- xmlconfig(StringIO(template %
- '''
- <view factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IR"
- />
- '''
- ))
-
- v = zope.component.queryMultiAdapter((ob, Request(IR)), IV)
- self.assertEqual(v, None)
-
- xmlconfig(StringIO(template %
- '''
- <view factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IR"
- provides="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.queryMultiAdapter((ob, Request(IR)), IV)
- self.assertEqual(v.__class__, V1)
-
- def testViewHavingARequiredClass(self):
- xmlconfig(StringIO(template % (
- '''
- <view
- for="zope.component.testfiles.components.Content"
- type="zope.component.testfiles.views.IR"
- factory="zope.component.testfiles.adapter.A1"
- />
- '''
- )))
-
- content = Content()
- a1 = zope.component.getMultiAdapter((content, Request(IR)))
- self.assert_(isinstance(a1, A1))
-
- class MyContent:
- interface.implements(IContent)
-
- self.assertRaises(ComponentLookupError, zope.component.getMultiAdapter,
- (MyContent(), Request(IR)))
-
- def testInterfaceProtectedView(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- permission="zope.Public"
- allowed_interface="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = ProxyFactory(zope.component.getMultiAdapter((Ob3(), Request(IV)),
- name='test'))
- self.assertEqual(v.index(), 'V1 here')
- self.assertRaises(Exception, getattr, v, 'action')
-
- def testAttributeProtectedView(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- permission="zope.Public"
- allowed_attributes="action"
- />
- '''
- ))
-
- v = ProxyFactory(zope.component.getMultiAdapter((Ob3(), Request(IV)),
- name='test'))
- self.assertEqual(v.action(), 'done')
- self.assertRaises(Exception, getattr, v, 'index')
-
- def testInterfaceAndAttributeProtectedView(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- permission="zope.Public"
- allowed_attributes="action"
- allowed_interface="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.getMultiAdapter((Ob3(), Request(IV)), name='test')
- self.assertEqual(v.index(), 'V1 here')
- self.assertEqual(v.action(), 'done')
-
- def testDuplicatedInterfaceAndAttributeProtectedView(self):
- xmlconfig(StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- permission="zope.Public"
- allowed_attributes="action index"
- allowed_interface="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.getMultiAdapter((Ob3(), Request(IV)), name='test')
- self.assertEqual(v.index(), 'V1 here')
- self.assertEqual(v.action(), 'done')
-
- def testIncompleteProtectedViewNoPermission(self):
- self.assertRaises(
- ConfigurationError,
- xmlconfig,
- StringIO(template %
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- allowed_attributes="action index"
- />
- '''
- ))
-
- def testViewUndefinedPermission(self):
- config = StringIO(template % (
- '''
- <view name="test"
- factory="zope.component.testfiles.views.V1"
- for="zope.component.testfiles.views.IC"
- type="zope.component.testfiles.views.IV"
- permission="zope.UndefinedPermission"
- allowed_attributes="action index"
- allowed_interface="zope.component.testfiles.views.IV"
- />
- '''
- ))
- self.assertRaises(ValueError, xmlconfig, config, testing=1)
-
- def testResource(self):
- ob = Ob3()
- self.assertEqual(
- zope.component.queryAdapter(Request(IV), name=u'test'), None)
- xmlconfig(StringIO(template % (
- '''
- <resource name="test"
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IV"/>
- '''
- )))
-
- self.assertEqual(
- zope.component.queryAdapter(Request(IV), name=u'test').__class__,
- R1)
-
- def testResourceThatProvidesAnInterface(self):
- ob = Ob3()
- self.assertEqual(zope.component.queryAdapter(Request(IR), IV, u'test'),
- None)
-
- xmlconfig(StringIO(template %
- '''
- <resource
- name="test"
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IR"
- />
- '''
- ))
-
- v = zope.component.queryAdapter(Request(IR), IV, name=u'test')
- self.assertEqual(v, None)
-
- xmlconfig(StringIO(template %
- '''
- <resource
- name="test"
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IR"
- provides="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.queryAdapter(Request(IR), IV, name=u'test')
- self.assertEqual(v.__class__, R1)
-
- def testUnnamedResourceThatProvidesAnInterface(self):
- ob = Ob3()
- self.assertEqual(zope.component.queryAdapter(Request(IR), IV), None)
-
- xmlconfig(StringIO(template %
- '''
- <resource
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IR"
- />
- '''
- ))
-
- v = zope.component.queryAdapter(Request(IR), IV)
- self.assertEqual(v, None)
-
- xmlconfig(StringIO(template %
- '''
- <resource
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IR"
- provides="zope.component.testfiles.views.IV"
- />
- '''
- ))
-
- v = zope.component.queryAdapter(Request(IR), IV)
- self.assertEqual(v.__class__, R1)
-
- def testResourceUndefinedPermission(self):
-
- config = StringIO(template % (
- '''
- <resource name="test"
- factory="zope.component.testfiles.views.R1"
- type="zope.component.testfiles.views.IV"
- permission="zope.UndefinedPermission"/>
- '''
- ))
- self.assertRaises(ValueError, xmlconfig, config, testing=1)
-
-
-class ConditionalSecurityLayer(UnitTests):
-
- __name__ = 'ConditionalSecurity'
- __bases__ = ()
-
- def setUp(self):
- setUp()
- self.modules = {}
- for m in ('zope.security', 'zope.proxy'):
- self.modules[m] = sys.modules[m]
- sys.modules[m] = None
- import zope.component.zcml
- reload(zope.component.zcml)
-
- def tearDown(self):
- tearDown()
- for m in ('zope.security', 'zope.proxy'):
- sys.modules[m] = self.modules[m]
- import zope.component.zcml
- reload(zope.component.zcml)
-
-
-def setUpRegistryTests(tests):
- setUp()
-
-def tearDownRegistryTests(tests):
- tearDown()
- import zope.event
- zope.event.subscribers.pop()
-
-def clearZCML(test=None):
- tearDown()
- setUp()
- XMLConfig('meta.zcml', component)()
-
-def test_suite():
- checker = renormalizing.RENormalizing([
- (re.compile('at 0x[0-9a-fA-F]+'), 'at <SOME ADDRESS>'),
- (re.compile(r"<type 'exceptions.(\w+)Error'>:"),
- r'exceptions.\1Error:'),
- ])
-
- zcml_conditional = doctest.DocFileSuite('zcml_conditional.txt', checker=checker)
- zcml_conditional.layer = ConditionalSecurityLayer()
-
- with_globs = dict(with_statement=__future__.with_statement)
- hooks_conditional = doctest.DocFileSuite(
- 'hooks.txt', checker=checker, globs=with_globs)
- hooks_conditional.layer = ConditionalSecurityLayer()
-
- return unittest.TestSuite((
- doctest.DocTestSuite(setUp=setUp, tearDown=tearDown),
- unittest.makeSuite(HookableTests),
- doctest.DocTestSuite('zope.component.interface',
- setUp=setUp, tearDown=tearDown),
- doctest.DocTestSuite('zope.component.nexttesting'),
- doctest.DocFileSuite('README.txt',
- setUp=setUp, tearDown=tearDown),
- doctest.DocFileSuite('socketexample.txt',
- setUp=setUp, tearDown=tearDown),
- doctest.DocFileSuite('factory.txt',
- setUp=setUp, tearDown=tearDown),
- doctest.DocFileSuite('hooks.txt', checker=checker,
- setUp=setUp, tearDown=tearDown,
- globs=with_globs),
- doctest.DocFileSuite('event.txt',
- setUp=setUp, tearDown=tearDown),
- doctest.DocTestSuite('zope.component.security'),
- doctest.DocFileSuite('zcml.txt', checker=checker,
- setUp=setUp, tearDown=tearDown),
- doctest.DocFileSuite('configure.txt',
- setUp=setUp, tearDown=tearDown),
- doctest.DocFileSuite('testlayer.txt',
- optionflags=(doctest.ELLIPSIS +
- doctest.NORMALIZE_WHITESPACE +
- doctest.REPORT_NDIFF)),
- zcml_conditional,
- hooks_conditional,
- unittest.makeSuite(StandaloneTests),
- unittest.makeSuite(ResourceViewTests),
- ))
-
-if __name__ == "__main__":
- unittest.main(defaultTest='test_suite')
Modified: zope.component/trunk/src/zope/component/zcml.py
===================================================================
--- zope.component/trunk/src/zope/component/zcml.py 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/zcml.py 2012-06-29 14:47:56 UTC (rev 127192)
@@ -13,42 +13,49 @@
##############################################################################
"""Component Architecture configuration handlers
"""
-__docformat__ = "reStructuredText"
-
-import warnings
-import zope.component
-import zope.configuration.fields
-import zope.interface
-import zope.schema
-
-from zope.component.interface import provideInterface
from zope.configuration.exceptions import ConfigurationError
+from zope.configuration.fields import Bool
+from zope.configuration.fields import GlobalInterface
+from zope.configuration.fields import GlobalObject
+from zope.configuration.fields import PythonIdentifier
+from zope.configuration.fields import Tokens
from zope.i18nmessageid import MessageFactory
+from zope.interface import Interface
+from zope.interface import implementedBy
+from zope.interface import providedBy
+from zope.schema import TextLine
+from zope.component._api import getSiteManager
+from zope.component._declaration import adaptedBy
+from zope.component.interface import provideInterface
+from zope.component._compat import _BLANK
+
try:
- from zope.component.security import _checker, proxify, protectedFactory, \
- securityAdapterFactory
from zope.security.zcml import Permission
-except ImportError:
- SECURITY_SUPPORT = False
- from zope.schema import TextLine as Permission
+except ImportError: #pragma NO COVER
+ def _no_security(*args, **kw):
+ raise ConfigurationError("security proxied components are not "
+ "supported because zope.security is not available")
+ _checker = proxify = protectedFactory = security =_no_security
+ Permission = TextLine
else:
- SECURITY_SUPPORT = True
+ from zope.component.security import _checker
+ from zope.component.security import proxify
+ from zope.component.security import protectedFactory
+ from zope.component.security import securityAdapterFactory
_ = MessageFactory('zope')
-def check_security_support():
- if not SECURITY_SUPPORT:
- raise ConfigurationError("security proxied components are not "
- "supported because zope.security is not available")
+class ComponentConfigurationError(ValueError, ConfigurationError):
+ pass
def handler(methodName, *args, **kwargs):
- method = getattr(zope.component.getSiteManager(), methodName)
+ method = getattr(getSiteManager(), methodName)
method(*args, **kwargs)
-class IBasicComponentInformation(zope.interface.Interface):
+class IBasicComponentInformation(Interface):
- component = zope.configuration.fields.GlobalObject(
+ component = GlobalObject(
title=_("Component to use"),
description=_("Python name of the implementation object. This"
" must identify an object in a module using the"
@@ -63,7 +70,7 @@
required=False,
)
- factory = zope.configuration.fields.GlobalObject(
+ factory = GlobalObject(
title=_("Factory"),
description=_("Python name of a factory which can create the"
" implementation object. This must identify an"
@@ -73,31 +80,31 @@
required=False,
)
-class IAdapterDirective(zope.interface.Interface):
+class IAdapterDirective(Interface):
"""
Register an adapter
"""
- factory = zope.configuration.fields.Tokens(
+ factory = Tokens(
title=_("Adapter factory/factories"),
description=_("A list of factories (usually just one) that create"
" the adapter instance."),
required=True,
- value_type=zope.configuration.fields.GlobalObject()
+ value_type=GlobalObject()
)
- provides = zope.configuration.fields.GlobalInterface(
+ provides = GlobalInterface(
title=_("Interface the component provides"),
description=_("This attribute specifies the interface the adapter"
" instance must provide."),
required=False,
)
- for_ = zope.configuration.fields.Tokens(
+ for_ = Tokens(
title=_("Specifications to be adapted"),
description=_("This should be a list of interfaces or classes"),
required=False,
- value_type=zope.configuration.fields.GlobalObject(
+ value_type=GlobalObject(
missing_value=object(),
),
)
@@ -109,7 +116,7 @@
required=False,
)
- name = zope.schema.TextLine(
+ name = TextLine(
title=_("Name"),
description=_("Adapters can have names.\n\n"
"This attribute allows you to specify the name for"
@@ -117,7 +124,7 @@
required=False,
)
- trusted = zope.configuration.fields.Bool(
+ trusted = Bool(
title=_("Trusted"),
description=_("""Make the adapter a trusted adapter
@@ -131,7 +138,7 @@
default=False,
)
- locate = zope.configuration.fields.Bool(
+ locate = Bool(
title=_("Locate"),
description=_("""Make the adapter a locatable adapter
@@ -158,7 +165,7 @@
if for_ is None:
if len(factory) == 1:
- for_ = zope.component.adaptedBy(factory[0])
+ for_ = adaptedBy(factory[0])
if for_ is None:
raise TypeError("No for attribute was provided and can't "
@@ -168,7 +175,7 @@
if provides is None:
if len(factory) == 1:
- p = list(zope.interface.implementedBy(factory[0]))
+ p = list(implementedBy(factory[0]))
if len(p) == 1:
provides = p[0]
@@ -180,19 +187,18 @@
if len(factories) == 1:
factory = factories[0]
elif len(factories) < 1:
- raise ValueError("No factory specified")
+ raise ComponentConfigurationError("No factory specified")
elif len(factories) > 1 and len(for_) != 1:
- raise ValueError("Can't use multiple factories and multiple for")
+ raise ComponentConfigurationError(
+ "Can't use multiple factories and multiple for")
else:
factory = _rolledUpFactory(factories)
if permission is not None:
- check_security_support()
factory = protectedFactory(factory, provides, permission)
# invoke custom adapter factories
if locate or permission is not None or trusted:
- check_security_support()
factory = securityAdapterFactory(factory, permission, locate, trusted)
_context.action(
@@ -215,35 +221,35 @@
args = ('', iface)
)
-class ISubscriberDirective(zope.interface.Interface):
+class ISubscriberDirective(Interface):
"""
Register a subscriber
"""
- factory = zope.configuration.fields.GlobalObject(
+ factory = GlobalObject(
title=_("Subscriber factory"),
description=_("A factory used to create the subscriber instance."),
required=False,
)
- handler = zope.configuration.fields.GlobalObject(
+ handler = GlobalObject(
title=_("Handler"),
description=_("A callable object that handles events."),
required=False,
)
- provides = zope.configuration.fields.GlobalInterface(
+ provides = GlobalInterface(
title=_("Interface the component provides"),
description=_("This attribute specifies the interface the adapter"
" instance must provide."),
required=False,
)
- for_ = zope.configuration.fields.Tokens(
+ for_ = Tokens(
title=_("Interfaces or classes that this subscriber depends on"),
description=_("This should be a list of interfaces or classes"),
required=False,
- value_type=zope.configuration.fields.GlobalObject(
+ value_type=GlobalObject(
missing_value = object(),
),
)
@@ -255,7 +261,7 @@
required=False,
)
- trusted = zope.configuration.fields.Bool(
+ trusted = Bool(
title=_("Trusted"),
description=_("""Make the subscriber a trusted subscriber
@@ -269,7 +275,7 @@
default=False,
)
- locate = zope.configuration.fields.Bool(
+ locate = Bool(
title=_("Locate"),
description=_("""Make the subscriber a locatable subscriber
@@ -298,20 +304,18 @@
"a factory")
if for_ is None:
- for_ = zope.component.adaptedBy(factory)
+ for_ = adaptedBy(factory)
if for_ is None:
raise TypeError("No for attribute was provided and can't "
"determine what the factory (or handler) adapts.")
if permission is not None:
- check_security_support()
factory = protectedFactory(factory, provides, permission)
for_ = tuple(for_)
# invoke custom adapter factories
if locate or permission is not None or trusted:
- check_security_support()
factory = securityAdapterFactory(factory, permission, locate, trusted)
if handler is not None:
@@ -319,14 +323,14 @@
discriminator = None,
callable = _handler,
args = ('registerHandler',
- handler, for_, u'', _context.info),
+ handler, for_, _BLANK, _context.info),
)
else:
_context.action(
discriminator = None,
callable = _handler,
args = ('registerSubscriptionAdapter',
- factory, for_, provides, u'', _context.info),
+ factory, for_, provides, _BLANK, _context.info),
)
if provides is not None:
@@ -348,13 +352,13 @@
class IUtilityDirective(IBasicComponentInformation):
"""Register a utility."""
- provides = zope.configuration.fields.GlobalInterface(
+ provides = GlobalInterface(
title=_("Provided interface"),
description=_("Interface provided by the utility."),
required=False,
)
- name = zope.schema.TextLine(
+ name = TextLine(
title=_("Name"),
description=_("Name of the registration. This is used by"
" application code when locating a utility."),
@@ -368,46 +372,45 @@
if provides is None:
if factory:
- provides = list(zope.interface.implementedBy(factory))
+ provides = list(implementedBy(factory))
else:
- provides = list(zope.interface.providedBy(component))
+ provides = list(providedBy(component))
if len(provides) == 1:
provides = provides[0]
else:
raise TypeError("Missing 'provides' attribute")
if permission is not None:
- check_security_support()
component = proxify(component, provides=provides, permission=permission)
_context.action(
discriminator = ('utility', provides, name),
callable = handler,
- args = ('registerUtility', component, provides, name),
+ args = ('registerUtility', component, provides, name, _context.info),
kw = dict(factory=factory),
)
_context.action(
discriminator = None,
callable = provideInterface,
- args = (provides.__module__ + '.' + provides.getName(), provides)
+ args = ('', provides),
)
-class IInterfaceDirective(zope.interface.Interface):
+class IInterfaceDirective(Interface):
"""
Define an interface
"""
- interface = zope.configuration.fields.GlobalInterface(
+ interface = GlobalInterface(
title=_("Interface"),
required=True,
)
- type = zope.configuration.fields.GlobalInterface(
+ type = GlobalInterface(
title=_("Interface type"),
required=False,
)
- name = zope.schema.TextLine(
+ name = TextLine(
title=_("Name"),
required=False,
)
@@ -419,15 +422,15 @@
args = (name, interface, type)
)
-class IBasicViewInformation(zope.interface.Interface):
+class IBasicViewInformation(Interface):
"""This is the basic information for all views."""
- for_ = zope.configuration.fields.Tokens(
+ for_ = Tokens(
title=_("Specifications of the objects to be viewed"),
description=_("""This should be a list of interfaces or classes
"""),
required=True,
- value_type=zope.configuration.fields.GlobalObject(
+ value_type=GlobalObject(
missing_value=object(),
),
)
@@ -438,22 +441,13 @@
required=False,
)
- class_ = zope.configuration.fields.GlobalObject(
+ class_ = GlobalObject(
title=_("Class"),
description=_("A class that provides attributes used by the view."),
required=False,
)
- layer = zope.configuration.fields.GlobalInterface(
- title=_("The layer the view is in."),
- description=_("""
- A skin is composed of layers. It is common to put skin
- specific views in a layer named after the skin. If the 'layer'
- attribute is not supplied, it defaults to 'default'."""),
- required=False,
- )
-
- allowed_interface = zope.configuration.fields.Tokens(
+ allowed_interface = Tokens(
title=_("Interface that is also allowed if user has permission."),
description=_("""
By default, 'permission' only applies to viewing the view and
@@ -464,10 +458,10 @@
Multiple interfaces can be provided, separated by
whitespace."""),
required=False,
- value_type=zope.configuration.fields.GlobalInterface(),
+ value_type=GlobalInterface(),
)
- allowed_attributes = zope.configuration.fields.Tokens(
+ allowed_attributes = Tokens(
title=_("View attributes that are also allowed if the user"
" has permission."),
description=_("""
@@ -476,31 +470,31 @@
you can make the permission also apply to the extra attributes
on the view object."""),
required=False,
- value_type=zope.configuration.fields.PythonIdentifier(),
+ value_type=PythonIdentifier(),
)
-class IBasicResourceInformation(zope.interface.Interface):
+class IBasicResourceInformation(Interface):
"""
Basic information for resources
"""
- name = zope.schema.TextLine(
+ name = TextLine(
title=_("The name of the resource."),
description=_("The name shows up in URLs/paths. For example 'foo'."),
required=True,
- default=u'',
+ default=_BLANK,
)
- provides = zope.configuration.fields.GlobalInterface(
+ provides = GlobalInterface(
title=_("The interface this component provides."),
description=_("""
A view can provide an interface. This would be used for
views that support other views."""),
required=False,
- default=zope.interface.Interface,
+ default=Interface,
)
- type = zope.configuration.fields.GlobalInterface(
+ type = GlobalInterface(
title=_("Request type"),
required=True
)
@@ -509,28 +503,26 @@
class IViewDirective(IBasicViewInformation, IBasicResourceInformation):
"""Register a view for a component"""
- factory = zope.configuration.fields.Tokens(
+ factory = Tokens(
title=_("Factory"),
required=False,
- value_type=zope.configuration.fields.GlobalObject(),
+ value_type=GlobalObject(),
)
-def view(_context, factory, type, name, for_, layer=None,
- permission=None, allowed_interface=None, allowed_attributes=None,
- provides=zope.interface.Interface):
+def view(_context, factory, type, name, for_,
+ permission=None,
+ allowed_interface=None,
+ allowed_attributes=None,
+ provides=Interface,
+ ):
if ((allowed_attributes or allowed_interface)
and (not permission)):
- raise ConfigurationError(
- "Must use name attribute with allowed_interface or "
- "allowed_attributes"
- )
+ raise ComponentConfigurationError(
+ "'permission' required with 'allowed_interface' or "
+ "'allowed_attributes'")
- if not factory:
- raise ConfigurationError("No view factory specified.")
-
if permission is not None:
- check_security_support()
checker = _checker(_context, permission,
allowed_interface, allowed_attributes)
@@ -549,7 +541,7 @@
if not for_:
- raise ValueError("No for interfaces specified");
+ raise ComponentConfigurationError("No for interfaces specified");
for_ = tuple(for_)
# Generate a single factory from multiple factories:
@@ -557,27 +549,18 @@
if len(factories) == 1:
factory = factories[0]
elif len(factories) < 1:
- raise ValueError("No factory specified")
+ raise ComponentConfigurationError("No view factory specified")
elif len(factories) > 1 and len(for_) > 1:
- raise ValueError("Can't use multiple factories and multiple for")
+ raise ComponentConfigurationError(
+ "Can't use multiple factories and multiple for")
else:
def factory(ob, request):
for f in factories[:-1]:
ob = f(ob)
return factories[-1](ob, request)
+ factory.factory = factories[0]
- # BBB 2006/02/18, to be removed after 12 months
- if layer is not None:
- for_ = for_ + (layer,)
- warnings.warn_explicit(
- "The 'layer' argument of the 'view' directive has been "
- "deprecated. Use the 'type' argument instead. If you have "
- "an existing 'type' argument IBrowserRequest, replace it with the "
- "'layer' argument (the layer subclasses IBrowserRequest). "
- "which subclasses BrowserRequest.",
- DeprecationWarning, _context.info.file, _context.info.line)
- else:
- for_ = for_ + (type,)
+ for_ = for_ + (type,)
_context.action(
discriminator = ('view', for_, name, provides),
@@ -585,12 +568,6 @@
args = ('registerAdapter',
factory, for_, provides, name, _context.info),
)
- if type is not None:
- _context.action(
- discriminator = None,
- callable = provideInterface,
- args = ('', type)
- )
_context.action(
discriminator = None,
@@ -612,67 +589,52 @@
IBasicResourceInformation):
"""Register a resource"""
- layer = zope.configuration.fields.GlobalInterface(
- title=_("The layer the resource is in."),
- required=False,
- )
-
- allowed_interface = zope.configuration.fields.Tokens(
+ allowed_interface = Tokens(
title=_("Interface that is also allowed if user has permission."),
required=False,
- value_type=zope.configuration.fields.GlobalInterface(),
+ value_type=GlobalInterface(),
)
- allowed_attributes = zope.configuration.fields.Tokens(
+ allowed_attributes = Tokens(
title=_("View attributes that are also allowed if user"
" has permission."),
required=False,
- value_type=zope.configuration.fields.PythonIdentifier(),
+ value_type=PythonIdentifier(),
)
-def resource(_context, factory, type, name, layer=None,
+def resource(_context, factory, type, name,
permission=None,
allowed_interface=None, allowed_attributes=None,
- provides=zope.interface.Interface):
+ provides=Interface):
if ((allowed_attributes or allowed_interface)
and (not permission)):
- raise ConfigurationError(
+ raise ComponentConfigurationError(
"Must use name attribute with allowed_interface or "
"allowed_attributes"
)
if permission is not None:
- check_security_support()
checker = _checker(_context, permission,
allowed_interface, allowed_attributes)
def proxyResource(request, factory=factory, checker=checker):
return proxify(factory(request), checker)
+ proxyResource.factory = factory
factory = proxyResource
- if layer is not None:
- warnings.warn_explicit(
- "The 'layer' argument of the 'resource' directive has been "
- "deprecated. Use the 'type' argument instead.",
- DeprecationWarning, _context.info.file, _context.info.line)
- type = layer
-
_context.action(
discriminator = ('resource', name, type, provides),
callable = handler,
args = ('registerAdapter',
- factory, (type,), provides, name, _context.info),
- )
+ factory, (type,), provides, name, _context.info))
_context.action(
discriminator = None,
callable = provideInterface,
- args = (type.__module__ + '.' + type.__name__, type)
- )
+ args = ('', type))
_context.action(
discriminator = None,
callable = provideInterface,
- args = (provides.__module__ + '.' + provides.__name__, type)
- )
+ args = ('', provides))
Deleted: zope.component/trunk/src/zope/component/zcml.txt
===================================================================
--- zope.component/trunk/src/zope/component/zcml.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/zcml.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,1021 +0,0 @@
-ZCML directives
-===============
-
-Components may be registered using the registration API exposed by
-``zope.component`` (provideAdapter, provideUtility, etc.). They may
-also be registered using configuration files. The common way to do
-that is by using ZCML (Zope Configuration Markup Language), an XML
-spelling of component registration.
-
-In ZCML, each XML element is a *directive*. There are different
-top-level directives that let us register components. We will
-introduce them one by one here.
-
-This helper will let us easily execute ZCML snippets:
-
- >>> from cStringIO import StringIO
- >>> from zope.configuration.xmlconfig import xmlconfig
- >>> def runSnippet(snippet):
- ... template = """\
- ... <configure xmlns='http://namespaces.zope.org/zope'
- ... i18n_domain="zope">
- ... %s
- ... </configure>"""
- ... xmlconfig(StringIO(template % snippet))
-
-adapter
--------
-
-Adapters play a key role in the Component Architecture. In ZCML, they
-are registered with the <adapter /> directive.
-
- >>> from zope.component.testfiles.adapter import A1, A2, A3, Handler
- >>> from zope.component.testfiles.adapter import I1, I2, I3, IS
- >>> from zope.component.testfiles.components import IContent, Content, Comp, comp
-
-Before we register the first test adapter, we can verify that adapter
-lookup doesn't work yet:
-
- >>> from zope.component.tests import clearZCML
- >>> clearZCML()
- >>> from zope.component.testfiles.components import IApp
- >>> IApp(Content(), None) is None
- True
-
-Then we register the adapter and see that the lookup works:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
-
- >>> IApp(Content()).__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-It is also possible to give adapters names. Then the combination of
-required interface, provided interface and name makes the adapter
-lookup unique. The name is supplied using the ``name`` argument to
-the <adapter /> directive:
-
- >>> from zope.component.tests import clearZCML
- >>> clearZCML()
- >>> import zope.component
- >>> zope.component.queryAdapter(Content(), IApp, 'test') is None
- True
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... name="test"
- ... />''')
-
- >>> zope.component.getAdapter(Content(), IApp, 'test').__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-Adapter factories
-~~~~~~~~~~~~~~~~~
-
-It is possible to supply more than one adapter factory. In this case,
-during adapter lookup each factory will be called and the return value
-will be given to the next factory. The return value of the last
-factory is returned as the result of the adapter lookup. For examle:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2
- ... zope.component.testfiles.adapter.A3"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
-
-The resulting adapter is an A3, around an A2, around an A1, around the
-adapted object:
-
- >>> content = Content()
- >>> a3 = IApp(content)
- >>> a3.__class__ is A3
- True
-
- >>> a2 = a3.context[0]
- >>> a2.__class__ is A2
- True
-
- >>> a1 = a2.context[0]
- >>> a1.__class__ is A1
- True
-
- >>> a1.context[0] is content
- True
-
-Of course, if no factory is provided at all, we will get an error:
-
- >>> runSnippet('''
- ... <adapter
- ... factory=""
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
- ValueError: No factory specified
-
-
-Declaring ``for`` and ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The <adapter /> directive can figure out from the in-line Python
-declaration (using ``zope.component.adapts()`` or
-``zope.component.adapter()`` as well as ``zope.interface.implements``)
-what the adapter should be registered for and what it provides::
-
- >>> clearZCML()
- >>> IApp(Content(), None) is None
- True
-
- >>> runSnippet('''
- ... <adapter factory="zope.component.testfiles.components.Comp" />''')
-
- >>> IApp(Content()).__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-Of course, if the adapter has no ``implements()`` declaration, ZCML
-can't figure out what it provides:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A4"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
- TypeError: Missing 'provides' attribute
-
-On the other hand, if the factory implements more than one interface,
-ZCML can't figure out what it should provide either:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A5"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
- TypeError: Missing 'provides' attribute
-
-A not so common edge case is registering adapters directly for
-classes, not for interfaces. For example:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.Content"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... />''')
-
- >>> content = Content()
- >>> a1 = zope.component.getAdapter(content, I1, '')
- >>> isinstance(a1, A1)
- True
-
-This time, any object providing ``IContent`` won't work if it's not an
-instance of the ``Content`` class:
-
- >>> import zope.interface
- >>> class MyContent:
- ... zope.interface.implements(IContent)
- >>> zope.component.getAdapter(MyContent(), I1, '') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- ComponentLookupError: ...
-
-Multi-adapters
-~~~~~~~~~~~~~~
-
-Conventional adapters adapt one object to provide another interface.
-Multi-adapters adapt several objects at once:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1
- ... zope.component.testfiles.adapter.I2"
- ... provides="zope.component.testfiles.adapter.I3"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> content = Content()
- >>> a1 = A1()
- >>> a2 = A2()
- >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-You can even adapt an empty list of objects (we call this a
-null-adapter):
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for=""
- ... provides="zope.component.testfiles.adapter.I3"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> a3 = zope.component.queryMultiAdapter((), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == ()
- True
-
-Even with multi-adapters, ZCML can figure out the ``for`` and
-``provides`` parameters from the Python declarations:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter factory="zope.component.testfiles.adapter.A3" />''')
-
- >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-Chained factories are not supported for multi-adapters, though:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1
- ... zope.component.testfiles.adapter.I2"
- ... provides="zope.component.testfiles.components.IApp"
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-11.8
- ValueError: Can't use multiple factories and multiple for
-
-And neither for null-adapters:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for=""
- ... provides="zope.component.testfiles.components.IApp"
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-9.8
- ValueError: Can't use multiple factories and multiple for
-
-Protected adapters
-~~~~~~~~~~~~~~~~~~
-
-Adapters can be protected with a permission. First we have to define
-a permission for which we'll have to register the <permission />
-directive:
-
- >>> clearZCML()
- >>> IApp(Content(), None) is None
- True
-
- >>> import zope.security
- >>> from zope.configuration.xmlconfig import XMLConfig
- >>> XMLConfig('meta.zcml', zope.security)()
- >>> runSnippet('''
- ... <permission
- ... id="y.x"
- ... title="XY"
- ... description="Allow XY."
- ... />
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... permission="y.x"
- ... />''')
-
-We see that the adapter is a location proxy now so that the
-appropriate permissions can be found from the context:
-
- >>> IApp(Content()).__class__
- <class 'zope.component.testfiles.components.Comp'>
- >>> type(IApp(Content()))
- <class 'zope.location.location.LocationProxy'>
-
-We can also go about it a different way. Let's make a public adapter
-and wrap the adapter in a security proxy. That often happens when
-an adapter is turned over to untrusted code:
-
- >>> clearZCML()
- >>> IApp(Content(), None) is None
- True
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... permission="zope.Public"
- ... />''')
-
- >>> from zope.security.checker import ProxyFactory
- >>> adapter = ProxyFactory(IApp(Content()))
- >>> from zope.security.proxy import getTestProxyItems
- >>> items = [item[0] for item in getTestProxyItems(adapter)]
- >>> items
- ['a', 'f']
-
- >>> from zope.security.proxy import removeSecurityProxy
- >>> removeSecurityProxy(adapter).__class__ is Comp
- True
-
-Of course, this still works when we let the ZCML directive handler
-figure out ``for`` and ``provides`` from the Python declarations:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... permission="zope.Public"
- ... />''')
-
- >>> adapter = ProxyFactory(IApp(Content()))
- >>> [item[0] for item in getTestProxyItems(adapter)]
- ['a', 'f']
- >>> removeSecurityProxy(adapter).__class__ is Comp
- True
-
-It also works with multi adapters:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A3"
- ... provides="zope.component.testfiles.adapter.I3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1
- ... zope.component.testfiles.adapter.I2"
- ... permission="zope.Public"
- ... />''')
-
- >>> content = Content()
- >>> a1 = A1()
- >>> a2 = A2()
- >>> a3 = ProxyFactory(zope.component.queryMultiAdapter((content, a1, a2), I3))
- >>> a3.__class__ == A3
- True
- >>> [item[0] for item in getTestProxyItems(a3)]
- ['f1', 'f2', 'f3']
-
-It's probably not worth mentioning, but when we try to protect an
-adapter with a permission that doesn't exist, we'll obviously get an
-error:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... permission="zope.UndefinedPermission"
- ... />''')
- Traceback (most recent call last):
- ...
- ConfigurationExecutionError: exceptions.ValueError: ('Undefined permission id', 'zope.UndefinedPermission')
- in:
- File "<string>", line 4.2-9.8
- Could not read source.
-
-Trusted adapters
-~~~~~~~~~~~~~~~~
-
-Trusted adapters are adapters that are trusted to do anything with the
-objects they are given so that these objects are not security-proxied.
-They are registered using the ``trusted`` argument to the <adapter />
-directive:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... trusted="yes"
- ... />''')
-
-With an unproxied object, it's business as usual:
-
- >>> ob = Content()
- >>> type(I1(ob)) is A1
- True
-
-With a security-proxied object, however, we get a security-proxied
-adapter:
-
- >>> p = ProxyFactory(ob)
- >>> a = I1(p)
- >>> type(a)
- <type 'zope.security._proxy._Proxy'>
-
-While the adapter is security-proxied, the object it adapts is now
-proxy-free. The adapter has umlimited access to it:
-
- >>> a = removeSecurityProxy(a)
- >>> type(a) is A1
- True
- >>> a.context[0] is ob
- True
-
-We can also protect the trusted adapter with a permission:
-
- >>> clearZCML()
- >>> XMLConfig('meta.zcml', zope.security)()
- >>> runSnippet('''
- ... <permission
- ... id="y.x"
- ... title="XY"
- ... description="Allow XY."
- ... />
- ... <adapter
- ... for="zope.component.testfiles.components.IContent"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... permission="y.x"
- ... trusted="yes"
- ... />''')
-
-Again, with an unproxied object, it's business as usual:
-
- >>> ob = Content()
- >>> type(I1(ob)) is A1
- True
-
-With a security-proxied object, we again get a security-proxied
-adapter:
-
- >>> p = ProxyFactory(ob)
- >>> a = I1(p)
- >>> type(a)
- <type 'zope.security._proxy._Proxy'>
-
-Since we protected the adapter with a permission, we now encounter a
-location proxy behind the security proxy:
-
- >>> a = removeSecurityProxy(a)
- >>> type(a)
- <class 'zope.location.location.LocationProxy'>
- >>> a.context[0] is ob
- True
-
-There's one exception to all of this: When you use the public
-permission (``zope.Public``), there will be no location proxy:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... permission="zope.Public"
- ... trusted="yes"
- ... />''')
-
- >>> ob = Content()
- >>> p = ProxyFactory(ob)
- >>> a = I1(p)
- >>> type(a)
- <type 'zope.security._proxy._Proxy'>
-
- >>> a = removeSecurityProxy(a)
- >>> type(a) is A1
- True
-
-We can also explicitply pass the ``locate`` argument to make sure we
-get location proxies:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... trusted="yes"
- ... locate="yes"
- ... />''')
-
- >>> ob = Content()
- >>> p = ProxyFactory(ob)
- >>> a = I1(p)
- >>> type(a)
- <type 'zope.security._proxy._Proxy'>
-
- >>> a = removeSecurityProxy(a)
- >>> type(a)
- <class 'zope.location.location.LocationProxy'>
-
-
-subscriber
-----------
-
-With the <subscriber /> directive you can register subscription
-adapters or event subscribers with the adapter registry. Consider
-this very typical example of a <subscriber /> directive:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />''')
-
- >>> content = Content()
- >>> a1 = A1()
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1)
- True
-
-Note how ZCML provides some additional information when registering
-components, such as the ZCML filename and line numbers:
-
- >>> sm = zope.component.getSiteManager()
- >>> doc = [reg.info for reg in sm.registeredSubscriptionAdapters()
- ... if reg.provided is IS][0]
- >>> print doc
- File "<string>", line 4.2-9.8
- Could not read source.
-
-The "fun" behind subscription adapters/subscribers is that when
-several ones are declared for the same for/provides, they are all
-found. With regular adapters, the most specific one (and in doubt the
-one registered last) wins. Consider these two subscribers:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A2"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />''')
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> len(subscribers)
- 2
- >>> sorted([a.__class__.__name__ for a in subscribers])
- ['A2', 'A3']
-
-Declaring ``for`` and ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Like the <adapter /> directive, the <subscriber /> directive can
-figure out from the in-line Python declaration (using
-``zope.component.adapts()`` or ``zope.component.adapter()``) what the
-subscriber should be registered for:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> content = Content()
- >>> a2 = A2()
- >>> subscribers = zope.component.subscribers((content, a1, a2), IS)
-
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-In the same way the directive can figure out what a subscriber
-provides:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber handler="zope.component.testfiles.adapter.A3" />''')
-
- >>> sm = zope.component.getSiteManager()
- >>> a3 = sm.adapters.subscriptions((IContent, I1, I2), None)[0]
- >>> a3 is A3
- True
-
-A not so common edge case is declaring subscribers directly for
-classes, not for interfaces. For example:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... for="zope.component.testfiles.components.Content"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... />''')
-
- >>> subs = list(zope.component.subscribers((Content(),), I1))
- >>> isinstance(subs[0], A1)
- True
-
-This time, any object providing ``IContent`` won't work if it's not an
-instance of the ``Content`` class:
-
- >>> list(zope.component.subscribers((MyContent(),), I1))
- []
-
-Protected subscribers
-~~~~~~~~~~~~~~~~~~~~~
-
-Subscribers can also be protected with a permission. First we have to
-define a permission for which we'll have to register the <permission />
-directive:
-
- >>> clearZCML()
- >>> XMLConfig('meta.zcml', zope.security)()
- >>> runSnippet('''
- ... <permission
- ... id="y.x"
- ... title="XY"
- ... description="Allow XY."
- ... />
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... permission="y.x"
- ... />''')
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> type(a3)
- <class 'zope.location.location.LocationProxy'>
- >>> a3.context == (content, a1)
- True
-
-Trusted subscribers
-~~~~~~~~~~~~~~~~~~~
-
-Like trusted adapters, trusted subscribers are subscribers that are
-trusted to do anything with the objects they are given so that these
-objects are not security-proxied. In analogy to the <adapter />
-directive, they are registered using the ``trusted`` argument to the
-<subscriber /> directive:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... trusted="yes"
- ... />''')
-
-With an unproxied object, it's business as usual:
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1)
- True
- >>> type(a3) is A3
- True
-
-Now with a proxied object. We will see that the subscriber has
-unproxied access to it, but the subscriber itself is proxied:
-
- >>> p = ProxyFactory(content)
- >>> a3 = zope.component.subscribers((p, a1), IS)[0]
- >>> type(a3)
- <type 'zope.security._proxy._Proxy'>
-
-There's no location proxy behind the security proxy:
-
- >>> removeSecurityProxy(a3).context[0] is content
- True
- >>> type(removeSecurityProxy(a3)) is A3
- True
-
-If you want the trusted subscriber to be located, you'll also have to
-use the ``locate`` argument:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... trusted="yes"
- ... locate="yes"
- ... />''')
-
-Again, it's business as usual with an unproxied object:
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1)
- True
- >>> type(a3) is A3
- True
-
-With a proxied object, we again get a security-proxied subscriber:
-
- >>> p = ProxyFactory(content)
- >>> a3 = zope.component.subscribers((p, a1), IS)[0]
-
- >>> type(a3)
- <type 'zope.security._proxy._Proxy'>
-
- >>> removeSecurityProxy(a3).context[0] is content
- True
-
-However, thanks to the ``locate`` argument, we now have a location
-proxy behind the security proxy:
-
- >>> type(removeSecurityProxy(a3))
- <class 'zope.location.location.LocationProxy'>
-
-Event subscriber (handlers)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes, subscribers don't need to be adapters that actually provide
-anything. It's enough that a callable is called for a certain event.
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... handler="zope.component.testfiles.adapter.Handler"
- ... />''')
-
-In this case, simply getting the subscribers is enough to invoke them:
-
- >>> list(zope.component.subscribers((content, a1), None))
- []
- >>> content.args == ((a1,),)
- True
-
-
-utility
--------
-
-Apart from adapters (and subscription adapters), the Component
-Architecture knows a second kind of component: utilities. They are
-registered using the <utility /> directive.
-
-Before we register the first test utility, we can verify that utility
-lookup doesn't work yet:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
-Then we register the utility:
-
- >>> runSnippet('''
- ... <utility
- ... component="zope.component.testfiles.components.comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... />''')
- >>> zope.component.getUtility(IApp) is comp
- True
-
-Like adapters, utilities can also have names. There can be more than
-one utility registered for a certain interface, as long as they each
-have a different name.
-
-First, we make sure that there's no utility yet:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp, 'test') is None
- True
-
-Then we register it:
-
- >>> runSnippet('''
- ... <utility
- ... component="zope.component.testfiles.components.comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... name="test"
- ... />''')
- >>> zope.component.getUtility(IApp, 'test') is comp
- True
-
-Utilities can also be registered from a factory. In this case, the
-ZCML handler calls the factory (without any arguments) and registers
-the returned value as a utility. Typically, you'd pass a class for
-the factory:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
- >>> runSnippet('''
- ... <utility
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... />''')
- >>> zope.component.getUtility(IApp).__class__ is Comp
- True
-
-Declaring ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Like other directives, <utility /> can also figure out which interface
-a utility provides from the Python declaration:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.components.comp" />''')
- >>> zope.component.getUtility(IApp) is comp
- True
-
-It won't work if the component that is to be registered doesn't
-provide anything:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.adapter.a4" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
- TypeError: Missing 'provides' attribute
-
-Or if more than one interface is provided (then the ZCML directive
-handler doesn't know under which the utility should be registered):
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.adapter.a5" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
- TypeError: Missing 'provides' attribute
-
-We can repeat the same drill for utility factories:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.components.Comp" />''')
- >>> zope.component.getUtility(IApp).__class__ is Comp
- True
-
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.adapter.A4" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.59
- TypeError: Missing 'provides' attribute
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.adapter.A5" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.59
- TypeError: Missing 'provides' attribute
-
-Protected utilities
-~~~~~~~~~~~~~~~~~~~
-
-TODO::
-
- def testProtectedUtility(self):
- """Test that we can protect a utility.
-
- Also:
- Check that multiple configurations for the same utility and
- don't interfere.
- """
- self.assertEqual(zope.component.queryUtility(IV), None)
- xmlconfig(StringIO(template % (
- '''
- <permission id="tell.everyone" title="Yay" />
- <utility
- component="zope.component.testfiles.components.comp"
- provides="zope.component.testfiles.components.IApp"
- permission="tell.everyone"
- />
- <permission id="top.secret" title="shhhh" />
- <utility
- component="zope.component.testfiles.components.comp"
- provides="zope.component.testfiles.components.IAppb"
- permission="top.secret"
- />
- '''
- )))
-
- utility = ProxyFactory(zope.component.getUtility(IApp))
- items = getTestProxyItems(utility)
- self.assertEqual(items, [('a', 'tell.everyone'),
- ('f', 'tell.everyone')
- ])
- self.assertEqual(removeSecurityProxy(utility), comp)
-
- def testUtilityUndefinedPermission(self):
- config = StringIO(template % (
- '''
- <utility
- component="zope.component.testfiles.components.comp"
- provides="zope.component.testfiles.components.IApp"
- permission="zope.UndefinedPermission"
- />
- '''
- ))
- self.assertRaises(ValueError, xmlconfig, config,
- testing=1)
-
-interface
----------
-
-The <interface /> directive lets us register an interface. Interfaces
-are registered as named utilities. We therefore needn't go though all
-the lookup details again, it is sufficient to see whether the
-directive handler emits the right actions.
-
-First we provide a stub configuration context:
-
- >>> import re, pprint
- >>> atre = re.compile(' at [0-9a-fA-Fx]+')
- >>> class Context(object):
- ... actions = ()
- ... def action(self, discriminator, callable, args):
- ... self.actions += ((discriminator, callable, args), )
- ... def __repr__(self):
- ... stream = StringIO()
- ... pprinter = pprint.PrettyPrinter(stream=stream, width=60)
- ... pprinter.pprint(self.actions)
- ... r = stream.getvalue()
- ... return (''.join(atre.split(r))).strip()
- >>> context = Context()
-
-Then we provide a test interface that we'd like to register:
-
- >>> from zope.interface import Interface
- >>> class I(Interface):
- ... pass
-
-It doesn't yet provide ``ITestType``:
-
- >>> from zope.component.tests import ITestType
- >>> ITestType.providedBy(I)
- False
-
-However, after calling the directive handler...
-
- >>> from zope.component.zcml import interface
- >>> interface(context, I, ITestType)
- >>> context
- ((None,
- <function provideInterface>,
- ('',
- <InterfaceClass __builtin__.I>,
- <InterfaceClass zope.component.tests.ITestType>)),)
-
-...it does provide ``ITestType``:
-
- >>> from zope.interface.interfaces import IInterface
- >>> ITestType.extends(IInterface)
- True
- >>> IInterface.providedBy(I)
- True
Deleted: zope.component/trunk/src/zope/component/zcml_conditional.txt
===================================================================
--- zope.component/trunk/src/zope/component/zcml_conditional.txt 2012-06-29 14:47:49 UTC (rev 127191)
+++ zope.component/trunk/src/zope/component/zcml_conditional.txt 2012-06-29 14:47:56 UTC (rev 127192)
@@ -1,612 +0,0 @@
-ZCML directives without zope.security support
-=============================================
-
-This tests run without zope.security available:
-
- >>> from zope.component.zcml import check_security_support
- >>> check_security_support()
- Traceback (most recent call last):
- ...
- ConfigurationError: security proxied components are not supported because zope.security is not available
-
-Components may be registered using the registration API exposed by
-``zope.component`` (provideAdapter, provideUtility, etc.). They may
-also be registered using configuration files. The common way to do
-that is by using ZCML (Zope Configuration Markup Language), an XML
-spelling of component registration.
-
-In ZCML, each XML element is a *directive*. There are different
-top-level directives that let us register components. We will
-introduce them one by one here.
-
-This helper will let us easily execute ZCML snippets:
-
- >>> from cStringIO import StringIO
- >>> from zope.configuration.xmlconfig import xmlconfig
- >>> def runSnippet(snippet):
- ... template = """\
- ... <configure xmlns='http://namespaces.zope.org/zope'
- ... i18n_domain="zope">
- ... %s
- ... </configure>"""
- ... xmlconfig(StringIO(template % snippet))
-
-adapter
--------
-
-Adapters play a key role in the Component Architecture. In ZCML, they
-are registered with the <adapter /> directive.
-
- >>> from zope.component.testfiles.adapter import A1, A2, A3, Handler
- >>> from zope.component.testfiles.adapter import I1, I2, I3, IS
- >>> from zope.component.testfiles.components import IContent, Content, Comp, comp
-
-Before we register the first test adapter, we can verify that adapter
-lookup doesn't work yet:
-
- >>> from zope.component.tests import clearZCML
- >>> clearZCML()
- >>> from zope.component.testfiles.components import IApp
- >>> IApp(Content(), None) is None
- True
-
-Then we register the adapter and see that the lookup works:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
-
- >>> IApp(Content()).__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-It is also possible to give adapters names. Then the combination of
-required interface, provided interface and name makes the adapter
-lookup unique. The name is supplied using the ``name`` argument to
-the <adapter /> directive:
-
- >>> from zope.component.tests import clearZCML
- >>> clearZCML()
- >>> import zope.component
- >>> zope.component.queryAdapter(Content(), IApp, 'test') is None
- True
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... name="test"
- ... />''')
-
- >>> zope.component.getAdapter(Content(), IApp, 'test').__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-Adapter factories
-~~~~~~~~~~~~~~~~~
-
-It is possible to supply more than one adapter factory. In this case,
-during adapter lookup each factory will be called and the return value
-will be given to the next factory. The return value of the last
-factory is returned as the result of the adapter lookup. For examle:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2
- ... zope.component.testfiles.adapter.A3"
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
-
-The resulting adapter is an A3, around an A2, around an A1, around the
-adapted object:
-
- >>> content = Content()
- >>> a3 = IApp(content)
- >>> a3.__class__ is A3
- True
-
- >>> a2 = a3.context[0]
- >>> a2.__class__ is A2
- True
-
- >>> a1 = a2.context[0]
- >>> a1.__class__ is A1
- True
-
- >>> a1.context[0] is content
- True
-
-Of course, if no factory is provided at all, we will get an error:
-
- >>> runSnippet('''
- ... <adapter
- ... factory=""
- ... provides="zope.component.testfiles.components.IApp"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-8.8
- ValueError: No factory specified
-
-Declaring ``for`` and ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The <adapter /> directive can figure out from the in-line Python
-declaration (using ``zope.component.adapts()`` or
-``zope.component.adapter()`` as well as ``zope.interface.implements``)
-what the adapter should be registered for and what it provides::
-
- >>> clearZCML()
- >>> IApp(Content(), None) is None
- True
-
- >>> runSnippet('''
- ... <adapter factory="zope.component.testfiles.components.Comp" />''')
-
- >>> IApp(Content()).__class__
- <class 'zope.component.testfiles.components.Comp'>
-
-Of course, if the adapter has no ``implements()`` declaration, ZCML
-can't figure out what it provides:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A4"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
- TypeError: Missing 'provides' attribute
-
-On the other hand, if the factory implements more than one interface,
-ZCML can't figure out what it should provide either:
-
- >>> runSnippet('''
- ... <adapter
- ... factory="zope.component.testfiles.adapter.A5"
- ... for="zope.component.testfiles.components.IContent"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-7.8
- TypeError: Missing 'provides' attribute
-
-A not so common edge case is registering adapters directly for
-classes, not for interfaces. For example:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.Content"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... />''')
-
- >>> content = Content()
- >>> a1 = zope.component.getAdapter(content, I1, '')
- >>> isinstance(a1, A1)
- True
-
-This time, any object providing ``IContent`` won't work if it's not an
-instance of the ``Content`` class:
-
- >>> import zope.interface
- >>> class MyContent:
- ... zope.interface.implements(IContent)
- >>> zope.component.getAdapter(MyContent(), I1, '') # doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- ComponentLookupError: ...
-
-Multi-adapters
-~~~~~~~~~~~~~~
-
-Conventional adapters adapt one object to provide another interface.
-Multi-adapters adapt several objects at once:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1
- ... zope.component.testfiles.adapter.I2"
- ... provides="zope.component.testfiles.adapter.I3"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> content = Content()
- >>> a1 = A1()
- >>> a2 = A2()
- >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-You can even adapt an empty list of objects (we call this a
-null-adapter):
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for=""
- ... provides="zope.component.testfiles.adapter.I3"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> a3 = zope.component.queryMultiAdapter((), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == ()
- True
-
-Even with multi-adapters, ZCML can figure out the ``for`` and
-``provides`` parameters from the Python declarations:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter factory="zope.component.testfiles.adapter.A3" />''')
-
- >>> a3 = zope.component.queryMultiAdapter((content, a1, a2), I3)
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-Chained factories are not supported for multi-adapters, though:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1
- ... zope.component.testfiles.adapter.I2"
- ... provides="zope.component.testfiles.components.IApp"
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-11.8
- ValueError: Can't use multiple factories and multiple for
-
-And neither for null-adapters:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <adapter
- ... for=""
- ... provides="zope.component.testfiles.components.IApp"
- ... factory="zope.component.testfiles.adapter.A1
- ... zope.component.testfiles.adapter.A2"
- ... />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-9.8
- ValueError: Can't use multiple factories and multiple for
-
-subscriber
-----------
-
-With the <subscriber /> directive you can register subscription
-adapters or event subscribers with the adapter registry. Consider
-this very typical example of a <subscriber /> directive:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />''')
-
- >>> content = Content()
- >>> a1 = A1()
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1)
- True
-
-Note how ZCML provides some additional information when registering
-components, such as the ZCML filename and line numbers:
-
- >>> sm = zope.component.getSiteManager()
- >>> doc = [reg.info for reg in sm.registeredSubscriptionAdapters()
- ... if reg.provided is IS][0]
- >>> print doc
- File "<string>", line 4.2-9.8
- Could not read source.
-
-The "fun" behind subscription adapters/subscribers is that when
-several ones are declared for the same for/provides, they are all
-found. With regular adapters, the most specific one (and in doubt the
-one registered last) wins. Consider these two subscribers:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A2"
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... />''')
-
- >>> subscribers = zope.component.subscribers((content, a1), IS)
- >>> len(subscribers)
- 2
- >>> sorted([a.__class__.__name__ for a in subscribers])
- ['A2', 'A3']
-
-Declaring ``for`` and ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Like the <adapter /> directive, the <subscriber /> directive can
-figure out from the in-line Python declaration (using
-``zope.component.adapts()`` or ``zope.component.adapter()``) what the
-subscriber should be registered for:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... provides="zope.component.testfiles.adapter.IS"
- ... factory="zope.component.testfiles.adapter.A3"
- ... />''')
-
- >>> content = Content()
- >>> a2 = A2()
- >>> subscribers = zope.component.subscribers((content, a1, a2), IS)
-
- >>> a3 = subscribers[0]
- >>> a3.__class__ is A3
- True
- >>> a3.context == (content, a1, a2)
- True
-
-In the same way the directive can figure out what a subscriber
-provides:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber handler="zope.component.testfiles.adapter.A3" />''')
-
- >>> sm = zope.component.getSiteManager()
- >>> a3 = sm.adapters.subscriptions((IContent, I1, I2), None)[0]
- >>> a3 is A3
- True
-
-A not so common edge case is declaring subscribers directly for
-classes, not for interfaces. For example:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... for="zope.component.testfiles.components.Content"
- ... provides="zope.component.testfiles.adapter.I1"
- ... factory="zope.component.testfiles.adapter.A1"
- ... />''')
-
- >>> subs = list(zope.component.subscribers((Content(),), I1))
- >>> isinstance(subs[0], A1)
- True
-
-This time, any object providing ``IContent`` won't work if it's not an
-instance of the ``Content`` class:
-
- >>> list(zope.component.subscribers((MyContent(),), I1))
- []
-
-Event subscriber (handlers)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes, subscribers don't need to be adapters that actually provide
-anything. It's enough that a callable is called for a certain event.
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <subscriber
- ... for="zope.component.testfiles.components.IContent
- ... zope.component.testfiles.adapter.I1"
- ... handler="zope.component.testfiles.adapter.Handler"
- ... />''')
-
-In this case, simply getting the subscribers is enough to invoke them:
-
- >>> list(zope.component.subscribers((content, a1), None))
- []
- >>> content.args == ((a1,),)
- True
-
-
-utility
--------
-
-Apart from adapters (and subscription adapters), the Component
-Architecture knows a second kind of component: utilities. They are
-registered using the <utility /> directive.
-
-Before we register the first test utility, we can verify that utility
-lookup doesn't work yet:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
-Then we register the utility:
-
- >>> runSnippet('''
- ... <utility
- ... component="zope.component.testfiles.components.comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... />''')
- >>> zope.component.getUtility(IApp) is comp
- True
-
-Like adapters, utilities can also have names. There can be more than
-one utility registered for a certain interface, as long as they each
-have a different name.
-
-First, we make sure that there's no utility yet:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp, 'test') is None
- True
-
-Then we register it:
-
- >>> runSnippet('''
- ... <utility
- ... component="zope.component.testfiles.components.comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... name="test"
- ... />''')
- >>> zope.component.getUtility(IApp, 'test') is comp
- True
-
-Utilities can also be registered from a factory. In this case, the
-ZCML handler calls the factory (without any arguments) and registers
-the returned value as a utility. Typically, you'd pass a class for
-the factory:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
- >>> runSnippet('''
- ... <utility
- ... factory="zope.component.testfiles.components.Comp"
- ... provides="zope.component.testfiles.components.IApp"
- ... />''')
- >>> zope.component.getUtility(IApp).__class__ is Comp
- True
-
-Declaring ``provides`` in Python
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Like other directives, <utility /> can also figure out which interface
-a utility provides from the Python declaration:
-
- >>> clearZCML()
- >>> zope.component.queryUtility(IApp) is None
- True
-
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.components.comp" />''')
- >>> zope.component.getUtility(IApp) is comp
- True
-
-It won't work if the component that is to be registered doesn't
-provide anything:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.adapter.a4" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
- TypeError: Missing 'provides' attribute
-
-Or if more than one interface is provided (then the ZCML directive
-handler doesn't know under which the utility should be registered):
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility component="zope.component.testfiles.adapter.a5" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.61
- TypeError: Missing 'provides' attribute
-
-We can repeat the same drill for utility factories:
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.components.Comp" />''')
- >>> zope.component.getUtility(IApp).__class__ is Comp
- True
-
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.adapter.A4" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.59
- TypeError: Missing 'provides' attribute
-
- >>> clearZCML()
- >>> runSnippet('''
- ... <utility factory="zope.component.testfiles.adapter.A5" />''')
- Traceback (most recent call last):
- ...
- ZopeXMLConfigurationError: File "<string>", line 4.2-4.59
- TypeError: Missing 'provides' attribute
-
-interface
----------
-
-The <interface /> directive lets us register an interface. Interfaces
-are registered as named utilities. We therefore needn't go though all
-the lookup details again, it is sufficient to see whether the
-directive handler emits the right actions.
-
-First we provide a stub configuration context:
-
- >>> import re, pprint
- >>> atre = re.compile(' at [0-9a-fA-Fx]+')
- >>> class Context(object):
- ... actions = ()
- ... def action(self, discriminator, callable, args):
- ... self.actions += ((discriminator, callable, args), )
- ... def __repr__(self):
- ... stream = StringIO()
- ... pprinter = pprint.PrettyPrinter(stream=stream, width=60)
- ... pprinter.pprint(self.actions)
- ... r = stream.getvalue()
- ... return (''.join(atre.split(r))).strip()
- >>> context = Context()
-
-Then we provide a test interface that we'd like to register:
-
- >>> from zope.interface import Interface
- >>> class I(Interface):
- ... pass
-
-It doesn't yet provide ``ITestType``:
-
- >>> from zope.component.tests import ITestType
- >>> ITestType.providedBy(I)
- False
-
-However, after calling the directive handler...
-
- >>> from zope.component.zcml import interface
- >>> interface(context, I, ITestType)
- >>> context
- ((None,
- <function provideInterface>,
- ('',
- <InterfaceClass __builtin__.I>,
- <InterfaceClass zope.component.tests.ITestType>)),)
-
-...it does provide ``ITestType``:
-
- >>> from zope.interface.interfaces import IInterface
- >>> ITestType.extends(IInterface)
- True
- >>> IInterface.providedBy(I)
- True
Copied: zope.component/trunk/tox.ini (from rev 127144, zope.component/tseaver-test_cleanup/tox.ini)
===================================================================
--- zope.component/trunk/tox.ini (rev 0)
+++ zope.component/trunk/tox.ini 2012-06-29 14:47:56 UTC (rev 127192)
@@ -0,0 +1,128 @@
+[tox]
+envlist =
+# Jython support pending 2.7 support, due 2012-07-15 or so. See:
+# http://fwierzbicki.blogspot.com/2012/03/adconion-to-fund-jython-27.html
+# py26,py27,py32,jython,pypy,coverage,docs
+ py26,py26min,py27,pypy,py32,coverage,docs
+
+[testenv]
+deps =
+ zope.component
+ zope.testing
+ zope.hookable
+ ZODB3
+ zope.location
+ zope.proxy
+ zope.security
+ zope.configuration
+ zope.i18nmessageid
+commands =
+ python setup.py test -q
+
+[testenv:jython]
+commands =
+ jython setup.py test -q
+
+[nosy]
+prep =
+ pip uninstall -y zope.component
+ python -c "import shutil; shutil.copyfile('src/zope/__init__.py', '{envdir}/lib/python2.6/site-packages/zope/__init__.py')"
+ pip install -e .
+
+
+[testenv:py26min]
+basepython =
+ python2.6
+deps =
+ zope.component
+ zope.interface
+ zope.event
+ zope.hookable
+ zope.configuration
+ zope.schema
+ zope.i18nmessageid
+ nose
+commands =
+ pip uninstall -y zope.component
+ python -c "import shutil; shutil.copyfile('src/zope/__init__.py', '{envdir}/lib/python2.6/site-packages/zope/__init__.py')"
+ pip install -e .
+ nosetests -I persistentregistry -I security
+
+
+[testenv:py32]
+deps =
+ zope.component
+ zope.interface
+ zope.event
+ zope.hookable
+ zope.configuration
+ zope.schema
+ zope.i18nmessageid
+ nose
+commands =
+ pip uninstall -y zope.component
+ python -c "import shutil; shutil.copyfile('src/zope/__init__.py', '{envdir}/lib/python3.2/site-packages/zope/__init__.py')"
+ pip install -e .
+ nosetests -I persistentregistry -I security
+
+[testenv:pypy]
+deps =
+ zope.component
+ zope.interface
+ zope.event
+ zope.hookable
+ zope.configuration
+ zope.schema
+ zope.i18nmessageid
+ nose
+commands =
+ pip uninstall -y zope.component
+ python -c "import shutil; shutil.copyfile('{toxinidir}/src/zope/__init__.py', '{envdir}/site-packages/zope/__init__.py')"
+ pip install -e .
+ nosetests -I persistentregistry -I security
+
+[testenv:coverage]
+basepython =
+ python2.6
+commands =
+# The installed version messes up nose's test discovery / coverage reporting
+# So, we uninstall that from the environment, and then install the editable
+# version, before running nosetests.
+ pip uninstall -y zope.component
+ python -c "import shutil; shutil.copyfile('src/zope/__init__.py', '{envdir}/lib/python2.6/site-packages/zope/__init__.py')"
+ pip install -e .
+ nosetests --with-xunit --with-xcoverage
+deps =
+ zope.component
+ zope.testing
+ zope.hookable
+ ZODB3
+ zope.location
+ zope.proxy
+ zope.security
+ zope.configuration
+ zope.i18nmessageid
+ nose
+ coverage
+ nosexcover
+
+[testenv:docs]
+basepython =
+ python2.6
+commands =
+ sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
+ sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest
+deps =
+ zope.component
+ zope.testing
+ zope.hookable
+ ZODB3
+ zope.location
+ zope.proxy
+ zope.security
+ zope.configuration
+ zope.i18nmessageid
+ Sphinx
+ repoze.sphinx.autointerface
+# Ugh. Need this for docs/testlayer.rst
+ zope.testrunner
More information about the checkins
mailing list