tested django-newsletter
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Annotation (meta data) support
|
||||
"""
|
||||
from zope.annotation.interfaces import IAttributeAnnotatable
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.annotation.factory import factory
|
||||
@@ -0,0 +1,102 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Attribute Annotations implementation"""
|
||||
import logging
|
||||
|
||||
try:
|
||||
from collections.abc import MutableMapping as DictMixin
|
||||
except ImportError:
|
||||
# Python 2
|
||||
from collections import MutableMapping as DictMixin
|
||||
|
||||
try:
|
||||
from BTrees.OOBTree import OOBTree as _STORAGE
|
||||
except ImportError: # pragma: no cover
|
||||
logging.getLogger(__name__).warning(
|
||||
'BTrees not available: falling back to dict for attribute storage')
|
||||
_STORAGE = dict
|
||||
|
||||
from zope import component, interface
|
||||
from zope.annotation import interfaces
|
||||
|
||||
|
||||
_EMPTY_STORAGE = _STORAGE()
|
||||
|
||||
@interface.implementer(interfaces.IAnnotations)
|
||||
@component.adapter(interfaces.IAttributeAnnotatable)
|
||||
class AttributeAnnotations(DictMixin):
|
||||
"""Store annotations on an object
|
||||
|
||||
Store annotations in the `__annotations__` attribute on a
|
||||
`IAttributeAnnotatable` object.
|
||||
"""
|
||||
|
||||
# Yes, there's a lot of repetition of the `getattr` call,
|
||||
# but that turns out to be the most efficient for the ways
|
||||
# instances are typically used without sacrificing any semantics.
|
||||
# See https://github.com/zopefoundation/zope.annotation/issues/8
|
||||
# for a discussion of alternatives (which included functools.partial,
|
||||
# a closure, capturing the annotations in __init__, and versions
|
||||
# with getattr and exceptions).
|
||||
|
||||
def __init__(self, obj, context=None):
|
||||
self.obj = obj
|
||||
|
||||
@property
|
||||
def __parent__(self):
|
||||
return self.obj
|
||||
|
||||
def __bool__(self):
|
||||
return bool(getattr(self.obj, '__annotations__', 0))
|
||||
|
||||
__nonzero__ = __bool__
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""See zope.annotation.interfaces.IAnnotations"""
|
||||
annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
|
||||
return annotations.get(key, default)
|
||||
|
||||
def __getitem__(self, key):
|
||||
annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
|
||||
return annotations[key]
|
||||
|
||||
def keys(self):
|
||||
annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
|
||||
return annotations.keys()
|
||||
|
||||
def __iter__(self):
|
||||
annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
|
||||
return iter(annotations)
|
||||
|
||||
def __len__(self):
|
||||
annotations = getattr(self.obj, '__annotations__', _EMPTY_STORAGE)
|
||||
return len(annotations)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""See zope.annotation.interfaces.IAnnotations"""
|
||||
try:
|
||||
annotations = self.obj.__annotations__
|
||||
except AttributeError:
|
||||
annotations = self.obj.__annotations__ = _STORAGE()
|
||||
|
||||
annotations[key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""See zope.app.interfaces.annotation.IAnnotations"""
|
||||
try:
|
||||
annotation = self.obj.__annotations__
|
||||
except AttributeError:
|
||||
raise KeyError(key)
|
||||
|
||||
del annotation[key]
|
||||
@@ -0,0 +1,11 @@
|
||||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<include file="meta.zcml" package="zope.component" />
|
||||
|
||||
<adapter
|
||||
for=".interfaces.IAttributeAnnotatable"
|
||||
provides=".interfaces.IAnnotations"
|
||||
factory=".attribute.AttributeAnnotations"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,57 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Annotation factory helper
|
||||
"""
|
||||
import zope.component
|
||||
import zope.interface
|
||||
import zope.location.location
|
||||
import zope.location.interfaces
|
||||
import zope.proxy
|
||||
|
||||
import zope.annotation.interfaces
|
||||
|
||||
|
||||
def factory(factory, key=None):
|
||||
"""Adapter factory to help create annotations easily.
|
||||
"""
|
||||
# if no key is provided,
|
||||
# we'll determine the unique key based on the factory's dotted name
|
||||
if key is None:
|
||||
key = factory.__module__ + '.' + factory.__name__
|
||||
|
||||
adapts = zope.component.adaptedBy(factory)
|
||||
if adapts is None:
|
||||
raise TypeError("Missing 'zope.component.adapts' on annotation")
|
||||
|
||||
@zope.component.adapter(list(adapts)[0])
|
||||
@zope.interface.implementer(list(zope.component.implementedBy(factory))[0])
|
||||
def getAnnotation(context):
|
||||
annotations = zope.annotation.interfaces.IAnnotations(context)
|
||||
try:
|
||||
result = annotations[key]
|
||||
except KeyError:
|
||||
result = factory()
|
||||
annotations[key] = result
|
||||
if zope.location.interfaces.ILocation.providedBy(result):
|
||||
zope.location.location.locate(result,
|
||||
zope.proxy.removeAllProxies(context), key)
|
||||
if not (zope.location.interfaces.ILocation.providedBy(result)
|
||||
and result.__parent__ is context
|
||||
and result.__name__ == key):
|
||||
result = zope.location.location.LocationProxy(result, context, key)
|
||||
return result
|
||||
|
||||
# Convention to make adapter introspectable, used by apidoc
|
||||
getAnnotation.factory = factory
|
||||
return getAnnotation
|
||||
@@ -0,0 +1,101 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Annotations store arbitrary application data under package-unique keys.
|
||||
"""
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
from zope.interface import Interface
|
||||
|
||||
class IAnnotatable(Interface):
|
||||
"""Marker interface for objects that support storing annotations.
|
||||
|
||||
This interface says "There exists an adapter to an IAnnotations
|
||||
for an object that implements `IAnnotatable`".
|
||||
|
||||
Classes should not directly declare that they implement this interface.
|
||||
Instead they should implement an interface derived from this one, which
|
||||
details how the annotations are to be stored, such as
|
||||
`IAttributeAnnotatable`.
|
||||
"""
|
||||
|
||||
class IAnnotations(IAnnotatable):
|
||||
"""Stores arbitrary application data under package-unique keys.
|
||||
|
||||
By "package-unique keys", we mean keys that are are unique by
|
||||
virtue of including the dotted name of a package as a prefix. A
|
||||
package name is used to limit the authority for picking names for
|
||||
a package to the people using that package.
|
||||
|
||||
For example, when implementing annotations for storing Zope
|
||||
Dublin-Core meta-data, we use the key::
|
||||
|
||||
"zope.app.dublincore.ZopeDublinCore"
|
||||
|
||||
"""
|
||||
|
||||
def __nonzero__():
|
||||
"""Test whether there are any annotations
|
||||
|
||||
Must be identical to __bool__()
|
||||
"""
|
||||
|
||||
def __bool__(): # Python 3 API.
|
||||
"""Test whether there are any annotations
|
||||
|
||||
Must be identical to __nonzero__()
|
||||
"""
|
||||
|
||||
def __getitem__(key):
|
||||
"""Return the annotation stored under key.
|
||||
|
||||
Raises KeyError if key not found.
|
||||
"""
|
||||
|
||||
def get(key, default=None):
|
||||
"""Return the annotation stored under key, or default if not found.
|
||||
"""
|
||||
|
||||
def __setitem__(key, value):
|
||||
"""Store annotation under key.
|
||||
|
||||
In order to avoid key collisions, users of this interface must
|
||||
use their dotted package name as part of the key name.
|
||||
"""
|
||||
|
||||
def __delitem__(key):
|
||||
"""Removes the annotation stored under key.
|
||||
|
||||
Raises a KeyError if the key is not found.
|
||||
"""
|
||||
|
||||
def __iter__():
|
||||
"""Return an iterator for the keys in the container.
|
||||
"""
|
||||
|
||||
def __contains__(key):
|
||||
"""Return True if 'key' is in the container, else False.
|
||||
"""
|
||||
|
||||
def items():
|
||||
"""Return '(key, value)' pairs for the keys in the container.
|
||||
"""
|
||||
|
||||
class IAttributeAnnotatable(IAnnotatable):
|
||||
"""Marker indicating that annotations can be stored on an attribute.
|
||||
|
||||
This is a marker interface giving permission for an `IAnnotations`
|
||||
adapter to store data in an attribute named `__annotations__`.
|
||||
|
||||
"""
|
||||
@@ -0,0 +1 @@
|
||||
# Import this.
|
||||
@@ -0,0 +1,90 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""General Annotations Tests
|
||||
|
||||
All objects implementing 'IAnnotations' should pass these tests. They might be
|
||||
used as base tests for real implementations.
|
||||
"""
|
||||
from zope.interface.verify import verifyObject
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
|
||||
class AnnotationsTestBase(object):
|
||||
"""Test the IAnnotations interface.
|
||||
|
||||
The test case class expects the 'IAnnotations' implementer to be in
|
||||
'self.annotations'.
|
||||
"""
|
||||
|
||||
annotations = None
|
||||
obj = None
|
||||
|
||||
def test_nonzero(self):
|
||||
self.assertFalse(self.annotations)
|
||||
self.annotations['unittest'] = self.obj
|
||||
self.assertTrue(self.annotations)
|
||||
del self.annotations['unittest']
|
||||
self.assertFalse(self.annotations)
|
||||
|
||||
def testInterfaceVerifies(self):
|
||||
verifyObject(IAnnotations, self.annotations)
|
||||
|
||||
def testStorage(self):
|
||||
# test __getitem__
|
||||
self.annotations['unittest'] = self.obj
|
||||
res = self.annotations['unittest']
|
||||
self.assertEqual(self.obj, res)
|
||||
|
||||
def testGetitemException(self):
|
||||
# test __getitem__ raises exception on unknown key
|
||||
self.assertRaises(KeyError, self.annotations.__getitem__,'randomkey')
|
||||
|
||||
def testGet(self):
|
||||
# test get
|
||||
self.annotations['unittest'] = self.obj
|
||||
res = self.annotations.get('unittest')
|
||||
self.assertEqual(self.obj, res)
|
||||
|
||||
def testGetNoSet(self):
|
||||
# test get with no set
|
||||
res = self.annotations.get('randomkey')
|
||||
self.assertEqual(None, res)
|
||||
|
||||
def testGetDefault(self):
|
||||
# test get returns default
|
||||
res = self.annotations.get('randomkey', 'default')
|
||||
self.assertEqual('default', res)
|
||||
|
||||
def testDel(self):
|
||||
self.annotations['unittest'] = self.obj
|
||||
del self.annotations['unittest']
|
||||
self.assertEqual(None, self.annotations.get('unittest'))
|
||||
self.assertEqual([], list(self.annotations.keys()))
|
||||
self.assertEqual([], list(self.annotations))
|
||||
self.assertEqual(0, len(self.annotations))
|
||||
|
||||
def testDelRaisesKeyError(self):
|
||||
self.assertRaises(KeyError, self.annotations.__delitem__, 'unittest')
|
||||
|
||||
def testKeys(self):
|
||||
self.assertEqual([], list(self.annotations.keys()))
|
||||
self.annotations['unittest'] = self.obj
|
||||
self.assertEqual(1, len(self.annotations))
|
||||
self.assertEqual(['unittest'], list(self.annotations.keys()))
|
||||
|
||||
def testIter(self):
|
||||
self.assertEqual([], list(self.annotations))
|
||||
self.annotations['unittest'] = self.obj
|
||||
self.assertEqual(1, len(self.annotations))
|
||||
self.assertEqual(['unittest'], list(self.annotations))
|
||||
self.assertEqual(1, len(self.annotations))
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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 unittest
|
||||
|
||||
from zope.annotation.tests.annotations import AnnotationsTestBase
|
||||
|
||||
class AttributeAnnotationsTest(AnnotationsTestBase, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
from zope.testing import cleanup
|
||||
from zope.interface import implementer
|
||||
from zope.annotation.attribute import AttributeAnnotations
|
||||
from zope.annotation.interfaces import IAttributeAnnotatable
|
||||
|
||||
cleanup.setUp()
|
||||
|
||||
@implementer(IAttributeAnnotatable)
|
||||
class Dummy(object):
|
||||
pass
|
||||
|
||||
self.obj = Dummy()
|
||||
self.annotations = AttributeAnnotations(self.obj)
|
||||
|
||||
def tearDown(self):
|
||||
from zope.testing import cleanup
|
||||
cleanup.tearDown()
|
||||
|
||||
def testInterfaceVerifies(self):
|
||||
super(AttributeAnnotationsTest, self).testInterfaceVerifies()
|
||||
self.assertIs(self.obj, self.annotations.__parent__)
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||
@@ -0,0 +1,43 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2011 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 unittest
|
||||
|
||||
|
||||
class ZCMLTest(unittest.TestCase):
|
||||
|
||||
def test_configure_zcml_should_be_loadable(self):
|
||||
from zope.configuration.xmlconfig import XMLConfig
|
||||
import zope.annotation as MUT
|
||||
|
||||
XMLConfig('configure.zcml', MUT)()
|
||||
|
||||
def test_configure_should_register_n_components(self):
|
||||
from zope.component import getGlobalSiteManager
|
||||
from zope.configuration.xmlconfig import XMLConfig
|
||||
import zope.annotation as MUT
|
||||
|
||||
gsm = getGlobalSiteManager()
|
||||
u_count = len(list(gsm.registeredUtilities()))
|
||||
a_count = len(list(gsm.registeredAdapters()))
|
||||
s_count = len(list(gsm.registeredSubscriptionAdapters()))
|
||||
h_count = len(list(gsm.registeredHandlers()))
|
||||
|
||||
XMLConfig( 'configure.zcml', MUT)()
|
||||
|
||||
self.assertEqual(u_count + 2, len(list(gsm.registeredUtilities())))
|
||||
self.assertEqual(a_count + 1, len(list(gsm.registeredAdapters())))
|
||||
self.assertEqual(
|
||||
s_count, len(list(gsm.registeredSubscriptionAdapters())))
|
||||
self.assertEqual(h_count, len(list(gsm.registeredHandlers())))
|
||||
@@ -0,0 +1,120 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2017 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 unittest
|
||||
|
||||
from zope.annotation import factory
|
||||
|
||||
from zope import interface
|
||||
from zope import component
|
||||
from zope.location.interfaces import ILocation
|
||||
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
|
||||
|
||||
class ITarget(interface.Interface):
|
||||
pass
|
||||
|
||||
class IContext(IAnnotations):
|
||||
pass
|
||||
|
||||
@interface.implementer(ITarget)
|
||||
@component.adapter(IContext)
|
||||
class Target(object):
|
||||
pass
|
||||
|
||||
@interface.implementer(IContext)
|
||||
class Context(dict):
|
||||
pass
|
||||
|
||||
class TestFactory(unittest.TestCase):
|
||||
|
||||
assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
|
||||
getattr(unittest.TestCase, 'assertRaisesRegexp'))
|
||||
|
||||
def test_no_adapts(self):
|
||||
self.assertRaisesRegex(TypeError, "Missing.*on annotation",
|
||||
factory, TestFactory)
|
||||
|
||||
def test_factory_no_location(self):
|
||||
|
||||
getAnnotation = factory(Target)
|
||||
|
||||
context = Context()
|
||||
target = getAnnotation(context)
|
||||
|
||||
# Several things have happened now.
|
||||
# First, we have an annotation, derived from
|
||||
# our class name
|
||||
key = 'zope.annotation.tests.test_factory.Target'
|
||||
self.assertEqual([key],
|
||||
list(context))
|
||||
|
||||
# Second, a target object is stored at that location.
|
||||
self.assertEqual(type(context[key]), Target)
|
||||
|
||||
# Third, the returned object is an ILocation, rooted at the
|
||||
# parent and having the given name.
|
||||
self.assertTrue(ILocation.providedBy(target))
|
||||
self.assertIs(target.__parent__, context)
|
||||
self.assertEqual(target.__name__, key)
|
||||
|
||||
# But it's a proxy.
|
||||
self.assertNotEqual(type(target), Target)
|
||||
self.assertTrue(ITarget.providedBy(target))
|
||||
|
||||
def test_factory_location(self):
|
||||
# Given an object that is a location,
|
||||
# it is not proxied
|
||||
@interface.implementer(ILocation)
|
||||
class LocatedTarget(Target):
|
||||
__name__ = None
|
||||
__parent__ = None
|
||||
|
||||
getAnnotation = factory(LocatedTarget)
|
||||
|
||||
context = Context()
|
||||
target = getAnnotation(context)
|
||||
|
||||
key = 'zope.annotation.tests.test_factory.LocatedTarget'
|
||||
self.assertEqual([key],
|
||||
list(context))
|
||||
|
||||
# Second, a target object is stored at that location.
|
||||
self.assertEqual(type(context[key]), LocatedTarget)
|
||||
|
||||
# Third, the returned object is an ILocation, rooted at the
|
||||
# parent and having the given name.
|
||||
self.assertTrue(ILocation.providedBy(target))
|
||||
self.assertIs(target.__parent__, context)
|
||||
self.assertEqual(target.__name__, key)
|
||||
|
||||
# And it's not a proxy.
|
||||
self.assertEqual(type(target), LocatedTarget)
|
||||
self.assertTrue(ITarget.providedBy(target))
|
||||
self.assertIs(target, context[key])
|
||||
|
||||
def test_factory_with_key(self):
|
||||
|
||||
key = 'testkey'
|
||||
getAnnotation = factory(Target, key)
|
||||
|
||||
context = Context()
|
||||
getAnnotation(context)
|
||||
|
||||
self.assertEqual([key],
|
||||
list(context))
|
||||
|
||||
# Second, a target object is stored at that location.
|
||||
self.assertEqual(type(context[key]), Target)
|
||||
@@ -0,0 +1,96 @@
|
||||
============
|
||||
Interfaces
|
||||
============
|
||||
|
||||
This package defines several basic interfaces.
|
||||
|
||||
.. currentmodule:: zope.browser.interfaces
|
||||
|
||||
IView
|
||||
=====
|
||||
|
||||
Views adapt both a context and a request.
|
||||
|
||||
There is not much we can test except that ``IView`` is importable
|
||||
and an interface:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.browser.interfaces import IView
|
||||
>>> Interface.providedBy(IView)
|
||||
True
|
||||
|
||||
.. autointerface:: IView
|
||||
|
||||
IBrowserView
|
||||
============
|
||||
|
||||
Browser views are views specialized for requests from a browser (e.g.,
|
||||
as distinct from WebDAV, FTP, XML-RPC, etc.).
|
||||
|
||||
There is not much we can test except that ``IBrowserView`` is importable
|
||||
and an interface derived from :class:`IView`:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.browser.interfaces import IBrowserView
|
||||
>>> Interface.providedBy(IBrowserView)
|
||||
True
|
||||
>>> IBrowserView.extends(IView)
|
||||
True
|
||||
|
||||
.. autointerface:: IBrowserView
|
||||
|
||||
IAdding
|
||||
=======
|
||||
|
||||
Adding views manage how newly-created items get added to containers.
|
||||
|
||||
There is not much we can test except that ``IAdding`` is importable
|
||||
and an interface derived from :class:`IBrowserView`:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.browser.interfaces import IAdding
|
||||
>>> Interface.providedBy(IBrowserView)
|
||||
True
|
||||
>>> IAdding.extends(IBrowserView)
|
||||
True
|
||||
|
||||
.. autointerface:: IAdding
|
||||
|
||||
ITerms
|
||||
======
|
||||
|
||||
The ``ITerms`` interface is used as a base for ``ISource`` widget
|
||||
implementations. This interfaces get used by ``zope.app.form`` and was
|
||||
initially defined in ``zope.app.form.browser.interfaces``, which made it
|
||||
impossible to use for other packages like ``z3c.form`` wihtout depending on
|
||||
``zope.app.form``.
|
||||
|
||||
Moving such base components / interfaces to ``zope.browser`` makes it
|
||||
possible to share them without undesirable dependencies.
|
||||
|
||||
There is not much we can test except that ITerms is importable
|
||||
and an interface:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.browser.interfaces import ITerms
|
||||
>>> Interface.providedBy(ITerms)
|
||||
True
|
||||
|
||||
.. autointerface:: ITerms
|
||||
|
||||
ISystemErrorView
|
||||
================
|
||||
|
||||
Views providing this interface can classify their contexts as system
|
||||
errors. These errors can be handled in a special way (e. g. more
|
||||
detailed logging).
|
||||
|
||||
There is not much we can test except that ``ISystemErrorView`` is importable
|
||||
and an interface:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> from zope.browser.interfaces import ISystemErrorView
|
||||
>>> Interface.providedBy(ISystemErrorView)
|
||||
True
|
||||
|
||||
.. autointerface:: ISystemErrorView
|
||||
@@ -0,0 +1 @@
|
||||
# make a package
|
||||
@@ -0,0 +1,112 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004-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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Shared dependency less Zope3 brwoser components.
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
|
||||
class IView(Interface):
|
||||
""" Views are multi-adapters for context and request objects.
|
||||
"""
|
||||
context = Attribute("The context object the view renders")
|
||||
request = Attribute("The request object driving the view")
|
||||
|
||||
class IBrowserView(IView):
|
||||
""" Views which are specialized for requests from a browser
|
||||
|
||||
Such views are distinct from those geerated via WebDAV, FTP, XML-RPC,
|
||||
etc.
|
||||
"""
|
||||
|
||||
class IAdding(IBrowserView):
|
||||
""" Multi-adapter interface for views which add items to containers.
|
||||
|
||||
The 'context' of the view must implement :obj:`zope.container.interfaces.IContainer`.
|
||||
"""
|
||||
|
||||
def add(content):
|
||||
"""Add content object to context.
|
||||
|
||||
Add using the name in ``contentName``.
|
||||
|
||||
Return the added object in the context of its container.
|
||||
|
||||
If ``contentName`` is already used in container, raise
|
||||
:class:`zope.container.interfaces.DuplicateIDError`.
|
||||
"""
|
||||
|
||||
contentName = Attribute(
|
||||
"""The content name, usually set by the Adder traverser.
|
||||
|
||||
If the content name hasn't been defined yet, returns ``None``.
|
||||
|
||||
Some creation views might use this to optionally display the
|
||||
name on forms.
|
||||
"""
|
||||
)
|
||||
|
||||
def nextURL():
|
||||
"""Return the URL that the creation view should redirect to.
|
||||
|
||||
This is called by the creation view after calling add.
|
||||
|
||||
It is the adder's responsibility, not the creation view's to
|
||||
decide what page to display after content is added.
|
||||
"""
|
||||
|
||||
def nameAllowed():
|
||||
"""Return whether names can be input by the user.
|
||||
"""
|
||||
|
||||
def addingInfo():
|
||||
"""Return add menu data as a sequence of mappings.
|
||||
|
||||
Each mapping contains 'action', 'title', and possibly other keys.
|
||||
|
||||
The result is sorted by title.
|
||||
"""
|
||||
|
||||
def isSingleMenuItem():
|
||||
"""Return whether there is single menu item or not."""
|
||||
|
||||
def hasCustomAddView():
|
||||
"This should be called only if there is ``singleMenuItem`` else return 0"
|
||||
|
||||
|
||||
class ITerms(Interface):
|
||||
""" Adapter providing lookups for vocabulary terms.
|
||||
"""
|
||||
def getTerm(value):
|
||||
"""Return an ITitledTokenizedTerm object for the given value
|
||||
|
||||
LookupError is raised if the value isn't in the source.
|
||||
|
||||
The return value should have the ``token`` and ``title`` attributes.
|
||||
"""
|
||||
|
||||
def getValue(token):
|
||||
"""Return a value for a given identifier token
|
||||
|
||||
LookupError is raised if there isn't a value in the source.
|
||||
"""
|
||||
|
||||
class ISystemErrorView(Interface):
|
||||
"""Error views that can classify their contexts as system errors
|
||||
"""
|
||||
|
||||
def isSystemError():
|
||||
"""Return a boolean indicating whether the error is a system errror
|
||||
"""
|
||||
@@ -0,0 +1,29 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2007 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test Suite"""
|
||||
import doctest
|
||||
import unittest
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
doctest.DocFileSuite(
|
||||
'README.rst',
|
||||
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
|
||||
),
|
||||
))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='test_suite')
|
||||
@@ -0,0 +1 @@
|
||||
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
|
||||
@@ -0,0 +1,21 @@
|
||||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<class class=".viewpagetemplatefile.BoundPageTemplate">
|
||||
<allow attributes="__call__ __str__ __name__" />
|
||||
</class>
|
||||
|
||||
<adapter
|
||||
for="zope.browserpage.viewpagetemplatefile.BoundPageTemplate
|
||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||
provides="zope.publisher.interfaces.browser.IBrowserPublisher"
|
||||
factory="zope.browserpage.viewpagetemplatefile.NoTraverser"
|
||||
/>
|
||||
|
||||
<!-- TALES namespace allows view/template:default etc -->
|
||||
<adapter
|
||||
for="*"
|
||||
factory=".namedtemplate.NamedTemplatePathAdapter"
|
||||
name="template"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,53 @@
|
||||
<configure xmlns:meta="http://namespaces.zope.org/meta">
|
||||
|
||||
<meta:directives namespace="http://namespaces.zope.org/browser">
|
||||
|
||||
<meta:directive
|
||||
name="page"
|
||||
schema=".metadirectives.IPageDirective"
|
||||
handler=".metaconfigure.page"
|
||||
/>
|
||||
|
||||
<meta:complexDirective
|
||||
name="pages"
|
||||
schema=".metadirectives.IPagesDirective"
|
||||
handler=".metaconfigure.pages"
|
||||
>
|
||||
|
||||
<meta:subdirective
|
||||
name="page"
|
||||
schema=".metadirectives.IPagesPageSubdirective"
|
||||
/>
|
||||
|
||||
</meta:complexDirective>
|
||||
|
||||
<meta:complexDirective
|
||||
name="view"
|
||||
schema=".metadirectives.IViewDirective"
|
||||
handler=".metaconfigure.view"
|
||||
>
|
||||
|
||||
<meta:subdirective
|
||||
name="page"
|
||||
schema=".metadirectives.IViewPageSubdirective"
|
||||
/>
|
||||
|
||||
<meta:subdirective
|
||||
name="defaultPage"
|
||||
schema=".metadirectives.IViewDefaultPageSubdirective"
|
||||
/>
|
||||
|
||||
</meta:complexDirective>
|
||||
|
||||
</meta:directives>
|
||||
|
||||
<meta:directives namespace="http://namespaces.zope.org/tales">
|
||||
|
||||
<meta:directive name="expressiontype"
|
||||
schema=".metadirectives.IExpressionTypeDirective"
|
||||
handler=".metaconfigure.expressiontype"
|
||||
/>
|
||||
|
||||
</meta:directives>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,459 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Browser page ZCML configuration code
|
||||
"""
|
||||
import os
|
||||
|
||||
from zope.component import queryMultiAdapter
|
||||
from zope.component.interface import provideInterface
|
||||
from zope.component.zcml import handler
|
||||
from zope.interface import implementer, classImplements, Interface
|
||||
from zope.publisher.interfaces import NotFound
|
||||
from zope.security.checker import CheckerPublic, Checker, defineChecker
|
||||
from zope.configuration.exceptions import ConfigurationError
|
||||
from zope.pagetemplate.engine import Engine
|
||||
from zope.pagetemplate.engine import _Engine
|
||||
from zope.pagetemplate.engine import TrustedEngine
|
||||
from zope.pagetemplate.engine import _TrustedEngine
|
||||
from zope.publisher.interfaces.browser import IBrowserRequest
|
||||
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
|
||||
from zope.publisher.interfaces.browser import IBrowserPublisher
|
||||
from zope.publisher.browser import BrowserView
|
||||
|
||||
from zope.browserpage.simpleviewclass import SimpleViewClass
|
||||
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
|
||||
|
||||
def _fallbackMenuItemDirective(_context, *args, **kwargs):
|
||||
import warnings
|
||||
warnings.warn_explicit(
|
||||
'Page directive used with "menu" argument, while "zope.browsermenu" '
|
||||
'package is not installed. Doing nothing.',
|
||||
UserWarning,
|
||||
_context.info.file, _context.info.line)
|
||||
return []
|
||||
|
||||
try:
|
||||
from zope.browsermenu.metaconfigure import menuItemDirective
|
||||
except ImportError: # pragma: no cover
|
||||
menuItemDirective = _fallbackMenuItemDirective
|
||||
|
||||
# There are three cases we want to suport:
|
||||
#
|
||||
# Named view without pages (single-page view)
|
||||
#
|
||||
# <browser:page
|
||||
# for=".IContact.IContactInfo."
|
||||
# name="info.html"
|
||||
# template="info.pt"
|
||||
# class=".ContactInfoView."
|
||||
# permission="zope.View"
|
||||
# />
|
||||
#
|
||||
# Unnamed view with pages (multi-page view)
|
||||
#
|
||||
# <browser:pages
|
||||
# for=".IContact."
|
||||
# class=".ContactEditView."
|
||||
# permission="ZopeProducts.Contact.ManageContacts"
|
||||
# >
|
||||
#
|
||||
# <browser:page name="edit.html" template="edit.pt" />
|
||||
# <browser:page name="editAction.html" attribute="action" />
|
||||
# </browser:pages>
|
||||
#
|
||||
# Named view with pages (add view is a special case of this)
|
||||
#
|
||||
# <browser:view
|
||||
# name="ZopeProducts.Contact"
|
||||
# for="Zope.App.OFS.Container.IAdding."
|
||||
# class=".ContactAddView."
|
||||
# permission="ZopeProducts.Contact.ManageContacts"
|
||||
# >
|
||||
#
|
||||
# <browser:page name="add.html" template="add.pt" />
|
||||
# <browser:page name="action.html" attribute="action" />
|
||||
# </browser:view>
|
||||
|
||||
# We'll also provide a convenience directive for add views:
|
||||
#
|
||||
# <browser:add
|
||||
# name="ZopeProducts.Contact"
|
||||
# class=".ContactAddView."
|
||||
# permission="ZopeProducts.Contact.ManageContacts"
|
||||
# >
|
||||
#
|
||||
# <browser:page name="add.html" template="add.pt" />
|
||||
# <browser:page name="action.html" attribute="action" />
|
||||
# </browser:view>
|
||||
|
||||
# page
|
||||
|
||||
def _norm_template(_context, template):
|
||||
template = os.path.abspath(str(_context.path(template)))
|
||||
if not os.path.isfile(template):
|
||||
raise ConfigurationError("No such file", template)
|
||||
return template
|
||||
|
||||
|
||||
def page(_context, name, permission, for_=Interface,
|
||||
layer=IDefaultBrowserLayer, template=None, class_=None,
|
||||
allowed_interface=None, allowed_attributes=None,
|
||||
attribute='__call__', menu=None, title=None):
|
||||
_handle_menu(_context, menu, title, [for_], name, permission, layer)
|
||||
required = {}
|
||||
|
||||
permission = _handle_permission(_context, permission)
|
||||
|
||||
if not (class_ or template):
|
||||
raise ConfigurationError("Must specify a class or template")
|
||||
|
||||
if attribute != '__call__':
|
||||
if template:
|
||||
raise ConfigurationError(
|
||||
"Attribute and template cannot be used together.")
|
||||
|
||||
assert class_, "Must have class if attribute is used"
|
||||
|
||||
if template:
|
||||
template = _norm_template(_context, template)
|
||||
required['__getitem__'] = permission
|
||||
|
||||
# TODO: new __name__ attribute must be tested
|
||||
if class_:
|
||||
if attribute != '__call__':
|
||||
if not hasattr(class_, attribute):
|
||||
raise ConfigurationError(
|
||||
"The provided class doesn't have the specified attribute "
|
||||
)
|
||||
if template:
|
||||
# class and template
|
||||
new_class = SimpleViewClass(template, bases=(class_, ), name=name)
|
||||
else:
|
||||
if not hasattr(class_, 'browserDefault'):
|
||||
cdict = {
|
||||
'browserDefault':
|
||||
lambda self, request: (getattr(self, attribute), ())
|
||||
}
|
||||
else:
|
||||
cdict = {}
|
||||
|
||||
cdict['__name__'] = name
|
||||
cdict['__page_attribute__'] = attribute
|
||||
new_class = type(class_.__name__, (class_, simple,), cdict)
|
||||
|
||||
if hasattr(class_, '__implements__'):
|
||||
classImplements(new_class, IBrowserPublisher)
|
||||
|
||||
else:
|
||||
# template
|
||||
new_class = SimpleViewClass(template, name=name)
|
||||
|
||||
for n in (attribute, 'browserDefault', '__call__', 'publishTraverse'):
|
||||
required[n] = permission
|
||||
|
||||
_handle_allowed_interface(_context, allowed_interface, permission,
|
||||
required)
|
||||
_handle_allowed_attributes(_context, allowed_attributes, permission,
|
||||
required)
|
||||
|
||||
_handle_for(_context, for_)
|
||||
|
||||
defineChecker(new_class, Checker(required))
|
||||
|
||||
_context.action(
|
||||
discriminator=('view', (for_, layer), name, IBrowserRequest),
|
||||
callable=handler,
|
||||
args=('registerAdapter',
|
||||
new_class, (for_, layer), Interface, name, _context.info),
|
||||
)
|
||||
|
||||
|
||||
# pages, which are just a short-hand for multiple page directives.
|
||||
|
||||
# Note that a class might want to access one of the defined
|
||||
# templates. If it does though, it should use getMultiAdapter.
|
||||
|
||||
class pages(object):
|
||||
|
||||
def __init__(self, _context, permission, for_=Interface,
|
||||
layer=IDefaultBrowserLayer, class_=None,
|
||||
allowed_interface=None, allowed_attributes=None):
|
||||
self.opts = dict(
|
||||
for_=for_, permission=permission,
|
||||
layer=layer, class_=class_,
|
||||
allowed_interface=allowed_interface,
|
||||
allowed_attributes=allowed_attributes,
|
||||
)
|
||||
|
||||
def page(self, _context, name, attribute='__call__', template=None,
|
||||
menu=None, title=None):
|
||||
return page(_context,
|
||||
name=name,
|
||||
attribute=attribute,
|
||||
template=template,
|
||||
menu=menu, title=title,
|
||||
**(self.opts))
|
||||
|
||||
def __call__(self):
|
||||
return ()
|
||||
|
||||
# view (named view with pages)
|
||||
|
||||
# This is a different case. We actually build a class with attributes
|
||||
# for all of the given pages.
|
||||
|
||||
class view(object):
|
||||
|
||||
default = None
|
||||
|
||||
def __init__(self, _context, permission, for_=Interface,
|
||||
name='', layer=IDefaultBrowserLayer, class_=None,
|
||||
allowed_interface=None, allowed_attributes=None,
|
||||
menu=None, title=None, provides=Interface):
|
||||
|
||||
_handle_menu(_context, menu, title, [for_], name, permission, layer)
|
||||
|
||||
permission = _handle_permission(_context, permission)
|
||||
|
||||
self.args = (_context, name, (for_, layer), permission, class_,
|
||||
allowed_interface, allowed_attributes)
|
||||
|
||||
self.pages = []
|
||||
self.menu = menu
|
||||
self.provides = provides
|
||||
|
||||
def page(self, _context, name, attribute=None, template=None):
|
||||
if template:
|
||||
template = _norm_template(_context, template)
|
||||
else:
|
||||
if not attribute:
|
||||
raise ConfigurationError(
|
||||
"Must specify either a template or an attribute name")
|
||||
|
||||
self.pages.append((name, attribute, template))
|
||||
return ()
|
||||
|
||||
def defaultPage(self, _context, name):
|
||||
self.default = name
|
||||
return ()
|
||||
|
||||
def __call__(self):
|
||||
(_context, name, (for_, layer), permission, class_,
|
||||
allowed_interface, allowed_attributes) = self.args
|
||||
|
||||
required = {}
|
||||
|
||||
cdict = {}
|
||||
pages = {}
|
||||
|
||||
for pname, attribute, template in self.pages:
|
||||
|
||||
if template:
|
||||
cdict[pname] = ViewPageTemplateFile(template)
|
||||
if attribute and attribute != name:
|
||||
cdict[attribute] = cdict[pname]
|
||||
else:
|
||||
if not hasattr(class_, attribute):
|
||||
raise ConfigurationError("Undefined attribute",
|
||||
attribute)
|
||||
|
||||
attribute = attribute or pname
|
||||
required[pname] = permission
|
||||
|
||||
pages[pname] = attribute
|
||||
|
||||
# This should go away, but noone seems to remember what to do. :-(
|
||||
if hasattr(class_, 'publishTraverse'):
|
||||
|
||||
def publishTraverse(self, request, name,
|
||||
pages=pages, getattr=getattr):
|
||||
|
||||
if name in pages:
|
||||
return getattr(self, pages[name])
|
||||
view = queryMultiAdapter((self, request), name=name)
|
||||
if view is not None:
|
||||
return view
|
||||
|
||||
m = class_.publishTraverse.__get__(self)
|
||||
return m(request, name)
|
||||
|
||||
else:
|
||||
def publishTraverse(self, request, name,
|
||||
pages=pages, getattr=getattr):
|
||||
|
||||
if name in pages:
|
||||
return getattr(self, pages[name])
|
||||
view = queryMultiAdapter((self, request), name=name)
|
||||
if view is not None:
|
||||
return view
|
||||
|
||||
raise NotFound(self, name, request)
|
||||
|
||||
cdict['publishTraverse'] = publishTraverse
|
||||
|
||||
if not hasattr(class_, 'browserDefault'):
|
||||
if self.default or self.pages:
|
||||
_default = self.default or self.pages[0][0]
|
||||
cdict['browserDefault'] = (
|
||||
lambda self, request, default=_default:
|
||||
(self, (default, ))
|
||||
)
|
||||
elif providesCallable(class_):
|
||||
cdict['browserDefault'] = (
|
||||
lambda self, request: (self, ())
|
||||
)
|
||||
|
||||
bases = (simple,) if class_ is None else (class_, simple)
|
||||
|
||||
try:
|
||||
cname = str(name)
|
||||
except Exception: # pragma: no cover
|
||||
cname = "GeneratedClass"
|
||||
|
||||
cdict['__name__'] = name
|
||||
newclass = type(cname, bases, cdict)
|
||||
|
||||
for n in ('publishTraverse', 'browserDefault', '__call__'):
|
||||
required[n] = permission
|
||||
|
||||
_handle_allowed_interface(_context, allowed_interface, permission,
|
||||
required)
|
||||
_handle_allowed_attributes(_context, allowed_attributes, permission,
|
||||
required)
|
||||
_handle_for(_context, for_)
|
||||
|
||||
defineChecker(newclass, Checker(required))
|
||||
|
||||
if self.provides is not None:
|
||||
_context.action(
|
||||
discriminator=None,
|
||||
callable=provideInterface,
|
||||
args=('', self.provides)
|
||||
)
|
||||
|
||||
_context.action(
|
||||
discriminator=('view', (for_, layer), name, self.provides),
|
||||
callable=handler,
|
||||
args=('registerAdapter',
|
||||
newclass, (for_, layer), self.provides, name,
|
||||
_context.info),
|
||||
)
|
||||
|
||||
def _handle_menu(_context, menu, title, for_, name, permission,
|
||||
layer=IDefaultBrowserLayer):
|
||||
if not menu and not title:
|
||||
# Neither of them
|
||||
return []
|
||||
|
||||
if not menu or not title:
|
||||
# Only one or the other
|
||||
raise ConfigurationError(
|
||||
"If either menu or title are specified, they must "
|
||||
"both be specified.")
|
||||
|
||||
if len(for_) != 1:
|
||||
raise ConfigurationError(
|
||||
"Menus can be specified only for single-view, not for "
|
||||
"multi-views.")
|
||||
|
||||
return menuItemDirective(
|
||||
_context, menu, for_[0], '@@' + name, title,
|
||||
permission=permission, layer=layer)
|
||||
|
||||
|
||||
def _handle_permission(_context, permission):
|
||||
if permission == 'zope.Public':
|
||||
permission = CheckerPublic
|
||||
|
||||
return permission
|
||||
|
||||
def _handle_allowed_interface(_context, allowed_interface, permission,
|
||||
required):
|
||||
# Allow access for all names defined by named interfaces
|
||||
if allowed_interface:
|
||||
for i in allowed_interface:
|
||||
_context.action(
|
||||
discriminator=None,
|
||||
callable=provideInterface,
|
||||
args=(None, i)
|
||||
)
|
||||
|
||||
for name in i:
|
||||
required[name] = permission
|
||||
|
||||
def _handle_allowed_attributes(_context, allowed_attributes, permission,
|
||||
required):
|
||||
# Allow access for all named attributes
|
||||
if allowed_attributes:
|
||||
for name in allowed_attributes:
|
||||
required[name] = permission
|
||||
|
||||
def _handle_for(_context, for_):
|
||||
if for_ is not None:
|
||||
_context.action(
|
||||
discriminator=None,
|
||||
callable=provideInterface,
|
||||
args=('', for_)
|
||||
)
|
||||
|
||||
@implementer(IBrowserPublisher)
|
||||
class simple(BrowserView):
|
||||
|
||||
def publishTraverse(self, request, name):
|
||||
raise NotFound(self, name, request)
|
||||
|
||||
def __call__(self, *a, **k):
|
||||
# If a class doesn't provide it's own call, then get the attribute
|
||||
# given by the browser default.
|
||||
|
||||
attr = self.__page_attribute__
|
||||
if attr == '__call__':
|
||||
raise AttributeError("__call__")
|
||||
|
||||
meth = getattr(self, attr)
|
||||
return meth(*a, **k)
|
||||
|
||||
def providesCallable(class_):
|
||||
if hasattr(class_, '__call__'):
|
||||
for c in class_.__mro__:
|
||||
if '__call__' in c.__dict__:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def expressiontype(_context, name, handler):
|
||||
_context.action(
|
||||
discriminator=("tales:expressiontype", name),
|
||||
callable=registerType,
|
||||
args=(name, handler)
|
||||
)
|
||||
|
||||
def registerType(name, handler):
|
||||
Engine.registerType(name, handler)
|
||||
TrustedEngine.registerType(name, handler)
|
||||
|
||||
|
||||
def clear():
|
||||
Engine.__init__()
|
||||
_Engine(Engine)
|
||||
TrustedEngine.__init__()
|
||||
_TrustedEngine(TrustedEngine)
|
||||
|
||||
|
||||
try:
|
||||
from zope.testing.cleanup import addCleanUp
|
||||
except ImportError: # pragma: no cover
|
||||
pass
|
||||
else:
|
||||
addCleanUp(clear)
|
||||
@@ -0,0 +1,211 @@
|
||||
#############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""ZCML directives for defining browser pages
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.configuration.fields import GlobalObject, GlobalInterface
|
||||
from zope.configuration.fields import Path, PythonIdentifier, MessageID
|
||||
from zope.schema import TextLine
|
||||
from zope.security.zcml import Permission
|
||||
|
||||
from zope.component.zcml import IBasicViewInformation
|
||||
|
||||
try:
|
||||
from zope.browsermenu.field import MenuField
|
||||
except ImportError: # avoid hard dependency on zope.browsermenu pragma: no cover
|
||||
MenuField = TextLine
|
||||
|
||||
|
||||
class IPagesDirective(IBasicViewInformation):
|
||||
"""
|
||||
Define multiple pages without repeating all of the parameters.
|
||||
|
||||
The pages directive allows multiple page views to be defined
|
||||
without repeating the 'for', 'permission', 'class', 'layer',
|
||||
'allowed_attributes', and 'allowed_interface' attributes.
|
||||
"""
|
||||
|
||||
for_ = GlobalObject(
|
||||
title=u"The interface or class this view is for.",
|
||||
required=False
|
||||
)
|
||||
|
||||
layer = GlobalObject(
|
||||
title=u"The request interface or class this view is for.",
|
||||
description=
|
||||
u"Defaults to zope.publisher.interfaces.browser.IDefaultBrowserLayer.",
|
||||
required=False
|
||||
)
|
||||
|
||||
permission = Permission(
|
||||
title=u"Permission",
|
||||
description=u"The permission needed to use the view.",
|
||||
required=True
|
||||
)
|
||||
|
||||
class IViewDirective(IPagesDirective):
|
||||
"""
|
||||
The view directive defines a view that has subpages.
|
||||
|
||||
The pages provided by the defined view are accessed by first
|
||||
traversing to the view name and then traversing to the page name.
|
||||
"""
|
||||
|
||||
for_ = GlobalInterface(
|
||||
title=u"The interface this view is for.",
|
||||
required=False
|
||||
)
|
||||
|
||||
name = TextLine(
|
||||
title=u"The name of the view.",
|
||||
description=u"The name shows up in URLs/paths. For example 'foo'.",
|
||||
required=False,
|
||||
default=u'',
|
||||
)
|
||||
|
||||
menu = MenuField(
|
||||
title=u"The browser menu to include the page (view) in.",
|
||||
description=u"""
|
||||
Many views are included in menus. It's convenient to name
|
||||
the menu in the page directive, rather than having to give a
|
||||
separate menuItem directive. 'zmi_views' is the menu most often
|
||||
used in the Zope management interface.
|
||||
|
||||
This attribute will only work if zope.browsermenu is installed.
|
||||
""",
|
||||
required=False
|
||||
)
|
||||
|
||||
title = MessageID(
|
||||
title=u"The browser menu label for the page (view)",
|
||||
description=u"""
|
||||
This attribute must be supplied if a menu attribute is
|
||||
supplied.
|
||||
|
||||
This attribute will only work if zope.browsermenu is installed.
|
||||
""",
|
||||
required=False
|
||||
)
|
||||
|
||||
provides = GlobalInterface(
|
||||
title=u"The interface this view provides.",
|
||||
description=u"""
|
||||
A view can provide an interface. This would be used for
|
||||
views that support other views.""",
|
||||
required=False,
|
||||
default=Interface,
|
||||
)
|
||||
|
||||
class IViewPageSubdirective(Interface):
|
||||
"""
|
||||
Subdirective to IViewDirective.
|
||||
"""
|
||||
|
||||
name = TextLine(
|
||||
title=u"The name of the page (view)",
|
||||
description=u"""
|
||||
The name shows up in URLs/paths. For example 'foo' or
|
||||
'foo.html'. This attribute is required unless you use the
|
||||
subdirective 'page' to create sub views. If you do not have
|
||||
sub pages, it is common to use an extension for the view name
|
||||
such as '.html'. If you do have sub pages and you want to
|
||||
provide a view name, you shouldn't use extensions.""",
|
||||
required=True
|
||||
)
|
||||
|
||||
attribute = PythonIdentifier(
|
||||
title=u"The name of the view attribute implementing the page.",
|
||||
description=u"""
|
||||
This refers to the attribute (method) on the view that is
|
||||
implementing a specific sub page.""",
|
||||
required=False
|
||||
)
|
||||
|
||||
template = Path(
|
||||
title=u"The name of a template that implements the page.",
|
||||
description=u"""
|
||||
Refers to a file containing a page template (should end in
|
||||
extension '.pt' or '.html').""",
|
||||
required=False
|
||||
)
|
||||
|
||||
class IViewDefaultPageSubdirective(Interface):
|
||||
"""
|
||||
Subdirective to IViewDirective.
|
||||
"""
|
||||
|
||||
name = TextLine(
|
||||
title=u"The name of the page that is the default.",
|
||||
description=u"""
|
||||
The named page will be used as the default if no name is
|
||||
specified explicitly in the path. If no defaultPage directive
|
||||
is supplied, the default page will be the first page
|
||||
listed.""",
|
||||
required=True
|
||||
)
|
||||
|
||||
|
||||
class IPagesPageSubdirective(IViewPageSubdirective):
|
||||
"""
|
||||
Subdirective to IPagesDirective
|
||||
"""
|
||||
|
||||
menu = MenuField(
|
||||
title=u"The browser menu to include the page (view) in.",
|
||||
description=u"""
|
||||
Many views are included in menus. It's convenient to name the
|
||||
menu in the page directive, rather than having to give a
|
||||
separate menuItem directive.
|
||||
|
||||
This attribute will only work if zope.browsermenu is installed.
|
||||
""",
|
||||
required=False
|
||||
)
|
||||
|
||||
title = MessageID(
|
||||
title=u"The browser menu label for the page (view)",
|
||||
description=u"""
|
||||
This attribute must be supplied if a menu attribute is
|
||||
supplied.
|
||||
|
||||
This attribute will only work if zope.browsermenu is installed.
|
||||
""",
|
||||
required=False
|
||||
)
|
||||
|
||||
class IPageDirective(IPagesDirective, IPagesPageSubdirective):
|
||||
"""
|
||||
The page directive is used to create views that provide a single
|
||||
url or page.
|
||||
|
||||
The page directive creates a new view class from a given template
|
||||
and/or class and registers it.
|
||||
"""
|
||||
|
||||
class IExpressionTypeDirective(Interface):
|
||||
"""Register a new TALES expression type"""
|
||||
|
||||
name = TextLine(
|
||||
title=u"Name",
|
||||
description=u"""Name of the expression. This will also be used
|
||||
as the prefix in actual TALES expressions.""",
|
||||
required=True
|
||||
)
|
||||
|
||||
handler = GlobalObject(
|
||||
title=u"Handler",
|
||||
description=u"""Handler is class that implements
|
||||
zope.tales.interfaces.ITALESExpression.""",
|
||||
required=True
|
||||
)
|
||||
@@ -0,0 +1,73 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
"""
|
||||
|
||||
from zope import component, interface
|
||||
import zope.traversing.interfaces
|
||||
|
||||
class INamedTemplate(interface.Interface):
|
||||
"""A template that is looked up by name
|
||||
"""
|
||||
|
||||
class NamedTemplateImplementation(object):
|
||||
|
||||
def __init__(self, descriptor, view_type=None):
|
||||
try:
|
||||
descriptor.__get__
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"NamedTemplateImplementation must be passed a descriptor."
|
||||
)
|
||||
self.descriptor = descriptor
|
||||
interface.implementer(INamedTemplate)(self)
|
||||
|
||||
if view_type is not None:
|
||||
component.adapter(view_type)(self)
|
||||
|
||||
def __call__(self, instance):
|
||||
return self.descriptor.__get__(instance, instance.__class__)
|
||||
|
||||
|
||||
class implementation(object):
|
||||
|
||||
def __init__(self, view_type=None):
|
||||
self.view_type = view_type
|
||||
|
||||
def __call__(self, descriptor):
|
||||
return NamedTemplateImplementation(descriptor, self.view_type)
|
||||
|
||||
|
||||
class NamedTemplate(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.__name__ = name
|
||||
|
||||
def __get__(self, instance, type=None):
|
||||
if instance is None:
|
||||
return self
|
||||
return component.getAdapter(instance, INamedTemplate, self.__name__)
|
||||
|
||||
def __call__(self, instance, *args, **kw):
|
||||
self.__get__(instance)(*args, **kw)
|
||||
|
||||
|
||||
@interface.implementer(zope.traversing.interfaces.IPathAdapter)
|
||||
class NamedTemplatePathAdapter(object):
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
def __getitem__(self, name):
|
||||
return component.getAdapter(self.context, INamedTemplate, name)
|
||||
@@ -0,0 +1,75 @@
|
||||
===============
|
||||
Named Templates
|
||||
===============
|
||||
|
||||
We often want to be able to define view logic and view templates
|
||||
independently. We'd like to be able to change the template used by a
|
||||
form without being forced to modify the form.
|
||||
|
||||
Named templates provide templates that are registered as named view
|
||||
adapters. To define a named template, use the `NamedTemplateImplementation`
|
||||
constructor:
|
||||
|
||||
>>> from zope.browserpage import ViewPageTemplateFile
|
||||
>>> from zope.browserpage.namedtemplate import (
|
||||
... NamedTemplateImplementation)
|
||||
>>> sample = ViewPageTemplateFile('tests/namedtemplate.pt')
|
||||
>>> sample = NamedTemplateImplementation(sample)
|
||||
|
||||
Let's define a view that uses the named template. To use a named
|
||||
template, use the NamedTemplate constructor, and give a template name:
|
||||
|
||||
>>> from zope.browserpage.namedtemplate import NamedTemplate
|
||||
>>> class MyView:
|
||||
... def __init__(self, context, request):
|
||||
... self.context = context
|
||||
... self.request = request
|
||||
...
|
||||
... __call__ = NamedTemplate('sample')
|
||||
|
||||
Normally, we'd register a named template for a view interface, to
|
||||
allow it to be registered for multiple views. We'll just register it
|
||||
for our view class.
|
||||
|
||||
>>> from zope import component
|
||||
>>> component.provideAdapter(sample, [MyView], name='sample')
|
||||
|
||||
Now, with this in place, we should be able to use our view:
|
||||
|
||||
>>> class MyContent:
|
||||
... def __init__(self, name):
|
||||
... self.name = name
|
||||
|
||||
>>> from zope.publisher.browser import TestRequest
|
||||
>>> view = MyView(MyContent('bob'), TestRequest())
|
||||
>>> print(view(x=42).replace('\r\n', '\n'))
|
||||
<html><body>
|
||||
Hello bob
|
||||
The URL is http://127.0.0.1
|
||||
The positional arguments were ()
|
||||
The keyword argument x is 42
|
||||
</body></html>
|
||||
<BLANKLINE>
|
||||
|
||||
The view type that a named template is to be used for can be supplied
|
||||
when the named template is created:
|
||||
|
||||
>>> class MyView:
|
||||
... def __init__(self, context, request):
|
||||
... self.context = context
|
||||
... self.request = request
|
||||
...
|
||||
... __call__ = NamedTemplate('sample2')
|
||||
|
||||
>>> sample = ViewPageTemplateFile('tests/namedtemplate.pt')
|
||||
>>> sample = NamedTemplateImplementation(sample, MyView)
|
||||
>>> component.provideAdapter(sample, name='sample2')
|
||||
>>> view = MyView(MyContent('bob'), TestRequest())
|
||||
>>> print(view(x=42).replace('\r\n', '\n'))
|
||||
<html><body>
|
||||
Hello bob
|
||||
The URL is http://127.0.0.1
|
||||
The positional arguments were ()
|
||||
The keyword argument x is 42
|
||||
</body></html>
|
||||
<BLANKLINE>
|
||||
@@ -0,0 +1,57 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Simple View Class
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
import sys
|
||||
from zope.interface import implementer
|
||||
from zope.publisher.browser import BrowserView
|
||||
from zope.publisher.interfaces.browser import IBrowserPublisher
|
||||
from zope.publisher.interfaces import NotFound
|
||||
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
|
||||
|
||||
@implementer(IBrowserPublisher)
|
||||
class simple(BrowserView):
|
||||
|
||||
def browserDefault(self, request):
|
||||
return self, ()
|
||||
|
||||
def publishTraverse(self, request, name):
|
||||
if name == 'index.html':
|
||||
return self.index
|
||||
|
||||
raise NotFound(self, name, request)
|
||||
|
||||
def __getitem__(self, name):
|
||||
return self.index.macros[name]
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
return self.index(*args, **kw)
|
||||
|
||||
|
||||
def SimpleViewClass(src, offering=None, used_for=None, bases=(), name=u''):
|
||||
if offering is None:
|
||||
offering = sys._getframe(1).f_globals
|
||||
|
||||
bases += (simple, )
|
||||
|
||||
class_ = type("SimpleViewClass from %s" % src, bases,
|
||||
{'index': ViewPageTemplateFile(src, offering),
|
||||
'__name__': name})
|
||||
|
||||
if used_for is not None:
|
||||
class_.__used_for__ = used_for
|
||||
|
||||
return class_
|
||||
@@ -0,0 +1 @@
|
||||
#
|
||||
@@ -0,0 +1,6 @@
|
||||
<html><body>
|
||||
Hello <span tal:replace="context/name" />
|
||||
The URL is <span tal:replace="request/URL" />
|
||||
The positional arguments were <span tal:replace="args" />
|
||||
The keyword argument x is <span tal:replace="options/x" />
|
||||
</body></html>
|
||||
@@ -0,0 +1,19 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Sample Component
|
||||
"""
|
||||
from zope.browserpage import ViewPageTemplateFile
|
||||
|
||||
class C(object):
|
||||
index = ViewPageTemplateFile('test.pt')
|
||||
@@ -0,0 +1,18 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Simple Test View
|
||||
"""
|
||||
from zope.browserpage.simpleviewclass import SimpleViewClass
|
||||
|
||||
SimpleTestView = SimpleViewClass('testsimpleviewclass.pt')
|
||||
@@ -0,0 +1 @@
|
||||
<html><body></body></html>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Bound Page Template Tests
|
||||
"""
|
||||
import unittest
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def testAttributes(self):
|
||||
|
||||
from zope.browserpage.tests.sample import C
|
||||
|
||||
C.index.__func__.foo = 1
|
||||
self.assertEqual(C.index.macros, C.index.__func__.macros)
|
||||
self.assertEqual(C.index.filename, C.index.__func__.filename)
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
@@ -0,0 +1,55 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2003 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests to check talesapi zcml configuration
|
||||
"""
|
||||
import unittest
|
||||
from io import StringIO
|
||||
|
||||
from zope.configuration.xmlconfig import xmlconfig, XMLConfig
|
||||
from zope.pagetemplate.engine import Engine
|
||||
import zope.browserpage
|
||||
|
||||
from zope.component.testing import PlacelessSetup
|
||||
|
||||
template = u"""<configure
|
||||
xmlns='http://namespaces.zope.org/zope'
|
||||
xmlns:tales='http://namespaces.zope.org/tales'>
|
||||
%s
|
||||
</configure>"""
|
||||
|
||||
|
||||
class Handler(object):
|
||||
pass
|
||||
|
||||
class Test(PlacelessSetup, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Test, self).setUp()
|
||||
XMLConfig('meta.zcml', zope.browserpage)()
|
||||
|
||||
def testExpressionType(self):
|
||||
xmlconfig(StringIO(
|
||||
template %
|
||||
u"""
|
||||
<tales:expressiontype
|
||||
name="test"
|
||||
handler="zope.browserpage.tests.test_expressiontype.Handler"
|
||||
/>
|
||||
"""
|
||||
))
|
||||
self.assertIn("test", Engine.getTypes())
|
||||
self.assertIs(Handler, Engine.getTypes()['test'])
|
||||
|
||||
def test_suite():
|
||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||
@@ -0,0 +1,260 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2017 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 unittest
|
||||
|
||||
from zope.browserpage.metaconfigure import page
|
||||
from zope.browserpage.metaconfigure import view
|
||||
from zope.browserpage.metaconfigure import simple
|
||||
from zope.browserpage.metaconfigure import _handle_menu
|
||||
from zope.configuration.exceptions import ConfigurationError
|
||||
|
||||
class Context(object):
|
||||
|
||||
class info(object):
|
||||
file = __file__
|
||||
line = 1
|
||||
|
||||
def __init__(self):
|
||||
self.actions = []
|
||||
|
||||
def path(self, s):
|
||||
return s
|
||||
|
||||
def action(self, **kwargs):
|
||||
self.actions.append(kwargs)
|
||||
|
||||
class _AbstractHandlerTest(unittest.TestCase):
|
||||
|
||||
if not hasattr(unittest.TestCase, 'assertRaisesRegex'):
|
||||
assertRaisesRegex = unittest.TestCase.assertRaisesRegexp
|
||||
|
||||
def setUp(self):
|
||||
self.context = Context()
|
||||
|
||||
def _call(self, **kwargs):
|
||||
context = self.context
|
||||
self._callFUT(context, 'Name', None, **kwargs)
|
||||
return context
|
||||
|
||||
def _check_raises(self, regex, **kwargs):
|
||||
with self.assertRaisesRegex(ConfigurationError, regex):
|
||||
self._call(**kwargs)
|
||||
|
||||
class TestPage(_AbstractHandlerTest):
|
||||
|
||||
def _callFUT(self, *args, **kwargs):
|
||||
page(*args, **kwargs)
|
||||
|
||||
def test_no_class_no_template(self):
|
||||
self._check_raises('Must specify a class or template')
|
||||
|
||||
def test_template_attribute(self):
|
||||
self._check_raises(
|
||||
'Attribute and template cannot be used together',
|
||||
template=self, attribute="attr")
|
||||
|
||||
def test_template_not_exists(self):
|
||||
self._check_raises(
|
||||
"No such file",
|
||||
template=__name__)
|
||||
|
||||
def test_class_missing_attribute(self):
|
||||
self._check_raises(
|
||||
"The provided class doesn't have the specified attribute",
|
||||
class_=type(self), attribute="does not exist")
|
||||
|
||||
def test_class_with_browser_default(self):
|
||||
class BrowserDefault(object):
|
||||
def browserDefault(self):
|
||||
raise AssertionError("Not called")
|
||||
context = self._call(
|
||||
class_=BrowserDefault)
|
||||
|
||||
action = context.actions[1]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
self.assertEqual(new_class.browserDefault,
|
||||
BrowserDefault.browserDefault)
|
||||
|
||||
def test_class_implements(self):
|
||||
from zope.publisher.interfaces.browser import IBrowserPublisher
|
||||
from zope import interface
|
||||
|
||||
class Class(object):
|
||||
# How does this arise in the wild?
|
||||
# @implementer(IThing) doesn't do it.
|
||||
__implements__ = None
|
||||
|
||||
self.assertTrue(hasattr(Class, '__implements__'))
|
||||
context = self._call(class_=Class)
|
||||
|
||||
action = context.actions[1]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
self.assertIn(IBrowserPublisher, interface.implementedBy(new_class))
|
||||
|
||||
class TestViewPage(_AbstractHandlerTest):
|
||||
|
||||
view = None
|
||||
|
||||
def _callFUT(self, *args, **kwargs):
|
||||
self.view = view(self.context, None)
|
||||
self.view.page(self.context, 'Name', **kwargs)
|
||||
|
||||
def test_no_attribute(self):
|
||||
self._check_raises(
|
||||
"Must specify either a template or an attribute name")
|
||||
|
||||
class TestView(_AbstractHandlerTest):
|
||||
|
||||
def test_class_without_attribute(self):
|
||||
v = view(self.context, None, class_=type(self))
|
||||
v.pages.append([None, 'does not exist', None])
|
||||
self._call = v
|
||||
|
||||
self._check_raises('Undefined attribute')
|
||||
|
||||
def test_class_without_publish_traverse_name(self):
|
||||
class C(object):
|
||||
attr = 'the attr'
|
||||
|
||||
v = view(self.context, None, class_=C)
|
||||
v.pages.append(['page_name', 'attr', None])
|
||||
|
||||
v()
|
||||
|
||||
action = self.context.actions[2]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
|
||||
instance = new_class(None, None)
|
||||
self.assertEqual(C.attr,
|
||||
instance.publishTraverse(None, 'page_name'))
|
||||
|
||||
with self.assertRaises(LookupError):
|
||||
instance.publishTraverse(None, 'something else')
|
||||
|
||||
def test_class_with_publish_traverse_name(self):
|
||||
class C(object):
|
||||
attr = 'the attr'
|
||||
|
||||
def publishTraverse(self, *args):
|
||||
raise AssertionError("Never called")
|
||||
|
||||
v = view(self.context, None, class_=C)
|
||||
v.pages.append(['page_name', 'attr', None])
|
||||
|
||||
v()
|
||||
|
||||
action = self.context.actions[2]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
|
||||
instance = new_class(None, None)
|
||||
self.assertEqual(C.attr,
|
||||
instance.publishTraverse(None, 'page_name'))
|
||||
|
||||
def test_class_with_publish_traverse_other_name(self):
|
||||
class C(object):
|
||||
attr = 'the attr'
|
||||
|
||||
def publishTraverse(self, *args):
|
||||
return 'default value'
|
||||
|
||||
v = view(self.context, None, class_=C)
|
||||
v.pages.append(['page_name', 'attr', None])
|
||||
|
||||
v()
|
||||
|
||||
action = self.context.actions[2]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
|
||||
instance = new_class(None, None)
|
||||
self.assertEqual('default value',
|
||||
instance.publishTraverse(None, 'something else'))
|
||||
|
||||
def test_template_with_attr_not_equal_name(self):
|
||||
import os
|
||||
v = view(self.context, None)
|
||||
v.page(self.context, 'page_name', attribute='foo',
|
||||
template=os.path.join(os.path.dirname(__file__), 'test.pt'))
|
||||
v()
|
||||
action = self.context.actions[2]
|
||||
register = action['args']
|
||||
new_class = register[1]
|
||||
|
||||
self.assertTrue(hasattr(new_class, 'foo'))
|
||||
self.assertTrue(hasattr(new_class, 'page_name'))
|
||||
|
||||
class TestHandleMenu(_AbstractHandlerTest):
|
||||
|
||||
def _call(self, **kwargs):
|
||||
args = {
|
||||
'_context': self.context,
|
||||
'menu': None,
|
||||
'title': None,
|
||||
'for_': None,
|
||||
'name': '',
|
||||
'permission': None
|
||||
}
|
||||
args.update(kwargs)
|
||||
return _handle_menu(**args)
|
||||
|
||||
def test_one_or_the_other(self):
|
||||
self._check_raises(
|
||||
".*they must both be specified",
|
||||
menu='menu', title='')
|
||||
|
||||
self._check_raises(
|
||||
".*they must both be specified",
|
||||
menu='', title='menu')
|
||||
|
||||
def test_bad_for(self):
|
||||
self._check_raises(
|
||||
"Menus can be specified only for single-view",
|
||||
menu='menu', title='title',
|
||||
for_=(1, 2)
|
||||
)
|
||||
|
||||
def test_no_directive(self):
|
||||
from zope.browserpage import metaconfigure
|
||||
import warnings
|
||||
menuItemDirective = metaconfigure.menuItemDirective
|
||||
metaconfigure.menuItemDirective = metaconfigure._fallbackMenuItemDirective
|
||||
try:
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
result = self._call(menu='menu', title='title', for_=(1,))
|
||||
self.assertEqual(result, [])
|
||||
self.assertEqual(
|
||||
'Page directive used with "menu" argument, while "zope.browsermenu" '
|
||||
'package is not installed. Doing nothing.',
|
||||
str(w[0].message))
|
||||
finally:
|
||||
metaconfigure.menuItemDirective = menuItemDirective
|
||||
|
||||
class TestSimple(unittest.TestCase):
|
||||
|
||||
def test_publish_not_found(self):
|
||||
sview = simple(None, None)
|
||||
with self.assertRaises(LookupError):
|
||||
sview.publishTraverse(None, None)
|
||||
|
||||
def test_recursive_call(self):
|
||||
sview = simple(None, None)
|
||||
sview.__page_attribute__ = '__call__'
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
sview()
|
||||
@@ -0,0 +1,88 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005-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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
"""
|
||||
import os
|
||||
import os.path
|
||||
import unittest
|
||||
|
||||
from zope.browserpage import namedtemplate
|
||||
|
||||
import zope.component.testing
|
||||
import zope.traversing.adapters
|
||||
|
||||
class TestImplementation(unittest.TestCase):
|
||||
|
||||
def test_call(self):
|
||||
inst = namedtemplate.implementation(None)
|
||||
|
||||
|
||||
nt = namedtemplate.NamedTemplate('name')
|
||||
nti = inst(nt)
|
||||
|
||||
self.assertEqual(nti.descriptor, nt)
|
||||
|
||||
class TestNamedTemplateImplementation(unittest.TestCase):
|
||||
|
||||
def test_bad_descriptor(self):
|
||||
with self.assertRaises(TypeError):
|
||||
namedtemplate.NamedTemplateImplementation(None)
|
||||
|
||||
|
||||
class TestNamedTemplate(unittest.TestCase):
|
||||
|
||||
def test_no_instance(self):
|
||||
class X(object):
|
||||
nt = namedtemplate.NamedTemplate('name')
|
||||
|
||||
self.assertIsInstance(X.nt, namedtemplate.NamedTemplate)
|
||||
|
||||
def test_call_no_adapter(self):
|
||||
class X(object):
|
||||
nt = namedtemplate.NamedTemplate('name')
|
||||
|
||||
with self.assertRaises(LookupError):
|
||||
getattr(X(), 'nt')
|
||||
|
||||
with self.assertRaises(LookupError):
|
||||
X.nt(X())
|
||||
|
||||
class TestNamedTemplatePathAdapter(unittest.TestCase):
|
||||
|
||||
def test_getitem_no_adapter(self):
|
||||
|
||||
adapter = namedtemplate.NamedTemplatePathAdapter(self)
|
||||
|
||||
with self.assertRaises(LookupError):
|
||||
_ = adapter['name']
|
||||
|
||||
def pageSetUp(test):
|
||||
zope.component.testing.setUp(test)
|
||||
zope.component.provideAdapter(
|
||||
zope.traversing.adapters.DefaultTraversable,
|
||||
[None],
|
||||
)
|
||||
|
||||
|
||||
def test_suite():
|
||||
import doctest
|
||||
filename = os.path.join(os.pardir, 'namedtemplate.rst')
|
||||
return unittest.TestSuite([
|
||||
unittest.defaultTestLoader.loadTestsFromName(__name__),
|
||||
doctest.DocFileSuite(
|
||||
filename,
|
||||
setUp=pageSetUp, tearDown=zope.component.testing.tearDown,
|
||||
globs={'__file__': os.path.abspath(os.path.join(os.path.dirname(__file__), filename))}
|
||||
)
|
||||
])
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,177 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2001-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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Simple View Class Tests
|
||||
"""
|
||||
import unittest
|
||||
|
||||
class Test_SimpleTestView(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.browserpage.tests.simpletestview import SimpleTestView
|
||||
return SimpleTestView
|
||||
|
||||
def _makeOne(self, context, request):
|
||||
return self._getTargetClass()(context, request)
|
||||
|
||||
def test_simple(self):
|
||||
from zope.publisher.browser import TestRequest
|
||||
context = DummyContext()
|
||||
request = TestRequest()
|
||||
view = self._makeOne(context, request)
|
||||
self.assertIsNotNone(view['test'])
|
||||
out = view()
|
||||
self.assertEqual(out.replace('\r\n', '\n'),
|
||||
'<html>\n'
|
||||
' <body>\n'
|
||||
' <p>hello world</p>\n'
|
||||
' </body>\n</html>\n')
|
||||
|
||||
class Test_SimpleViewClass(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.browserpage.simpleviewclass import SimpleViewClass
|
||||
return SimpleViewClass
|
||||
|
||||
def _makeKlass(self, *args, **kw):
|
||||
return self._getTargetClass()(*args, **kw)
|
||||
|
||||
def test___name__(self):
|
||||
klass = self._makeKlass('testsimpleviewclass.pt', name='test.html')
|
||||
view = klass(None, None)
|
||||
self.assertEqual(view.__name__, 'test.html')
|
||||
|
||||
def test__used_for__(self):
|
||||
klass = self._makeKlass('testsimpleviewclass.pt',
|
||||
name='test.html',
|
||||
used_for=self)
|
||||
self.assertIs(klass.__used_for__, self)
|
||||
|
||||
def test___getitem___(self):
|
||||
klass = self._makeKlass('testsimpleviewclass.pt', name='test.html')
|
||||
view = klass(None, None)
|
||||
self.assertTrue(view['test'] is not None)
|
||||
self.assertRaises(KeyError, view.__getitem__, 'foo')
|
||||
|
||||
def test_w_base_classes(self):
|
||||
from zope.publisher.browser import TestRequest
|
||||
class BaseClass(object):
|
||||
pass
|
||||
|
||||
klass = self._makeKlass('testsimpleviewclass.pt', bases=(BaseClass, ))
|
||||
|
||||
self.assertTrue(issubclass(klass, BaseClass))
|
||||
|
||||
ob = DummyContext()
|
||||
request = TestRequest()
|
||||
view = klass(ob, request)
|
||||
self.assertIsNotNone(view['test'])
|
||||
out = view()
|
||||
self.assertEqual(out.replace('\r\n', '\n'),
|
||||
'<html>\n'
|
||||
' <body>\n'
|
||||
' <p>hello world</p>\n'
|
||||
' </body>\n</html>\n')
|
||||
|
||||
class Test_simple(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.browserpage.simpleviewclass import simple
|
||||
return simple
|
||||
|
||||
def _makeOne(self, context=None, request=None):
|
||||
if context is None:
|
||||
context = DummyContext()
|
||||
if request is None:
|
||||
request = DummyRequest()
|
||||
return self._getTargetClass()(context, request)
|
||||
|
||||
def test_class_conforms_to_IBrowserPublisher(self):
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.publisher.interfaces.browser import IBrowserPublisher
|
||||
verifyClass(IBrowserPublisher, self._getTargetClass())
|
||||
|
||||
def test_browserDefault(self):
|
||||
request = DummyRequest()
|
||||
view = self._makeOne(request=request)
|
||||
self.assertEqual(view.browserDefault(request), (view, ()))
|
||||
|
||||
def test_publishTraverse_not_index_raises_NotFound(self):
|
||||
from zope.publisher.interfaces import NotFound
|
||||
request = DummyRequest()
|
||||
view = self._makeOne(request=request)
|
||||
self.assertRaises(NotFound, view.publishTraverse, request, 'nonesuch')
|
||||
|
||||
def test_publishTraverse_w_index_returns_index(self):
|
||||
request = DummyRequest()
|
||||
view = self._makeOne(request=request)
|
||||
index = view.index = DummyTemplate()
|
||||
self.assertTrue(view.publishTraverse(request, 'index.html') is index)
|
||||
|
||||
def test___getitem___uses_index_macros(self):
|
||||
view = self._makeOne()
|
||||
view.index = index = DummyTemplate()
|
||||
index.macros = {}
|
||||
index.macros['aaa'] = aaa = object()
|
||||
self.assertTrue(view['aaa'] is aaa)
|
||||
|
||||
def test___call___no_args_no_kw(self):
|
||||
view = self._makeOne()
|
||||
view.index = index = DummyTemplate()
|
||||
result = view()
|
||||
self.assertTrue(result is index)
|
||||
self.assertEqual(index._called_with, ((), {}))
|
||||
|
||||
def test___call___w_args_no_kw(self):
|
||||
view = self._makeOne()
|
||||
view.index = index = DummyTemplate()
|
||||
result = view('abc')
|
||||
self.assertTrue(result is index)
|
||||
self.assertEqual(index._called_with, (('abc',), {}))
|
||||
|
||||
def test___call___no_args_w_kw(self):
|
||||
view = self._makeOne()
|
||||
view.index = index = DummyTemplate()
|
||||
result = view(foo='bar')
|
||||
self.assertTrue(result is index)
|
||||
self.assertEqual(index._called_with, ((), {'foo': 'bar'}))
|
||||
|
||||
def test___call___w_args_w_kw(self):
|
||||
view = self._makeOne()
|
||||
view.index = index = DummyTemplate()
|
||||
result = view('abc', foo='bar')
|
||||
self.assertTrue(result is index)
|
||||
self.assertEqual(index._called_with, (('abc',), {'foo': 'bar'}))
|
||||
|
||||
|
||||
class DummyContext:
|
||||
pass
|
||||
|
||||
class DummyResponse:
|
||||
pass
|
||||
|
||||
class DummyRequest:
|
||||
debug = False
|
||||
response = DummyResponse()
|
||||
|
||||
class DummyTemplate:
|
||||
def __call__(self, *args, **kw):
|
||||
self._called_with = (args, kw)
|
||||
return self
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test_SimpleTestView),
|
||||
unittest.makeSuite(Test_SimpleViewClass),
|
||||
unittest.makeSuite(Test_simple),
|
||||
))
|
||||
@@ -0,0 +1,175 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""View ZPT Tests
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.component import getGlobalSiteManager
|
||||
from zope.component.testing import PlacelessSetup
|
||||
from zope.interface import Interface, implementer
|
||||
|
||||
from zope.browserpage.viewpagetemplatefile import ViewPageTemplateFile
|
||||
from zope.browserpage.viewpagetemplatefile import BoundPageTemplate
|
||||
|
||||
|
||||
class I1(Interface):
|
||||
pass
|
||||
|
||||
@implementer(I1)
|
||||
class C1(object):
|
||||
pass
|
||||
|
||||
class InstanceWithContext(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
class InstanceWithoutContext(object):
|
||||
pass
|
||||
|
||||
|
||||
class TestViewZPT(PlacelessSetup, unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestViewZPT, self).setUp()
|
||||
self.t = ViewPageTemplateFile('test.pt')
|
||||
self.context = C1()
|
||||
|
||||
def testNamespaceContextAvailable(self):
|
||||
context = self.context
|
||||
request = None
|
||||
|
||||
namespace = self.t.pt_getContext(InstanceWithContext(context), request)
|
||||
self.assertTrue(namespace['context'] is context)
|
||||
self.assertTrue('views' in namespace)
|
||||
|
||||
def testNamespaceHereNotAvailable(self):
|
||||
request = None
|
||||
self.assertRaises(AttributeError, self.t.pt_getContext,
|
||||
InstanceWithoutContext(), request)
|
||||
|
||||
def testViewMapper(self):
|
||||
the_view = "This is the view"
|
||||
the_view_name = "some view name"
|
||||
def ViewMaker(*args, **kw):
|
||||
return the_view
|
||||
|
||||
from zope.publisher.interfaces import IRequest
|
||||
|
||||
gsm = getGlobalSiteManager()
|
||||
gsm.registerAdapter(
|
||||
ViewMaker, (I1, IRequest), Interface, the_view_name, event=False)
|
||||
|
||||
@implementer(IRequest)
|
||||
class MyRequest(object):
|
||||
pass
|
||||
|
||||
request = MyRequest()
|
||||
|
||||
namespace = self.t.pt_getContext(InstanceWithContext(self.context),
|
||||
request)
|
||||
views = namespace['views']
|
||||
self.assertTrue(the_view is views[the_view_name])
|
||||
|
||||
def test_debug_flags(self):
|
||||
from zope.publisher.browser import TestRequest
|
||||
self.request = TestRequest()
|
||||
self.request.debug.sourceAnnotations = False
|
||||
self.assertFalse('test.pt' in self.t(self))
|
||||
self.request.debug.sourceAnnotations = True
|
||||
self.assertTrue('test.pt' in self.t(self))
|
||||
|
||||
t = ViewPageTemplateFile('testsimpleviewclass.pt')
|
||||
self.request.debug.showTAL = False
|
||||
self.assertFalse('metal:' in t(self))
|
||||
self.request.debug.showTAL = True
|
||||
self.assertTrue('metal:' in t(self))
|
||||
|
||||
def test_render_sets_content_type_unless_set(self):
|
||||
from zope.publisher.browser import TestRequest
|
||||
t = ViewPageTemplateFile('test.pt')
|
||||
|
||||
self.request = TestRequest()
|
||||
response = self.request.response
|
||||
self.assertFalse(response.getHeader('Content-Type'))
|
||||
t(self)
|
||||
self.assertEqual(response.getHeader('Content-Type'), 'text/html')
|
||||
|
||||
self.request = TestRequest()
|
||||
response = self.request.response
|
||||
response.setHeader('Content-Type', 'application/x-test-junk')
|
||||
t(self)
|
||||
self.assertEqual(response.getHeader('Content-Type'),
|
||||
'application/x-test-junk')
|
||||
|
||||
|
||||
class TestViewZPTContentType(unittest.TestCase):
|
||||
|
||||
def testInitWithoutType(self):
|
||||
t = ViewPageTemplateFile('test.pt')
|
||||
t._cook_check()
|
||||
self.assertEqual(t.content_type, "text/html")
|
||||
|
||||
t = ViewPageTemplateFile('testxml.pt')
|
||||
t._cook_check()
|
||||
self.assertEqual(t.content_type, "text/xml")
|
||||
|
||||
def testInitWithType(self):
|
||||
t = ViewPageTemplateFile('test.pt', content_type="text/plain")
|
||||
t._cook_check()
|
||||
self.assertEqual(t.content_type, "text/plain")
|
||||
|
||||
t = ViewPageTemplateFile('testxml.pt', content_type="text/plain")
|
||||
t._cook_check()
|
||||
self.assertEqual(t.content_type, "text/xml")
|
||||
|
||||
|
||||
class TestBoundPageTemplate(unittest.TestCase):
|
||||
|
||||
def test_call_self_none(self):
|
||||
args = []
|
||||
def func(*a):
|
||||
args.extend(a)
|
||||
|
||||
bpt = BoundPageTemplate(func, None)
|
||||
bpt(self, 1, 2)
|
||||
|
||||
self.assertEqual(args, [self, 1, 2])
|
||||
|
||||
def test_cannot_set_attr(self):
|
||||
bpt = BoundPageTemplate(None, None)
|
||||
with self.assertRaises(AttributeError):
|
||||
bpt.thing = 1
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
bpt.__func__ = 1
|
||||
|
||||
with self.assertRaises(AttributeError):
|
||||
bpt.__self__ = 1
|
||||
|
||||
def test_repr(self):
|
||||
ob = "WackyWavingInflatableArmFlailingTubeMan"
|
||||
|
||||
bpt = BoundPageTemplate(None, ob)
|
||||
self.assertEqual(repr(bpt),
|
||||
"<BoundPageTemplateFile of 'WackyWavingInflatableArmFlailingTubeMan'>")
|
||||
|
||||
|
||||
class TestNoTraverser(unittest.TestCase):
|
||||
|
||||
def test_none(self):
|
||||
from zope.browserpage.viewpagetemplatefile import NoTraverser
|
||||
self.assertIsNone(NoTraverser(self, self))
|
||||
|
||||
def test_suite():
|
||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><p>test</p></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><p tal:content="view/data">test</p></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
<html><body><p tal:content="view/action">test</p></body></html>
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<p metal:define-macro="test">hello world</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" ?>
|
||||
<html><body></body></html>
|
||||
@@ -0,0 +1,90 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""File-based page templates that can be used as methods on views.
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
from zope.component import getMultiAdapter
|
||||
from zope.pagetemplate.pagetemplatefile import PageTemplateFile
|
||||
from zope.pagetemplate.engine import TrustedAppPT
|
||||
|
||||
class ViewPageTemplateFile(TrustedAppPT, PageTemplateFile):
|
||||
"""Page Templates used as methods of views defined as Python classes.
|
||||
"""
|
||||
|
||||
def __init__(self, filename, _prefix=None, content_type=None):
|
||||
_prefix = self.get_path_from_prefix(_prefix)
|
||||
super(ViewPageTemplateFile, self).__init__(filename, _prefix)
|
||||
if content_type is not None:
|
||||
self.content_type = content_type
|
||||
|
||||
def pt_getContext(self, instance, request, **_kw):
|
||||
# instance is a View component
|
||||
namespace = super(ViewPageTemplateFile, self).pt_getContext(**_kw)
|
||||
namespace['request'] = request
|
||||
namespace['view'] = instance
|
||||
namespace['context'] = context = instance.context
|
||||
namespace['views'] = ViewMapper(context, request)
|
||||
return namespace
|
||||
|
||||
def __call__(self, instance, *args, **keywords):
|
||||
namespace = self.pt_getContext(
|
||||
request=instance.request,
|
||||
instance=instance, args=args, options=keywords)
|
||||
debug_flags = instance.request.debug
|
||||
s = self.pt_render(
|
||||
namespace,
|
||||
showtal=getattr(debug_flags, 'showTAL', 0),
|
||||
sourceAnnotations=getattr(debug_flags, 'sourceAnnotations', 0),
|
||||
)
|
||||
response = instance.request.response
|
||||
if not response.getHeader("Content-Type"):
|
||||
response.setHeader("Content-Type", self.content_type)
|
||||
return s
|
||||
|
||||
def __get__(self, instance, type):
|
||||
return BoundPageTemplate(self, instance)
|
||||
|
||||
class ViewMapper(object):
|
||||
def __init__(self, ob, request):
|
||||
self.ob = ob
|
||||
self.request = request
|
||||
|
||||
def __getitem__(self, name):
|
||||
return getMultiAdapter((self.ob, self.request), name=name)
|
||||
|
||||
|
||||
class BoundPageTemplate(object):
|
||||
def __init__(self, pt, ob):
|
||||
object.__setattr__(self, '__func__', pt)
|
||||
object.__setattr__(self, '__self__', ob)
|
||||
|
||||
macros = property(lambda self: self.__func__.macros)
|
||||
filename = property(lambda self: self.__func__.filename)
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
if self.__self__ is None:
|
||||
im_self, args = args[0], args[1:]
|
||||
else:
|
||||
im_self = self.__self__
|
||||
return self.__func__(im_self, *args, **kw)
|
||||
|
||||
def __setattr__(self, name, v):
|
||||
raise AttributeError("Can't set attribute", name)
|
||||
|
||||
def __repr__(self):
|
||||
return "<BoundPageTemplateFile of %r>" % self.__self__
|
||||
|
||||
def NoTraverser(ob, request):
|
||||
return None
|
||||
@@ -0,0 +1,61 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Zope 3 Component Architecture
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementedBy
|
||||
from zope.interface import moduleProvides
|
||||
from zope.interface import named
|
||||
from zope.interface import providedBy
|
||||
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
from zope.component.interfaces import IComponentArchitecture
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
from zope.component.interfaces import IComponentRegistrationConvenience
|
||||
from zope.component.interfaces import IFactory
|
||||
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.component.globalregistry import globalSiteManager
|
||||
from zope.component.globalregistry import provideAdapter
|
||||
from zope.component.globalregistry import provideHandler
|
||||
from zope.component.globalregistry import provideSubscriptionAdapter
|
||||
from zope.component.globalregistry import provideUtility
|
||||
|
||||
from zope.component._api import adapter_hook
|
||||
from zope.component._api import createObject
|
||||
from zope.component._api import getAdapter
|
||||
from zope.component._api import getAdapterInContext
|
||||
from zope.component._api import getAdapters
|
||||
from zope.component._api import getAllUtilitiesRegisteredFor
|
||||
from zope.component._api import getFactoriesFor
|
||||
from zope.component._api import getFactoryInterfaces
|
||||
from zope.component._api import getMultiAdapter
|
||||
from zope.component._api import getSiteManager
|
||||
from zope.component._api import getUtilitiesFor
|
||||
from zope.component._api import getUtility
|
||||
from zope.component._api import getNextUtility
|
||||
from zope.component._api import handle
|
||||
from zope.component._api import queryAdapter
|
||||
from zope.component._api import queryAdapterInContext
|
||||
from zope.component._api import queryMultiAdapter
|
||||
from zope.component._api import queryUtility
|
||||
from zope.component._api import queryNextUtility
|
||||
from zope.component._api import subscribers
|
||||
|
||||
from zope.component._declaration import adaptedBy
|
||||
from zope.component._declaration import adapter
|
||||
from zope.component._declaration import adapts
|
||||
|
||||
moduleProvides(IComponentArchitecture, IComponentRegistrationConvenience)
|
||||
__all__ = tuple(IComponentArchitecture)
|
||||
@@ -0,0 +1,231 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Zope 3 Component Architecture
|
||||
"""
|
||||
import sys
|
||||
|
||||
from zope.hookable import hookable
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
|
||||
from zope.component.interfaces import IFactory
|
||||
|
||||
# getSiteManager() returns a component registry. Although the term
|
||||
# "site manager" is deprecated in favor of "component registry",
|
||||
# the old term is kept around to maintain a stable API.
|
||||
base = None
|
||||
@hookable
|
||||
def getSiteManager(context=None):
|
||||
""" See IComponentArchitecture.
|
||||
"""
|
||||
global base
|
||||
if context is None:
|
||||
if base is None:
|
||||
from zope.component.globalregistry import base
|
||||
return base
|
||||
else:
|
||||
# Use the global site manager to adapt context to `IComponentLookup`
|
||||
# to avoid the recursion implied by using a local `getAdapter()` call.
|
||||
try:
|
||||
return IComponentLookup(context)
|
||||
except TypeError as error:
|
||||
raise ComponentLookupError(*error.args)
|
||||
|
||||
# Adapter API
|
||||
|
||||
def getAdapterInContext(object, interface, context):
|
||||
adapter = queryAdapterInContext(object, interface, context)
|
||||
if adapter is None:
|
||||
raise ComponentLookupError(object, interface)
|
||||
return adapter
|
||||
|
||||
def queryAdapterInContext(object, interface, context, default=None):
|
||||
conform = getattr(object, '__conform__', None)
|
||||
if conform is not None:
|
||||
try:
|
||||
adapter = conform(interface)
|
||||
except TypeError:
|
||||
# We got a TypeError. It might be an error raised by
|
||||
# the __conform__ implementation, or *we* may have
|
||||
# made the TypeError by calling an unbound method
|
||||
# (object is a class). In the later case, we behave
|
||||
# as though there is no __conform__ method. We can
|
||||
# detect this case by checking whether there is more
|
||||
# than one traceback object in the traceback chain:
|
||||
if sys.exc_info()[2].tb_next is not None:
|
||||
# There is more than one entry in the chain, so
|
||||
# reraise the error:
|
||||
raise
|
||||
# This clever trick is from Phillip Eby
|
||||
else:
|
||||
if adapter is not None:
|
||||
return adapter
|
||||
|
||||
if interface.providedBy(object):
|
||||
return object
|
||||
|
||||
return getSiteManager(context).queryAdapter(object, interface, '', default)
|
||||
|
||||
def getAdapter(object, interface=Interface, name=u'', 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,
|
||||
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):
|
||||
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,
|
||||
context=None):
|
||||
try:
|
||||
sitemanager = getSiteManager(context)
|
||||
except ComponentLookupError:
|
||||
# Oh blast, no site manager. This should *never* happen!
|
||||
return default
|
||||
|
||||
return sitemanager.queryMultiAdapter(objects, interface, name, default)
|
||||
|
||||
def getAdapters(objects, provided, context=None):
|
||||
try:
|
||||
sitemanager = getSiteManager(context)
|
||||
except ComponentLookupError:
|
||||
# Oh blast, no site manager. This should *never* happen!
|
||||
return []
|
||||
return sitemanager.getAdapters(objects, provided)
|
||||
|
||||
def subscribers(objects, interface, context=None):
|
||||
try:
|
||||
sitemanager = getSiteManager(context)
|
||||
except ComponentLookupError:
|
||||
# Oh blast, no site manager. This should *never* happen!
|
||||
return []
|
||||
return sitemanager.subscribers(objects, interface)
|
||||
|
||||
def handle(*objects):
|
||||
getSiteManager(None).subscribers(objects, None)
|
||||
|
||||
#############################################################################
|
||||
# Register the component architectures adapter hook, with the adapter hook
|
||||
# registry of the `zope.inteface` package. This way we will be able to call
|
||||
# interfaces to create adapters for objects. For example, `I1(ob)` is
|
||||
# equvalent to `getAdapterInContext(I1, ob, '')`.
|
||||
@hookable
|
||||
def adapter_hook(interface, object, name='', default=None):
|
||||
try:
|
||||
sitemanager = getSiteManager()
|
||||
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)
|
||||
|
||||
import zope.interface.interface
|
||||
zope.interface.interface.adapter_hooks.append(adapter_hook)
|
||||
#############################################################################
|
||||
|
||||
|
||||
# Utility API
|
||||
|
||||
def getUtility(interface, name='', context=None):
|
||||
utility = queryUtility(interface, name, context=context)
|
||||
if utility is not None:
|
||||
return utility
|
||||
raise ComponentLookupError(interface, name)
|
||||
|
||||
def queryUtility(interface, name='', default=None, context=None):
|
||||
return getSiteManager(context).queryUtility(interface, name, default)
|
||||
|
||||
def getUtilitiesFor(interface, context=None):
|
||||
return getSiteManager(context).getUtilitiesFor(interface)
|
||||
|
||||
|
||||
def getAllUtilitiesRegisteredFor(interface, context=None):
|
||||
return getSiteManager(context).getAllUtilitiesRegisteredFor(interface)
|
||||
|
||||
|
||||
_marker = object()
|
||||
|
||||
def queryNextUtility(context, interface, name='', default=None):
|
||||
"""Query for the next available utility.
|
||||
|
||||
Find the next available utility providing `interface` and having the
|
||||
specified name. If no utility was found, return the specified `default`
|
||||
value.
|
||||
"""
|
||||
try:
|
||||
sm = getSiteManager(context)
|
||||
except ComponentLookupError:
|
||||
return default
|
||||
bases = sm.__bases__
|
||||
for base in bases:
|
||||
util = base.queryUtility(interface, name, _marker)
|
||||
if util is not _marker:
|
||||
return util
|
||||
return default
|
||||
|
||||
|
||||
def getNextUtility(context, interface, name=''):
|
||||
"""Get the next available utility.
|
||||
|
||||
If no utility was found, a `ComponentLookupError` is raised.
|
||||
"""
|
||||
util = queryNextUtility(context, interface, name, _marker)
|
||||
if util is _marker:
|
||||
raise ComponentLookupError(
|
||||
"No more utilities for %s, '%s' have been found." % (
|
||||
interface, name))
|
||||
return util
|
||||
|
||||
|
||||
# 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()
|
||||
try:
|
||||
if interfaces.isOrExtends(interface):
|
||||
yield name, factory
|
||||
except AttributeError:
|
||||
for iface in interfaces:
|
||||
if iface.isOrExtends(interface):
|
||||
yield name, factory
|
||||
break
|
||||
@@ -0,0 +1,34 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
CLASS_TYPES = (type, types.ClassType)
|
||||
|
||||
PYTHON3 = False
|
||||
PYTHON2 = True
|
||||
|
||||
else: #pragma NO COVER
|
||||
|
||||
import pickle as _pickle
|
||||
|
||||
CLASS_TYPES = (type,)
|
||||
|
||||
PYTHON3 = True
|
||||
PYTHON2 = False
|
||||
@@ -0,0 +1,59 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Adapter declarations
|
||||
"""
|
||||
import sys
|
||||
|
||||
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):
|
||||
ob.__component_adapts__ = _adapts_descr(self.interfaces)
|
||||
else:
|
||||
ob.__component_adapts__ = self.interfaces
|
||||
|
||||
return ob
|
||||
|
||||
def adapts(*interfaces):
|
||||
frame = sys._getframe(1)
|
||||
locals = frame.f_locals
|
||||
|
||||
# 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:
|
||||
raise TypeError("adapts can be used only once in a class definition.")
|
||||
|
||||
locals['__component_adapts__'] = _adapts_descr(interfaces)
|
||||
|
||||
def adaptedBy(ob):
|
||||
return getattr(ob, '__component_adapts__', None)
|
||||
|
||||
def getName(ob):
|
||||
return getattr(ob, '__component_name__', u'')
|
||||
|
||||
class _adapts_descr(object):
|
||||
def __init__(self, interfaces):
|
||||
self.interfaces = interfaces
|
||||
|
||||
def __get__(self, inst, cls):
|
||||
if inst is None:
|
||||
return self.interfaces
|
||||
raise AttributeError('__component_adapts__')
|
||||
@@ -0,0 +1,12 @@
|
||||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
|
||||
<include file="meta.zcml" />
|
||||
|
||||
<subscriber handler=".event.objectEventNotify" />
|
||||
|
||||
<subscriber handler=".registry.dispatchUtilityRegistrationEvent" />
|
||||
<subscriber handler=".registry.dispatchAdapterRegistrationEvent" />
|
||||
<subscriber handler=".registry.dispatchSubscriptionAdapterRegistrationEvent" />
|
||||
<subscriber handler=".registry.dispatchHandlerRegistrationEvent" />
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,36 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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-specific event dispatching
|
||||
|
||||
Based on subscription adapters / handlers.
|
||||
"""
|
||||
|
||||
from zope.event import subscribers as event_subscribers
|
||||
|
||||
from zope.interface.interfaces import IObjectEvent
|
||||
from zope.component._api import subscribers as component_subscribers
|
||||
from zope.component._declaration import adapter
|
||||
|
||||
|
||||
def dispatch(*event):
|
||||
component_subscribers(event, None)
|
||||
|
||||
event_subscribers.append(dispatch)
|
||||
|
||||
|
||||
@adapter(IObjectEvent)
|
||||
def objectEventNotify(event):
|
||||
"""Dispatch ObjectEvents to interested adapters.
|
||||
"""
|
||||
component_subscribers((event.object, event), None)
|
||||
@@ -0,0 +1,57 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Placeless Test Setup
|
||||
"""
|
||||
|
||||
from zope.component import provideHandler
|
||||
from zope.component.event import objectEventNotify
|
||||
from zope.component.registry import dispatchUtilityRegistrationEvent
|
||||
from zope.component.registry import dispatchAdapterRegistrationEvent
|
||||
from zope.component.registry import (
|
||||
dispatchSubscriptionAdapterRegistrationEvent)
|
||||
from zope.component.registry import dispatchHandlerRegistrationEvent
|
||||
try:
|
||||
from zope.testing.cleanup import addCleanUp
|
||||
except ImportError:
|
||||
def addCleanUp(x):
|
||||
pass
|
||||
|
||||
events = []
|
||||
def getEvents(event_type=None, filter=None):
|
||||
r = []
|
||||
for event in events:
|
||||
if event_type is not None and not event_type.providedBy(event):
|
||||
continue
|
||||
if filter is not None and not filter(event):
|
||||
continue
|
||||
r.append(event)
|
||||
|
||||
return r
|
||||
|
||||
def clearEvents():
|
||||
del events[:]
|
||||
addCleanUp(clearEvents)
|
||||
|
||||
class PlacelessSetup:
|
||||
|
||||
def setUp(self):
|
||||
provideHandler(objectEventNotify)
|
||||
provideHandler(dispatchUtilityRegistrationEvent)
|
||||
provideHandler(dispatchAdapterRegistrationEvent)
|
||||
provideHandler(dispatchSubscriptionAdapterRegistrationEvent)
|
||||
provideHandler(dispatchHandlerRegistrationEvent)
|
||||
provideHandler(events.append, (None,))
|
||||
|
||||
def setUp(test=None):
|
||||
PlacelessSetup().setUp()
|
||||
@@ -0,0 +1,47 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Factory object
|
||||
"""
|
||||
from zope.interface import implementer
|
||||
from zope.interface import implementedBy
|
||||
from zope.interface.declarations import Implements
|
||||
from zope.component.interfaces import IFactory
|
||||
|
||||
|
||||
@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.
|
||||
"""
|
||||
|
||||
def __init__(self, callable, title='', description='', interfaces=None):
|
||||
self._callable = callable
|
||||
self.title = title
|
||||
self.description = description
|
||||
self._interfaces = interfaces
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
return self._callable(*args, **kw)
|
||||
|
||||
def getInterfaces(self):
|
||||
if self._interfaces is not None:
|
||||
spec = Implements(*self._interfaces)
|
||||
spec.__name__ = getattr(self._callable, '__name__', '[callable]')
|
||||
return spec
|
||||
return implementedBy(self._callable)
|
||||
|
||||
def __repr__(self): #pragma NO COVER
|
||||
return '<%s for %s>' % (self.__class__.__name__, repr(self._callable))
|
||||
@@ -0,0 +1,79 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Global components support
|
||||
"""
|
||||
from zope.interface import implementer
|
||||
from zope.interface.adapter import AdapterRegistry
|
||||
from zope.interface.registry import Components
|
||||
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
|
||||
|
||||
def GAR(components, registryName):
|
||||
return getattr(components, registryName)
|
||||
|
||||
class GlobalAdapterRegistry(AdapterRegistry):
|
||||
"""A global adapter registry
|
||||
|
||||
This adapter registry's main purpose is to be picklable in combination
|
||||
with a site manager."""
|
||||
|
||||
def __init__(self, parent, name):
|
||||
self.__parent__ = parent
|
||||
self.__name__ = name
|
||||
super(GlobalAdapterRegistry, self).__init__()
|
||||
|
||||
def __reduce__(self):
|
||||
return GAR, (self.__parent__, self.__name__)
|
||||
|
||||
@implementer(IComponentLookup)
|
||||
class BaseGlobalComponents(Components):
|
||||
|
||||
def _init_registries(self):
|
||||
self.adapters = GlobalAdapterRegistry(self, 'adapters')
|
||||
self.utilities = GlobalAdapterRegistry(self, 'utilities')
|
||||
|
||||
def __reduce__(self):
|
||||
# Global site managers are pickled as global objects
|
||||
return self.__name__
|
||||
|
||||
base = BaseGlobalComponents('base')
|
||||
|
||||
try:
|
||||
from zope.testing.cleanup import addCleanUp
|
||||
except ImportError: #pragma NO COVER
|
||||
pass
|
||||
else:
|
||||
addCleanUp(lambda: base.__init__('base'))
|
||||
del addCleanUp
|
||||
|
||||
globalSiteManager = base
|
||||
def getGlobalSiteManager():
|
||||
return globalSiteManager
|
||||
|
||||
# The following APIs provide global registration support for Python code.
|
||||
# We eventually want to deprecate these in favor of using the global
|
||||
# component registry directly.
|
||||
|
||||
def provideUtility(component, provides=None, name=u''):
|
||||
base.registerUtility(component, provides, name, event=False)
|
||||
|
||||
def provideAdapter(factory, adapts=None, provides=None, name=u''):
|
||||
base.registerAdapter(factory, adapts, provides, name, event=False)
|
||||
|
||||
def provideSubscriptionAdapter(factory, adapts=None, provides=None):
|
||||
base.registerSubscriptionAdapter(factory, adapts, provides, event=False)
|
||||
|
||||
def provideHandler(factory, adapts=None):
|
||||
base.registerHandler(factory, adapts, event=False)
|
||||
@@ -0,0 +1,19 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
This module is deprecated. Prefer to use zope.hookable.hookable.
|
||||
"""
|
||||
# pragma: no cover
|
||||
import zope.deprecation
|
||||
zope.deprecation.moved("zope.hookable", "4.5")
|
||||
@@ -0,0 +1,148 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Hooks for getting and setting a site in the thread global namespace.
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
import contextlib
|
||||
import threading
|
||||
|
||||
try:
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
except ImportError: #pragma NO COVER
|
||||
def removeSecurityProxy(x):
|
||||
return x
|
||||
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
from zope.interface.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
|
||||
|
||||
def __get__(self, inst, cls):
|
||||
if inst is None:
|
||||
return self
|
||||
|
||||
return self.func(inst)
|
||||
|
||||
class SiteInfo(threading.local):
|
||||
site = None
|
||||
sm = getGlobalSiteManager()
|
||||
|
||||
@read_property
|
||||
def adapter_hook(self):
|
||||
adapter_hook = self.sm.adapters.adapter_hook
|
||||
self.adapter_hook = adapter_hook
|
||||
return adapter_hook
|
||||
|
||||
siteinfo = SiteInfo()
|
||||
|
||||
def setSite(site=None):
|
||||
if site is None:
|
||||
sm = getGlobalSiteManager()
|
||||
else:
|
||||
|
||||
# We remove the security proxy because there's no way for
|
||||
# untrusted code to get at it without it being proxied again.
|
||||
|
||||
# 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.
|
||||
|
||||
site = removeSecurityProxy(site)
|
||||
# The getSiteManager method is defined by IPossibleSite.
|
||||
sm = site.getSiteManager()
|
||||
|
||||
siteinfo.site = site
|
||||
siteinfo.sm = sm
|
||||
try:
|
||||
del siteinfo.adapter_hook
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def getSite():
|
||||
return siteinfo.site
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def site(site):
|
||||
old_site = getSite()
|
||||
setSite(site)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
setSite(old_site)
|
||||
|
||||
|
||||
def getSiteManager(context=None):
|
||||
"""A special hook for getting the site manager.
|
||||
|
||||
Here we take the currently set site into account to find the appropriate
|
||||
site manager.
|
||||
"""
|
||||
if context is None:
|
||||
return siteinfo.sm
|
||||
|
||||
# We remove the security proxy because there's no way for
|
||||
# untrusted code to get at it without it being proxied again.
|
||||
|
||||
# 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 = 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 ComponentLookupError:
|
||||
return default
|
||||
|
||||
|
||||
def setHooks():
|
||||
from zope.component import _api
|
||||
_api.adapter_hook.sethook(adapter_hook)
|
||||
_api.getSiteManager.sethook(getSiteManager)
|
||||
|
||||
def resetHooks():
|
||||
# Reset hookable functions to original implementation.
|
||||
from zope.component import _api
|
||||
_api.adapter_hook.reset()
|
||||
_api.getSiteManager.reset()
|
||||
# be sure the old adapter hook isn't cached, since
|
||||
# it is derived from the SiteManager
|
||||
try:
|
||||
del siteinfo.adapter_hook
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Clear the site thread global
|
||||
clearSite = setSite
|
||||
try:
|
||||
from zope.testing.cleanup import addCleanUp
|
||||
except ImportError: #pragma NO COVER
|
||||
pass
|
||||
else:
|
||||
addCleanUp(resetHooks)
|
||||
@@ -0,0 +1,116 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Interface utility functions
|
||||
"""
|
||||
from zope.interface import alsoProvides
|
||||
from zope.interface.interfaces import IInterface
|
||||
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
from zope.component._api import queryUtility
|
||||
from zope.component._compat import CLASS_TYPES
|
||||
|
||||
|
||||
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, CLASS_TYPES):
|
||||
raise TypeError(id, "is not an interface or class")
|
||||
return
|
||||
|
||||
if iface_type is not None:
|
||||
if not iface_type.extends(IInterface):
|
||||
raise TypeError(iface_type, "is not an interface type")
|
||||
alsoProvides(interface, iface_type)
|
||||
else:
|
||||
iface_type = IInterface
|
||||
|
||||
gsm = getGlobalSiteManager()
|
||||
gsm.registerUtility(interface, iface_type, id, info)
|
||||
|
||||
|
||||
def getInterface(context, id):
|
||||
"""Return interface or raise ComponentLookupError
|
||||
"""
|
||||
iface = queryInterface(id, None)
|
||||
if iface is None:
|
||||
raise ComponentLookupError(id)
|
||||
return iface
|
||||
|
||||
|
||||
def queryInterface(id, default=None):
|
||||
"""Return an interface or ``None``
|
||||
"""
|
||||
return queryUtility(IInterface, id, default)
|
||||
|
||||
|
||||
def searchInterface(context, search_string=None, base=None):
|
||||
"""Interfaces search
|
||||
"""
|
||||
return [iface_util[1] for iface_util in
|
||||
searchInterfaceUtilities(context, search_string, base)]
|
||||
|
||||
|
||||
def searchInterfaceIds(context, search_string=None, base=None):
|
||||
"""Interfaces search
|
||||
"""
|
||||
return [iface_util[0] for iface_util in
|
||||
searchInterfaceUtilities(context, search_string, base)]
|
||||
|
||||
|
||||
def searchInterfaceUtilities(context, search_string=None, base=None):
|
||||
gsm = getGlobalSiteManager()
|
||||
iface_utilities = gsm.getUtilitiesFor(IInterface)
|
||||
|
||||
if search_string:
|
||||
search_string = search_string.lower()
|
||||
iface_utilities = [iface_util for iface_util in iface_utilities
|
||||
if (getInterfaceAllDocs(iface_util[1]).
|
||||
find(search_string) >= 0)]
|
||||
if base:
|
||||
res = [iface_util for iface_util in iface_utilities
|
||||
if iface_util[1].isOrExtends(base)]
|
||||
else:
|
||||
res = [iface_util for iface_util in iface_utilities]
|
||||
return res
|
||||
|
||||
|
||||
def getInterfaceAllDocs(interface):
|
||||
iface_id = '%s.%s' % (interface.__module__, interface.__name__)
|
||||
docs = [str(iface_id).lower(),
|
||||
str(interface.__doc__).lower()]
|
||||
|
||||
if IInterface.providedBy(interface):
|
||||
for name in sorted(interface):
|
||||
docs.append(
|
||||
str(interface.getDescriptionFor(name).__doc__).lower())
|
||||
|
||||
return '\n'.join(docs)
|
||||
|
||||
|
||||
def nameToInterface(context, id):
|
||||
if id == 'None':
|
||||
return None
|
||||
iface = getInterface(context, id)
|
||||
return iface
|
||||
|
||||
|
||||
def interfaceToName(context, interface):
|
||||
if interface is None:
|
||||
return 'None'
|
||||
return '%s.%s' % (interface.__module__, interface.__name__)
|
||||
@@ -0,0 +1,437 @@
|
||||
############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
"""Component and Component Architecture Interfaces
|
||||
"""
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
|
||||
|
||||
# BBB 2011-09-09, import interfaces from zope.interface
|
||||
import zope.deferredimport
|
||||
zope.deferredimport.deprecatedFrom(
|
||||
"Import from zope.interface.interfaces",
|
||||
"zope.interface.interfaces",
|
||||
'ComponentLookupError',
|
||||
'Invalid',
|
||||
'IObjectEvent',
|
||||
'ObjectEvent',
|
||||
'IComponentLookup',
|
||||
'IRegistration',
|
||||
'IUtilityRegistration',
|
||||
'_IBaseAdapterRegistration',
|
||||
'IAdapterRegistration',
|
||||
'ISubscriptionAdapterRegistration',
|
||||
'IHandlerRegistration',
|
||||
'IRegistrationEvent',
|
||||
'RegistrationEvent',
|
||||
'IRegistered',
|
||||
'Registered',
|
||||
'IUnregistered',
|
||||
'Unregistered',
|
||||
'IComponentRegistry',
|
||||
'IComponents',
|
||||
)
|
||||
|
||||
|
||||
class IComponentArchitecture(Interface):
|
||||
"""The Component Architecture is defined by two key components: Adapters
|
||||
and Utiltities. Both are managed by site managers. All other components
|
||||
build on top of them.
|
||||
"""
|
||||
# Site Manager API
|
||||
|
||||
def getGlobalSiteManager():
|
||||
"""Return the global site manager.
|
||||
|
||||
This function should never fail and always return an object that
|
||||
provides `IGlobalSiteManager`.
|
||||
"""
|
||||
|
||||
def getSiteManager(context=None):
|
||||
"""Get the nearest site manager in the given context.
|
||||
|
||||
If `context` is `None`, return the global site manager.
|
||||
|
||||
If the `context` is not `None`, it is expected that an adapter
|
||||
from the `context` to `IComponentLookup` can be found. If no
|
||||
adapter is found, a `ComponentLookupError` is raised.
|
||||
|
||||
"""
|
||||
|
||||
# Utility API
|
||||
|
||||
def getUtility(interface, name='', context=None):
|
||||
"""Get the utility that provides interface
|
||||
|
||||
Returns the nearest utility to the context that implements the
|
||||
specified interface. If one is not found, raises
|
||||
ComponentLookupError.
|
||||
"""
|
||||
|
||||
def queryUtility(interface, name='', default=None, context=None):
|
||||
"""Look for the utility that provides interface
|
||||
|
||||
Returns the nearest utility to the context that implements
|
||||
the specified interface. If one is not found, returns default.
|
||||
"""
|
||||
|
||||
def queryNextUtility(context, interface, name='', default=None):
|
||||
"""Query for the next available utility.
|
||||
|
||||
Find the next available utility providing `interface` and having the
|
||||
specified name. If no utility was found, return the specified `default`
|
||||
value.
|
||||
"""
|
||||
|
||||
def getNextUtility(context, interface, name=''):
|
||||
"""Get the next available utility.
|
||||
|
||||
If no utility was found, a `ComponentLookupError` is raised.
|
||||
"""
|
||||
|
||||
def getUtilitiesFor(interface, context=None):
|
||||
"""Return the utilities that provide an interface
|
||||
|
||||
An iterable of utility name-value pairs is returned.
|
||||
"""
|
||||
|
||||
def getAllUtilitiesRegisteredFor(interface, context=None):
|
||||
"""Return all registered utilities for an interface
|
||||
|
||||
This includes overridden utilities.
|
||||
|
||||
An iterable of utility instances is returned. No names are
|
||||
returned.
|
||||
"""
|
||||
|
||||
# Adapter API
|
||||
|
||||
def getAdapter(object,
|
||||
interface=Interface, name=u'',
|
||||
context=None):
|
||||
"""Get a named adapter to an interface for an object
|
||||
|
||||
Returns an adapter that can adapt object to interface. If a matching
|
||||
adapter cannot be found, raises ComponentLookupError.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters' service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
"""
|
||||
|
||||
def getAdapterInContext(object, interface, context):
|
||||
"""Get a special adapter to an interface for an object
|
||||
|
||||
NOTE: This method should only be used if a custom context
|
||||
needs to be provided to provide custom component
|
||||
lookup. Otherwise, call the interface, as in::
|
||||
|
||||
interface(object)
|
||||
|
||||
Returns an adapter that can adapt object to interface. If a matching
|
||||
adapter cannot be found, raises ComponentLookupError.
|
||||
|
||||
Context is adapted to IServiceService, and this adapter's
|
||||
'Adapters' service is used.
|
||||
|
||||
If the object has a __conform__ method, this method will be
|
||||
called with the requested interface. If the method returns a
|
||||
non-None value, that value will be returned. Otherwise, if the
|
||||
object already implements the interface, the object will be
|
||||
returned.
|
||||
"""
|
||||
|
||||
def getMultiAdapter(objects,
|
||||
interface=Interface, name='',
|
||||
context=None):
|
||||
"""Look for a multi-adapter to an interface for an objects
|
||||
|
||||
Returns a multi-adapter that can adapt objects to interface. If a
|
||||
matching adapter cannot be found, raises ComponentLookupError.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters' service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
|
||||
The name consisting of an empty string is reserved for unnamed
|
||||
adapters. The unnamed adapter methods will often call the
|
||||
named adapter methods with an empty string for a name.
|
||||
"""
|
||||
|
||||
def queryAdapter(object, interface=Interface, name=u'',
|
||||
default=None, context=None):
|
||||
"""Look for a named adapter to an interface for an object
|
||||
|
||||
Returns an adapter that can adapt object to interface. If a matching
|
||||
adapter cannot be found, returns the default.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters' service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
"""
|
||||
|
||||
def queryAdapterInContext(object, interface, context, default=None):
|
||||
"""Look for a special adapter to an interface for an object
|
||||
|
||||
NOTE: This method should only be used if a custom context
|
||||
needs to be provided to provide custom component
|
||||
lookup. Otherwise, call the interface, as in::
|
||||
|
||||
interface(object, default)
|
||||
|
||||
Returns an adapter that can adapt object to interface. If a matching
|
||||
adapter cannot be found, returns the default.
|
||||
|
||||
Context is adapted to IServiceService, and this adapter's
|
||||
'Adapters' service is used.
|
||||
|
||||
If the object has a __conform__ method, this method will be
|
||||
called with the requested interface. If the method returns a
|
||||
non-None value, that value will be returned. Otherwise, if the
|
||||
object already implements the interface, the object will be
|
||||
returned.
|
||||
"""
|
||||
|
||||
def queryMultiAdapter(objects,
|
||||
interface=Interface, name=u'',
|
||||
default=None,
|
||||
context=None):
|
||||
"""Look for a multi-adapter to an interface for objects
|
||||
|
||||
Returns a multi-adapter that can adapt objects to interface. If a
|
||||
matching adapter cannot be found, returns the default.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters' service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
|
||||
The name consisting of an empty string is reserved for unnamed
|
||||
adapters. The unnamed adapter methods will often call the
|
||||
named adapter methods with an empty string for a name.
|
||||
"""
|
||||
|
||||
def getAdapters(objects, provided, context=None):
|
||||
"""Look for all matching adapters to a provided interface for objects
|
||||
|
||||
Return a list of adapters that match. If an adapter is named, only the
|
||||
most specific adapter of a given name is returned.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters'
|
||||
service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
"""
|
||||
|
||||
def subscribers(required, provided, context=None):
|
||||
"""Get subscribers
|
||||
|
||||
Subscribers are returned that provide the provided interface
|
||||
and that depend on and are computed from the sequence of
|
||||
required objects.
|
||||
|
||||
If context is None, an application-defined policy is used to choose
|
||||
an appropriate service manager from which to get an 'Adapters'
|
||||
service.
|
||||
|
||||
If 'context' is not None, context is adapted to IServiceService,
|
||||
and this adapter's 'Adapters' service is used.
|
||||
"""
|
||||
|
||||
def handle(*objects):
|
||||
"""Call all of the handlers for the given objects
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def adapts(*interfaces):
|
||||
"""Declare that a class adapts the given interfaces.
|
||||
|
||||
This function can only be used in a class definition.
|
||||
|
||||
(TODO, allow classes to be passed as well as interfaces.)
|
||||
"""
|
||||
|
||||
# Factory service
|
||||
|
||||
def createObject(factory_name, *args, **kwargs):
|
||||
"""Create an object using a factory
|
||||
|
||||
Finds the named factory in the current site and calls it with
|
||||
the given arguments. If a matching factory cannot be found
|
||||
raises ComponentLookupError. Returns the created object.
|
||||
|
||||
A context keyword argument can be provided to cause the
|
||||
factory to be looked up in a location other than the current
|
||||
site. (Of course, this means that it is impossible to pass a
|
||||
keyword argument named "context" to the factory.
|
||||
"""
|
||||
|
||||
def getFactoryInterfaces(name, context=None):
|
||||
"""Get interfaces implemented by a factory
|
||||
|
||||
Finds the factory of the given name that is nearest to the
|
||||
context, and returns the interface or interface tuple that
|
||||
object instances created by the named factory will implement.
|
||||
"""
|
||||
|
||||
def getFactoriesFor(interface, context=None):
|
||||
"""Return a tuple (name, factory) of registered factories that
|
||||
create objects which implement the given interface.
|
||||
"""
|
||||
|
||||
|
||||
class IRegistry(Interface):
|
||||
"""Object that supports component registry
|
||||
"""
|
||||
|
||||
def registrations():
|
||||
"""Return an iterable of component registrations
|
||||
"""
|
||||
|
||||
class IComponentRegistrationConvenience(Interface):
|
||||
"""API for registering components.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
def provideUtility(component, provides=None, name=u''):
|
||||
"""Register a utility globally
|
||||
|
||||
A utility is registered to provide an interface with a
|
||||
name. If a component provides only one interface, then the
|
||||
provides argument can be omitted and the provided interface
|
||||
will be used. (In this case, provides argument can still be
|
||||
provided to provide a less specific interface.)
|
||||
|
||||
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.
|
||||
|
||||
"""
|
||||
|
||||
def provideAdapter(factory, adapts=None, provides=None, name=u''):
|
||||
"""Register an adapter globally
|
||||
|
||||
An adapter is registered to provide an interface with a name
|
||||
for some number of object types. If a factory implements only
|
||||
one interface, then the provides argument can be omitted and
|
||||
the provided interface will be used. (In this case, a provides
|
||||
argument can still be provided to provide a less specific
|
||||
interface.)
|
||||
|
||||
If the factory has an adapts declaration, then the adapts
|
||||
argument can be omitted and the declaration will be used. (An
|
||||
adapts argument can be provided to override the declaration.)
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
def provideSubscriptionAdapter(factory, adapts=None, provides=None):
|
||||
"""Register a subscription adapter
|
||||
|
||||
A subscription adapter is registered to provide an interface
|
||||
for some number of object types. If a factory implements only
|
||||
one interface, then the provides argument can be omitted and
|
||||
the provided interface will be used. (In this case, a provides
|
||||
argument can still be provided to provide a less specific
|
||||
interface.)
|
||||
|
||||
If the factory has an adapts declaration, then the adapts
|
||||
argument can be omitted and the declaration will be used. (An
|
||||
adapts argument can be provided to override the declaration.)
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
def provideHandler(handler, adapts=None):
|
||||
"""Register a handler
|
||||
|
||||
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.
|
||||
|
||||
If the handler has an adapts declaration, then the adapts
|
||||
argument can be omitted and the declaration will be used. (An
|
||||
adapts argument can be provided to override the declaration.)
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
|
||||
class IPossibleSite(Interface):
|
||||
"""An object that could be a site.
|
||||
"""
|
||||
|
||||
def setSiteManager(sitemanager):
|
||||
"""Sets the site manager for this object.
|
||||
"""
|
||||
|
||||
def getSiteManager():
|
||||
"""Returns the site manager contained in this object.
|
||||
|
||||
If there isn't a site manager, raise a component lookup.
|
||||
"""
|
||||
|
||||
class ISite(IPossibleSite):
|
||||
"""Marker interface to indicate that we have a site"""
|
||||
|
||||
class Misused(Exception):
|
||||
"""A component is being used (registered) for the wrong interface."""
|
||||
|
||||
|
||||
class IFactory(Interface):
|
||||
"""A factory is responsible for creating other components."""
|
||||
|
||||
title = Attribute("The factory title.")
|
||||
|
||||
description = Attribute("A brief description of the factory.")
|
||||
|
||||
def __call__(*args, **kw):
|
||||
"""Return an instance of the objects we're a factory for."""
|
||||
|
||||
|
||||
def getInterfaces():
|
||||
"""Get the interfaces implemented by the factory
|
||||
|
||||
Return the interface(s), as an instance of Implements, that objects
|
||||
created by this factory will implement. If the callable's Implements
|
||||
instance cannot be created, an empty Implements instance is returned.
|
||||
"""
|
||||
@@ -0,0 +1,45 @@
|
||||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:meta="http://namespaces.zope.org/meta">
|
||||
|
||||
<meta:directives namespace="http://namespaces.zope.org/zope">
|
||||
|
||||
<meta:directive
|
||||
name="interface"
|
||||
schema="zope.component.zcml.IInterfaceDirective"
|
||||
handler="zope.component.zcml.interface"
|
||||
/>
|
||||
|
||||
<meta:directive
|
||||
name="adapter"
|
||||
schema="zope.component.zcml.IAdapterDirective"
|
||||
handler="zope.component.zcml.adapter"
|
||||
/>
|
||||
|
||||
<meta:directive
|
||||
name="subscriber"
|
||||
schema="zope.component.zcml.ISubscriberDirective"
|
||||
handler="zope.component.zcml.subscriber"
|
||||
/>
|
||||
|
||||
<meta:directive
|
||||
name="utility"
|
||||
schema="zope.component.zcml.IUtilityDirective"
|
||||
handler="zope.component.zcml.utility"
|
||||
/>
|
||||
|
||||
<meta:directive
|
||||
name="view"
|
||||
schema="zope.component.zcml.IViewDirective"
|
||||
handler="zope.component.zcml.view"
|
||||
/>
|
||||
|
||||
<meta:directive
|
||||
name="resource"
|
||||
schema="zope.component.zcml.IResourceDirective"
|
||||
handler="zope.component.zcml.resource"
|
||||
/>
|
||||
|
||||
</meta:directives>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,54 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Persistent component managers
|
||||
"""
|
||||
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(VerifyingAdapterRegistry, Persistent):
|
||||
|
||||
def changed(self, originally_changed):
|
||||
if originally_changed is self:
|
||||
self._p_changed = True
|
||||
super(PersistentAdapterRegistry, self).changed(originally_changed)
|
||||
|
||||
def __getstate__(self):
|
||||
state = super(PersistentAdapterRegistry, self).__getstate__().copy()
|
||||
for name in self._delegated:
|
||||
state.pop(name, 0)
|
||||
state.pop('ro', None)
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
bases = state.pop('__bases__', ())
|
||||
super(PersistentAdapterRegistry, self).__setstate__(state)
|
||||
self._createLookup()
|
||||
self.__bases__ = bases
|
||||
self._v_lookup.changed(self)
|
||||
|
||||
|
||||
class PersistentComponents(Components):
|
||||
|
||||
def _init_registries(self):
|
||||
self.adapters = PersistentAdapterRegistry()
|
||||
self.utilities = PersistentAdapterRegistry()
|
||||
|
||||
def _init_registrations(self):
|
||||
self._utility_registrations = PersistentMapping()
|
||||
self._adapter_registrations = PersistentMapping()
|
||||
self._subscription_registrations = PersistentList()
|
||||
self._handler_registrations = PersistentList()
|
||||
@@ -0,0 +1,56 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Basic components support
|
||||
"""
|
||||
|
||||
from zope.component._api import handle
|
||||
from zope.component._declaration import adapter
|
||||
|
||||
from zope.interface.interfaces import IAdapterRegistration
|
||||
from zope.interface.interfaces import IHandlerRegistration
|
||||
from zope.interface.interfaces import IRegistrationEvent
|
||||
from zope.interface.interfaces import ISubscriptionAdapterRegistration
|
||||
from zope.interface.interfaces import IUtilityRegistration
|
||||
|
||||
# BBB, import component-related from zope.interface
|
||||
import zope.deferredimport
|
||||
zope.deferredimport.deprecatedFrom(
|
||||
"Import from zope.interface.registry",
|
||||
"zope.interface.registry",
|
||||
'Components',
|
||||
'_getUtilityProvided',
|
||||
'_getAdapterProvided',
|
||||
'_getAdapterRequired',
|
||||
'UtilityRegistration',
|
||||
'AdapterRegistration',
|
||||
'SubscriptionRegistration',
|
||||
'HandlerRegistration',
|
||||
)
|
||||
|
||||
|
||||
@adapter(IUtilityRegistration, IRegistrationEvent)
|
||||
def dispatchUtilityRegistrationEvent(registration, event):
|
||||
handle(registration.component, event)
|
||||
|
||||
@adapter(IAdapterRegistration, IRegistrationEvent)
|
||||
def dispatchAdapterRegistrationEvent(registration, event):
|
||||
handle(registration.factory, event)
|
||||
|
||||
@adapter(ISubscriptionAdapterRegistration, IRegistrationEvent)
|
||||
def dispatchSubscriptionAdapterRegistrationEvent(registration, event):
|
||||
handle(registration.factory, event)
|
||||
|
||||
@adapter(IHandlerRegistration, IRegistrationEvent)
|
||||
def dispatchHandlerRegistrationEvent(registration, event):
|
||||
handle(registration.handler, event)
|
||||
@@ -0,0 +1,100 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""zope.security support for the configuration handlers
|
||||
"""
|
||||
from zope.interface import providedBy
|
||||
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
|
||||
|
||||
|
||||
PublicPermission = 'zope.Public'
|
||||
|
||||
class PermissionProxy(ProxyBase):
|
||||
|
||||
__slots__ = ('__Security_checker__', )
|
||||
|
||||
def __providedBy__(self):
|
||||
return providedBy(getProxiedObject(self))
|
||||
__providedBy__ = property(__providedBy__)
|
||||
|
||||
def _checker(_context, permission, allowed_interface, allowed_attributes):
|
||||
if (not allowed_attributes) and (not allowed_interface):
|
||||
allowed_attributes = ["__call__"]
|
||||
|
||||
if permission == PublicPermission:
|
||||
permission = CheckerPublic
|
||||
|
||||
require={}
|
||||
if allowed_attributes:
|
||||
for name in allowed_attributes:
|
||||
require[name] = permission
|
||||
if allowed_interface:
|
||||
for i in allowed_interface:
|
||||
for name in i.names(all=True):
|
||||
require[name] = permission
|
||||
|
||||
checker = Checker(require)
|
||||
return checker
|
||||
|
||||
def proxify(ob, checker=None, provides=None, permission=None):
|
||||
"""Try to get the object proxied with the `checker`, but not too soon
|
||||
|
||||
We really don't want to proxy the object unless we need to.
|
||||
"""
|
||||
|
||||
if checker is None:
|
||||
if provides is None or permission is None:
|
||||
raise ValueError('Required arguments: '
|
||||
'checker or both provides and permissions')
|
||||
if permission == PublicPermission:
|
||||
permission = CheckerPublic
|
||||
checker = InterfaceChecker(provides, permission)
|
||||
ob = PermissionProxy(ob)
|
||||
ob.__Security_checker__ = checker
|
||||
return ob
|
||||
|
||||
def protectedFactory(original_factory, provides, permission):
|
||||
if permission == PublicPermission:
|
||||
permission = CheckerPublic
|
||||
checker = InterfaceChecker(provides, permission)
|
||||
# This has to be named 'factory', aparently, so as not to confuse apidoc :(
|
||||
def factory(*args):
|
||||
ob = original_factory(*args)
|
||||
try:
|
||||
ob.__Security_checker__ = checker
|
||||
except AttributeError:
|
||||
ob = Proxy(ob, checker)
|
||||
return ob
|
||||
factory.factory = original_factory
|
||||
return factory
|
||||
|
||||
def securityAdapterFactory(factory, permission, locate, trusted):
|
||||
if permission == PublicPermission:
|
||||
permission = CheckerPublic
|
||||
if locate or (permission is not None and permission is not CheckerPublic):
|
||||
if trusted:
|
||||
return LocatingTrustedAdapterFactory(factory)
|
||||
else:
|
||||
return LocatingUntrustedAdapterFactory(factory)
|
||||
elif trusted:
|
||||
return TrustedAdapterFactory(factory)
|
||||
else:
|
||||
return factory
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
See: https://bugs.launchpad.net/zope3/+bug/98401
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pickle
|
||||
|
||||
def write(x):
|
||||
sys.stdout.write('%s\n' % x)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.version_info[0] >= 3:
|
||||
# TextIO? Are you kidding me?
|
||||
data = sys.stdin.buffer.read()
|
||||
else:
|
||||
data = sys.stdin.read()
|
||||
sys.path = pickle.loads(data)
|
||||
write('XXXXXXXXXX')
|
||||
for p in sys.path:
|
||||
write('- %s' % p)
|
||||
write('XXXXXXXXXX')
|
||||
|
||||
import zope
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class I1(Interface):
|
||||
pass
|
||||
|
||||
class I2(Interface):
|
||||
pass
|
||||
|
||||
@implementer(I1)
|
||||
class Ob(object):
|
||||
def __repr__(self):
|
||||
return '<instance Ob>'
|
||||
|
||||
ob = Ob()
|
||||
|
||||
@implementer(I2)
|
||||
class Comp(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
write('YYYYYYYYY')
|
||||
for p in zope.__path__:
|
||||
write('- %s' % p)
|
||||
write('YYYYYYYYY')
|
||||
import zope.component
|
||||
|
||||
zope.component.provideAdapter(Comp, (I1,), I2)
|
||||
adapter = I2(ob)
|
||||
write('ZZZZZZZZ')
|
||||
assert adapter.__class__ is Comp
|
||||
assert adapter.context is ob
|
||||
@@ -0,0 +1 @@
|
||||
#Python package
|
||||
@@ -0,0 +1,68 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Sample adapter class for testing
|
||||
"""
|
||||
|
||||
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(Interface):
|
||||
pass
|
||||
|
||||
class I3(Interface):
|
||||
def f1(): pass
|
||||
def f2(): pass
|
||||
def f3(): pass
|
||||
|
||||
class IS(Interface):
|
||||
pass
|
||||
|
||||
|
||||
class Adapter(object):
|
||||
def __init__(self, *args):
|
||||
self.context = args
|
||||
|
||||
@implementer(I1)
|
||||
class A1(Adapter):
|
||||
pass
|
||||
|
||||
@implementer(I2)
|
||||
class A2(Adapter):
|
||||
pass
|
||||
|
||||
@adapter(components.IContent, I1, I2)
|
||||
@implementer(I3)
|
||||
class A3(Adapter):
|
||||
pass
|
||||
|
||||
class A4:
|
||||
pass
|
||||
|
||||
a4 = A4()
|
||||
|
||||
@implementer(I1, I2)
|
||||
class A5:
|
||||
pass
|
||||
|
||||
a5 = A5()
|
||||
|
||||
def Handler(content, *args):
|
||||
# uninteresting handler
|
||||
content.args = getattr(content, 'args', ()) + (args, )
|
||||
@@ -0,0 +1,66 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Components for testing
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import implementer
|
||||
from zope.component import adapter
|
||||
from zope.component import named
|
||||
|
||||
class IAppb(Interface):
|
||||
a = Attribute('test attribute')
|
||||
def f(): "test func"
|
||||
|
||||
class IApp(IAppb):
|
||||
pass
|
||||
|
||||
class IApp2(IAppb):
|
||||
pass
|
||||
|
||||
class IApp3(IAppb):
|
||||
pass
|
||||
|
||||
class IContent(Interface): pass
|
||||
|
||||
@implementer(IContent)
|
||||
class Content(object):
|
||||
pass
|
||||
|
||||
@adapter(IContent)
|
||||
@implementer(IApp)
|
||||
class Comp(object):
|
||||
|
||||
def __init__(self, *args):
|
||||
# Ignore arguments passed to constructor
|
||||
pass
|
||||
|
||||
a = 1
|
||||
def f(): pass
|
||||
|
||||
class Comp2(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
@adapter(IContent)
|
||||
@implementer(IApp)
|
||||
@named('app')
|
||||
class Comp4(object):
|
||||
def __init__(self, context=None):
|
||||
self.context = context
|
||||
|
||||
comp = Comp()
|
||||
comp4 = Comp4()
|
||||
|
||||
content = Content()
|
||||
@@ -0,0 +1,9 @@
|
||||
<configure xmlns="http://namespaces.zope.org/zope">
|
||||
<include package="zope.component" file="meta.zcml" />
|
||||
|
||||
<adapter
|
||||
factory="zope.component.testfiles.components.Comp2"
|
||||
provides="zope.component.testfiles.components.IApp2"
|
||||
for="zope.component.testfiles.components.IContent" />
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,20 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Views test.
|
||||
"""
|
||||
|
||||
from zope.interface import Interface
|
||||
|
||||
class IC(Interface):
|
||||
pass
|
||||
@@ -0,0 +1,37 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Placeless Test Setup
|
||||
"""
|
||||
|
||||
# HACK to make sure basicmost event subscriber is installed
|
||||
import zope.component.event
|
||||
|
||||
# we really don't need special setup now:
|
||||
class _PlacelessSetupFallback(object):
|
||||
def cleanUp(self):
|
||||
from zope.component.globalregistry import base
|
||||
base.__init__('base')
|
||||
|
||||
setUp = tearDown = cleanUp
|
||||
|
||||
try:
|
||||
from zope.testing.cleanup import CleanUp as PlacelessSetup
|
||||
except ImportError: # pragma: no cover
|
||||
PlacelessSetup = _PlacelessSetupFallback
|
||||
|
||||
def setUp(test=None):
|
||||
PlacelessSetup().setUp()
|
||||
|
||||
def tearDown(test=None):
|
||||
PlacelessSetup().tearDown()
|
||||
@@ -0,0 +1,120 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2010 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 os
|
||||
|
||||
from zope.configuration import xmlconfig, config
|
||||
try:
|
||||
from zope.testing.cleanup import cleanUp
|
||||
except ImportError: # pragma: no cover
|
||||
def cleanUp():
|
||||
pass
|
||||
|
||||
from zope.component import provideHandler
|
||||
from zope.component.hooks import setHooks
|
||||
from zope.component.eventtesting import events, clearEvents
|
||||
|
||||
|
||||
class LayerBase(object):
|
||||
"""Sane layer base class.
|
||||
|
||||
zope.testing implements an advanced mechanism so that layer setUp,
|
||||
tearDown, testSetUp and testTearDown code gets called in the right
|
||||
order. These methods are supposed to be @classmethods and should
|
||||
not use super() as the test runner is supposed to take care of that.
|
||||
|
||||
In practice, this mechanism turns out not to be useful and
|
||||
overcomplicated. It becomes difficult to pass information into
|
||||
layers (such as a ZCML file to load), because the only way to pass
|
||||
in information is to subclass, and subclassing these layers leads
|
||||
to a range of interactions that is hard to reason about.
|
||||
|
||||
We'd rather just use Python and the super mechanism, as we know how
|
||||
to reason about that. This base class is a hack to make this
|
||||
possible.
|
||||
|
||||
The hack requires us to set __bases__, __module__ and
|
||||
__name__. This fools zope.testing into thinking that this layer
|
||||
instance is a class it can work with.
|
||||
|
||||
It'd be better if zope.testing just called a minimal API and
|
||||
didn't try to be fancy. Fancy layer inheritance mechanisms can
|
||||
then be implemented elsewhere if people want to. But unfortunately
|
||||
it does implement a fancy mechanism and we need to fool it.
|
||||
"""
|
||||
|
||||
__bases__ = ()
|
||||
|
||||
def __init__(self, package, name=None):
|
||||
if name is None:
|
||||
name = self.__class__.__name__
|
||||
self.__name__ = name
|
||||
self.__module__ = package.__name__
|
||||
self.package = package
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def testSetUp(self):
|
||||
pass
|
||||
|
||||
def testTearDown(self):
|
||||
pass
|
||||
|
||||
class ZCMLLayerBase(LayerBase):
|
||||
"""Base class to load up some ZCML.
|
||||
"""
|
||||
def __init__(self, package, name=None, features=None):
|
||||
super(ZCMLLayerBase, self).__init__(package, name)
|
||||
self.features = features or []
|
||||
|
||||
def setUp(self):
|
||||
setHooks()
|
||||
context = config.ConfigurationMachine()
|
||||
xmlconfig.registerCommonDirectives(context)
|
||||
for feature in self.features:
|
||||
context.provideFeature(feature)
|
||||
self.context = self._load_zcml(context)
|
||||
provideHandler(events.append, (None,))
|
||||
|
||||
def testTearDown(self):
|
||||
clearEvents()
|
||||
|
||||
def tearDown(self):
|
||||
cleanUp()
|
||||
|
||||
def _load_zcml(self, context):
|
||||
raise NotImplementedError
|
||||
|
||||
class ZCMLFileLayer(ZCMLLayerBase):
|
||||
"""This layer can be used to run tests with a ZCML file loaded.
|
||||
|
||||
The ZCML file is assumed to include sufficient (meta)configuration
|
||||
so that it can be interpreted itself. I.e. to create a ZCMLLayer
|
||||
based on another ZCMLLayer's ZCML, just use a ZCML include
|
||||
statement in your own ZCML to load it.
|
||||
"""
|
||||
def __init__(self, package, zcml_file='ftesting.zcml',
|
||||
name=None, features=None):
|
||||
super(ZCMLFileLayer, self).__init__(package, name, features)
|
||||
self.zcml_file = os.path.join(os.path.dirname(package.__file__),
|
||||
zcml_file)
|
||||
|
||||
def _load_zcml(self, context):
|
||||
return xmlconfig.file(self.zcml_file,
|
||||
package=self.package,
|
||||
context=context, execute=True)
|
||||
@@ -0,0 +1,23 @@
|
||||
import unittest
|
||||
|
||||
def skipIfNoSecurity(testfunc):
|
||||
try:
|
||||
import zope.security
|
||||
except ImportError: # pragma: no cover
|
||||
return unittest.skip("zope.security not installed")(testfunc)
|
||||
return testfunc
|
||||
|
||||
def fails_if_called(test, msg="This function must not be called.",
|
||||
arguments=True):
|
||||
"""
|
||||
Return a new function (accepting any arguments)
|
||||
that will call test.fail(msg) if it is called.
|
||||
|
||||
:keyword bool arguments: If set to ``False``, then we will
|
||||
not accept any arguments. This can avoid
|
||||
masking when we would expect a TypeError to be raised by
|
||||
calling an instance method against a class.
|
||||
"""
|
||||
if not arguments:
|
||||
return lambda: test.fail(msg)
|
||||
return lambda *_args, **__kwargs: test.fail(msg)
|
||||
@@ -0,0 +1,142 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Examples supporting Sphinx doctest snippets.
|
||||
"""
|
||||
import sys
|
||||
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.interfaces import IInterface
|
||||
|
||||
from zope.component._declaration import adapter
|
||||
from zope.component.testfiles.views import IC
|
||||
|
||||
def write(x):
|
||||
sys.stdout.write('%s\n' % x)
|
||||
|
||||
class ITestType(IInterface):
|
||||
pass
|
||||
|
||||
|
||||
class I1(Interface):
|
||||
pass
|
||||
|
||||
class I2(Interface):
|
||||
pass
|
||||
|
||||
class I3(Interface):
|
||||
pass
|
||||
|
||||
class I4(Interface):
|
||||
pass
|
||||
|
||||
class IGI(Interface):
|
||||
pass
|
||||
|
||||
class IQI(Interface):
|
||||
pass
|
||||
|
||||
class ISI(Interface):
|
||||
pass
|
||||
|
||||
class ISII(Interface):
|
||||
pass
|
||||
|
||||
class U(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.__name__ = name
|
||||
|
||||
def __repr__(self):
|
||||
return "%s(%s)" % (self.__class__.__name__, self.__name__)
|
||||
|
||||
@implementer(I1)
|
||||
class U1(U):
|
||||
pass
|
||||
|
||||
@implementer(I1, I2)
|
||||
class U12(U):
|
||||
pass
|
||||
|
||||
@adapter(I1)
|
||||
def handle1(x):
|
||||
write('handle1 %s' % x)
|
||||
|
||||
def handle2(*objects):
|
||||
write( 'handle2 ' + repr(objects))
|
||||
|
||||
@adapter(I1)
|
||||
def handle3(x):
|
||||
write( 'handle3 %s' % x)
|
||||
|
||||
@adapter(I1)
|
||||
def handle4(x):
|
||||
write( 'handle4 %s' % x)
|
||||
|
||||
class GlobalRegistry:
|
||||
pass
|
||||
|
||||
from zope.component.globalregistry import GlobalAdapterRegistry
|
||||
base = GlobalAdapterRegistry(GlobalRegistry, 'adapters')
|
||||
GlobalRegistry.adapters = base
|
||||
def clear_base():
|
||||
base.__init__(GlobalRegistry, 'adapters')
|
||||
|
||||
|
||||
@implementer(I1)
|
||||
class Ob(object):
|
||||
def __repr__(self):
|
||||
return '<instance Ob>'
|
||||
|
||||
|
||||
ob = Ob()
|
||||
|
||||
@implementer(I2)
|
||||
class Ob2(object):
|
||||
def __repr__(self):
|
||||
return '<instance Ob2>'
|
||||
|
||||
@implementer(IC)
|
||||
class Ob3(object):
|
||||
pass
|
||||
|
||||
@implementer(I2)
|
||||
class Comp(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
comp = Comp(1)
|
||||
|
||||
|
||||
class ConformsToIComponentLookup(object):
|
||||
"""Allow a dummy sitemanager to conform/adapt to `IComponentLookup`."""
|
||||
|
||||
def __init__(self, sitemanager):
|
||||
self.sitemanager = sitemanager
|
||||
|
||||
def __conform__(self, interface):
|
||||
"""This method is specified by the adapter PEP to do the adaptation."""
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
if interface is IComponentLookup:
|
||||
return self.sitemanager
|
||||
|
||||
|
||||
def clearZCML(test=None):
|
||||
from zope.configuration.xmlconfig import XMLConfig
|
||||
import zope.component
|
||||
from zope.component.testing import setUp
|
||||
from zope.component.testing import tearDown
|
||||
tearDown()
|
||||
setUp()
|
||||
XMLConfig('meta.zcml', zope.component)()
|
||||
@@ -0,0 +1,92 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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 unittest
|
||||
|
||||
class Test_package(unittest.TestCase):
|
||||
|
||||
def test_module_conforms_to_IComponentArchitecture(self):
|
||||
from zope.interface.verify import verifyObject
|
||||
from zope.component.interfaces import IComponentArchitecture
|
||||
import zope.component as zc
|
||||
verifyObject(IComponentArchitecture, zc)
|
||||
|
||||
def test_module_conforms_to_IComponentRegistrationConvenience(self):
|
||||
from zope.interface.verify import verifyObject
|
||||
from zope.component.interfaces import IComponentRegistrationConvenience
|
||||
import zope.component as zc
|
||||
verifyObject(IComponentRegistrationConvenience, zc)
|
||||
|
||||
|
||||
class Test_Interface_call(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def test_miss(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
self.assertRaises(TypeError, IFoo, object())
|
||||
|
||||
def test_miss_w_default(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
marker = object()
|
||||
self.assertTrue(IFoo(object(), marker) is marker)
|
||||
|
||||
def test_hit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@implementer(IBar)
|
||||
class Bar(object):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Baz(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
getGlobalSiteManager().registerAdapter(Baz, (IBar,), IFoo, '')
|
||||
bar = Bar()
|
||||
adapted = IFoo(bar)
|
||||
self.assertTrue(adapted.__class__ is Baz)
|
||||
self.assertTrue(adapted.context is bar)
|
||||
|
||||
def test_hit_registered_for_None(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Baz(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
getGlobalSiteManager().registerAdapter(Baz, (None,), IFoo, '')
|
||||
ctx = object()
|
||||
adapted = IFoo(ctx)
|
||||
self.assertTrue(adapted.__class__ is Baz)
|
||||
self.assertTrue(adapted.context is ctx)
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test_package),
|
||||
unittest.makeSuite(Test_Interface_call),
|
||||
))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,196 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test adapter declaration helpers
|
||||
"""
|
||||
import unittest
|
||||
|
||||
class Test_adapter(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component._declaration import adapter
|
||||
return adapter
|
||||
|
||||
def _makeOne(self, *interfaces):
|
||||
return self._getTargetClass()(*interfaces)
|
||||
|
||||
def test_ctor_no_interfaces(self):
|
||||
deco = self._makeOne()
|
||||
self.assertEqual(list(deco.interfaces), [])
|
||||
|
||||
def test_ctor_w_interfaces(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
deco = self._makeOne(IFoo, IBar)
|
||||
self.assertEqual(list(deco.interfaces), [IFoo, IBar])
|
||||
|
||||
def test__call___w_class(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@self._makeOne(IFoo, IBar)
|
||||
class Baz(object):
|
||||
pass
|
||||
self.assertEqual(Baz.__component_adapts__, (IFoo, IBar))
|
||||
|
||||
def test__call___w_inst_of_decorated_class(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@self._makeOne(IFoo, IBar)
|
||||
class Baz(object):
|
||||
pass
|
||||
baz = Baz()
|
||||
self.assertRaises(AttributeError,
|
||||
getattr, baz, '__component_adapts_')
|
||||
|
||||
def test__call___w_non_class(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
class Baz(object):
|
||||
pass
|
||||
deco = self._makeOne(IFoo, IBar)
|
||||
baz = deco(Baz())
|
||||
self.assertEqual(baz.__component_adapts__, (IFoo, IBar))
|
||||
|
||||
|
||||
class Test_adapts(unittest.TestCase):
|
||||
|
||||
def _run_generated_code(self, code, globs, locs):
|
||||
import warnings
|
||||
with warnings.catch_warnings(record=True) as log:
|
||||
warnings.resetwarnings()
|
||||
exec(code, globs, locs)
|
||||
self.assertEqual(len(log), 0) # no longer warn
|
||||
return True
|
||||
|
||||
def test_instances_not_affected(self):
|
||||
from zope.component._declaration import adapts
|
||||
class C(object):
|
||||
adapts()
|
||||
|
||||
self.assertEqual(C.__component_adapts__, ())
|
||||
def _try():
|
||||
return C().__component_adapts__
|
||||
self.assertRaises(AttributeError, _try)
|
||||
|
||||
def test_called_from_function(self):
|
||||
import warnings
|
||||
from zope.component._declaration import adapts
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
globs = {'adapts': adapts, 'IFoo': IFoo}
|
||||
locs = {}
|
||||
CODE = "\n".join([
|
||||
'def foo():',
|
||||
' adapts(IFoo)'
|
||||
])
|
||||
self._run_generated_code(CODE, globs, locs)
|
||||
foo = locs['foo']
|
||||
with warnings.catch_warnings(record=True) as log:
|
||||
warnings.resetwarnings()
|
||||
self.assertRaises(TypeError, foo)
|
||||
self.assertEqual(len(log), 0) # no longer warn
|
||||
|
||||
def test_called_twice_from_class(self):
|
||||
import warnings
|
||||
from zope.component._declaration import adapts
|
||||
from zope.interface import Interface
|
||||
from zope.interface._compat import PYTHON3
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
globs = {'adapts': adapts, 'IFoo': IFoo, 'IBar': IBar}
|
||||
locs = {}
|
||||
CODE = "\n".join([
|
||||
'class Foo(object):',
|
||||
' adapts(IFoo)',
|
||||
' adapts(IBar)',
|
||||
])
|
||||
with warnings.catch_warnings(record=True) as log:
|
||||
warnings.resetwarnings()
|
||||
with self.assertRaises(TypeError):
|
||||
exec(CODE, globs, locs)
|
||||
self.assertEqual(len(log), 0) # no longer warn
|
||||
|
||||
def test_called_once_from_class(self):
|
||||
from zope.component._declaration import adapts
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
globs = {'adapts': adapts, 'IFoo': IFoo}
|
||||
locs = {}
|
||||
CODE = "\n".join([
|
||||
'class Foo(object):',
|
||||
' adapts(IFoo)',
|
||||
])
|
||||
self._run_generated_code(CODE, globs, locs)
|
||||
Foo = locs['Foo']
|
||||
spec = Foo.__component_adapts__
|
||||
self.assertEqual(list(spec), [IFoo])
|
||||
|
||||
|
||||
class Test_adaptedBy(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, obj):
|
||||
from zope.component._declaration import adaptedBy
|
||||
return adaptedBy(obj)
|
||||
|
||||
def test_obj_w_no_attr(self):
|
||||
self.assertEqual(self._callFUT(object()), None)
|
||||
|
||||
def test__call___w_class(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
class Baz(object):
|
||||
__component_adapts__ = (IFoo, IBar)
|
||||
self.assertEqual(self._callFUT(Baz), (IFoo, IBar))
|
||||
|
||||
def test__call___w_inst_of_decorated_class(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component._declaration import _adapts_descr
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
class Baz(object):
|
||||
__component_adapts__ = _adapts_descr((IFoo, IBar))
|
||||
baz = Baz()
|
||||
self.assertEqual(self._callFUT(baz), None)
|
||||
|
||||
def test__call___w_non_class(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
class Baz(object):
|
||||
pass
|
||||
baz = Baz()
|
||||
baz.__component_adapts__ = (IFoo, IBar)
|
||||
self.assertEqual(self._callFUT(baz), (IFoo, IBar))
|
||||
@@ -0,0 +1,65 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test adapter declaration helpers
|
||||
"""
|
||||
import unittest
|
||||
|
||||
class Test_dispatch(unittest.TestCase):
|
||||
|
||||
def test_it(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.component.event import dispatch
|
||||
_adapted = []
|
||||
def _adapter(context):
|
||||
_adapted.append(context)
|
||||
return object()
|
||||
gsm = getGlobalSiteManager()
|
||||
gsm.registerHandler(_adapter, (Interface,))
|
||||
del _adapted[:] # clear handler reg
|
||||
event = object()
|
||||
dispatch(event)
|
||||
self.assertEqual(_adapted, [event])
|
||||
|
||||
class Test_objectEventNotify(unittest.TestCase):
|
||||
|
||||
def test_it(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.interface.interfaces import IObjectEvent
|
||||
from zope.component.event import objectEventNotify
|
||||
_adapted = []
|
||||
def _adapter(context, event):
|
||||
_adapted.append((context, event))
|
||||
return object()
|
||||
gsm = getGlobalSiteManager()
|
||||
gsm.registerHandler(_adapter, (Interface, IObjectEvent))
|
||||
del _adapted[:] # clear handler reg
|
||||
@implementer(IObjectEvent)
|
||||
class _ObjectEvent(object):
|
||||
def __init__(self, object):
|
||||
self.object = object
|
||||
context = object()
|
||||
event = _ObjectEvent(context)
|
||||
objectEventNotify(event)
|
||||
self.assertEqual(_adapted, [(context, event)])
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test_dispatch),
|
||||
unittest.makeSuite(Test_objectEventNotify),
|
||||
))
|
||||
@@ -0,0 +1,103 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for z.c.factory
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.component.tests import fails_if_called
|
||||
|
||||
class FactoryTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.factory import Factory
|
||||
return Factory
|
||||
|
||||
def _makeOne(self, callable=None, *args, **kw):
|
||||
if callable is None:
|
||||
callable = fails_if_called(self)
|
||||
return self._getTargetClass()(callable, *args, **kw)
|
||||
|
||||
def test_class_conforms_to_IFactory(self):
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.component.interfaces import IFactory
|
||||
verifyClass(IFactory, self._getTargetClass())
|
||||
|
||||
def test_instance_conforms_to_IFactory(self):
|
||||
from zope.interface.verify import verifyObject
|
||||
from zope.component.interfaces import IFactory
|
||||
verifyObject(IFactory, self._makeOne())
|
||||
|
||||
def test_ctor_defaults(self):
|
||||
func = fails_if_called(self)
|
||||
factory = self._makeOne(func)
|
||||
self.assertEqual(factory._callable, func)
|
||||
self.assertEqual(factory.title, '')
|
||||
self.assertEqual(factory.description, '')
|
||||
self.assertEqual(factory._interfaces, None)
|
||||
|
||||
def test_ctor_expclit(self):
|
||||
factory = self._makeOne(fails_if_called(self), 'TITLE', 'DESCRIPTION')
|
||||
self.assertEqual(factory.title, 'TITLE')
|
||||
self.assertEqual(factory.description, 'DESCRIPTION')
|
||||
|
||||
def test___call___no_args(self):
|
||||
_called = []
|
||||
def _callable(*args, **kw):
|
||||
_called.append((args, kw))
|
||||
factory = self._makeOne(_callable)
|
||||
factory()
|
||||
self.assertEqual(_called, [((), {})])
|
||||
|
||||
def test___call___positional_args(self):
|
||||
_called = []
|
||||
def _callable(*args, **kw):
|
||||
_called.append((args, kw))
|
||||
factory = self._makeOne(_callable)
|
||||
factory('one', 'two')
|
||||
self.assertEqual(_called, [(('one', 'two'), {})])
|
||||
|
||||
def test___call___keyword_args(self):
|
||||
_called = []
|
||||
def _callable(*args, **kw):
|
||||
_called.append((args, kw))
|
||||
factory = self._makeOne(_callable)
|
||||
factory(foo='bar')
|
||||
self.assertEqual(_called, [((), {'foo': 'bar'})])
|
||||
|
||||
def test_getInterfaces_explicit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
class IBaz(Interface):
|
||||
pass
|
||||
_callable = fails_if_called(self)
|
||||
_callable.__name__ = '_callable'
|
||||
_callable = implementer(IBaz)(_callable)
|
||||
factory = self._makeOne(_callable, interfaces=(IFoo, IBar))
|
||||
spec = factory.getInterfaces()
|
||||
self.assertEqual(spec.__name__, '_callable')
|
||||
self.assertEqual(list(spec), [IFoo, IBar])
|
||||
|
||||
def test_getInterfaces_implicit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
class IBaz(Interface):
|
||||
pass
|
||||
_callable = implementer(IBaz)(fails_if_called(self))
|
||||
factory = self._makeOne(_callable)
|
||||
spec = factory.getInterfaces()
|
||||
self.assertEqual(list(spec), [IBaz])
|
||||
@@ -0,0 +1,246 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" Tests for z.c._api
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.component.tests import fails_if_called
|
||||
|
||||
class Test_getGlobalSiteManager(unittest.TestCase):
|
||||
|
||||
def _callFUT(self):
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
return getGlobalSiteManager()
|
||||
|
||||
def test_gsm_is_IComponentLookup(self):
|
||||
from zope.component.globalregistry import base
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
gsm = self._callFUT()
|
||||
self.assertTrue(gsm is base)
|
||||
self.assertTrue(IComponentLookup.providedBy(gsm))
|
||||
|
||||
def test_gsm_is_singleton(self):
|
||||
gsm = self._callFUT()
|
||||
self.assertTrue(self._callFUT() is gsm)
|
||||
|
||||
def test_gsm_pickling(self):
|
||||
from zope.component._compat import _pickle
|
||||
gsm = self._callFUT()
|
||||
dumped = _pickle.dumps(gsm)
|
||||
loaded = _pickle.loads(dumped)
|
||||
self.assertTrue(loaded is gsm)
|
||||
|
||||
dumped_utilities = _pickle.dumps(gsm.utilities)
|
||||
loaded_utilities = _pickle.loads(dumped_utilities)
|
||||
self.assertTrue(loaded_utilities is gsm.utilities)
|
||||
|
||||
dumped_adapters = _pickle.dumps(gsm.adapters)
|
||||
loaded_adapters = _pickle.loads(dumped_adapters)
|
||||
self.assertTrue(loaded_adapters is gsm.adapters)
|
||||
|
||||
|
||||
class Test_provideUtility(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.globalregistry import provideUtility
|
||||
return provideUtility(*args, **kw)
|
||||
|
||||
def test_anonymous_no_provides(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
foo = Foo()
|
||||
self._callFUT(foo)
|
||||
gsm = getGlobalSiteManager()
|
||||
self.assertIs(gsm.getUtility(IFoo, ''), foo)
|
||||
|
||||
# We can clean it up using the fallback and it will be gone
|
||||
from zope.component.testing import _PlacelessSetupFallback
|
||||
_PlacelessSetupFallback().cleanUp()
|
||||
self.assertIsNone(gsm.queryUtility(IFoo, ''))
|
||||
|
||||
def test_named_w_provides(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class Foo(object):
|
||||
pass
|
||||
foo = Foo()
|
||||
self._callFUT(foo, IFoo, 'named')
|
||||
gsm = getGlobalSiteManager()
|
||||
self.assertTrue(gsm.getUtility(IFoo, 'named') is foo)
|
||||
|
||||
|
||||
class Test_provideAdapter(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.globalregistry import provideAdapter
|
||||
return provideAdapter(*args, **kw)
|
||||
|
||||
def test_anonymous_no_provides_no_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.component._declaration import adapter
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
@adapter(IFoo)
|
||||
@implementer(IBar)
|
||||
class Bar(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self._callFUT(Bar)
|
||||
gsm = getGlobalSiteManager()
|
||||
foo = Foo()
|
||||
adapted = gsm.getAdapter(foo, IBar)
|
||||
self.assertTrue(isinstance(adapted, Bar))
|
||||
self.assertTrue(adapted.context is foo)
|
||||
|
||||
def test_named_w_provides_w_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self._callFUT(Bar, (IFoo,), IBar, 'test')
|
||||
gsm = getGlobalSiteManager()
|
||||
foo = Foo()
|
||||
adapted = gsm.getAdapter(foo, IBar, name='test')
|
||||
self.assertTrue(isinstance(adapted, Bar))
|
||||
self.assertTrue(adapted.context is foo)
|
||||
|
||||
|
||||
class Test_provideSubscriptionAdapter(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.globalregistry import provideSubscriptionAdapter
|
||||
return provideSubscriptionAdapter(*args, **kw)
|
||||
|
||||
def test_no_provides_no_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.component._declaration import adapter
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
@adapter(IFoo)
|
||||
@implementer(IBar)
|
||||
class Bar(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self._callFUT(Bar)
|
||||
gsm = getGlobalSiteManager()
|
||||
foo = Foo()
|
||||
adapted = gsm.subscribers((foo,), IBar)
|
||||
self.assertEqual(len(adapted), 1)
|
||||
self.assertTrue(isinstance(adapted[0], Bar))
|
||||
self.assertTrue(adapted[0].context is foo)
|
||||
|
||||
def test_w_provides_w_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
self._callFUT(Bar, (IFoo,), IBar)
|
||||
gsm = getGlobalSiteManager()
|
||||
foo = Foo()
|
||||
adapted = gsm.subscribers((foo,), IBar)
|
||||
self.assertEqual(len(adapted), 1)
|
||||
self.assertTrue(isinstance(adapted[0], Bar))
|
||||
self.assertTrue(adapted[0].context is foo)
|
||||
|
||||
|
||||
class Test_provideHandler(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.globalregistry import provideHandler
|
||||
return provideHandler(*args, **kw)
|
||||
|
||||
def test_no_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface import providedBy
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.component._declaration import adapter
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
_handler = adapter(IFoo)(fails_if_called(self))
|
||||
|
||||
self._callFUT(_handler)
|
||||
gsm = getGlobalSiteManager()
|
||||
regs = list(gsm.registeredHandlers())
|
||||
self.assertEqual(len(regs), 1)
|
||||
hr = regs[0]
|
||||
self.assertEqual(list(hr.required), list(providedBy(Foo())))
|
||||
self.assertEqual(hr.name, '')
|
||||
self.assertTrue(hr.factory is _handler)
|
||||
|
||||
def test_w_adapts(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
_handler = fails_if_called(self)
|
||||
self._callFUT(_handler, (IFoo,))
|
||||
gsm = getGlobalSiteManager()
|
||||
regs = list(gsm.registeredHandlers())
|
||||
self.assertEqual(len(regs), 1)
|
||||
hr = regs[0]
|
||||
self.assertEqual(list(hr.required), [IFoo])
|
||||
self.assertEqual(hr.name, '')
|
||||
self.assertTrue(hr.factory is _handler)
|
||||
@@ -0,0 +1,352 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for z.c.hooks
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
class Test_read_property(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.hooks import read_property
|
||||
return read_property
|
||||
|
||||
def test_via_instance(self):
|
||||
class Foo(object):
|
||||
@self._getTargetClass()
|
||||
def bar(self):
|
||||
return 'BAR'
|
||||
foo = Foo()
|
||||
self.assertEqual(foo.bar, 'BAR')
|
||||
foo.bar = 'BAZ'
|
||||
self.assertEqual(foo.bar, 'BAZ')
|
||||
del foo.bar
|
||||
self.assertEqual(foo.bar, 'BAR')
|
||||
|
||||
def test_via_class(self):
|
||||
class Foo(object):
|
||||
@self._getTargetClass()
|
||||
def bar(self):
|
||||
return 'BAR'
|
||||
bar = Foo.bar
|
||||
self.assertTrue(isinstance(bar, self._getTargetClass()))
|
||||
self.assertEqual(bar.func(object()), 'BAR')
|
||||
|
||||
|
||||
class SiteInfoTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.hooks import SiteInfo
|
||||
return SiteInfo
|
||||
|
||||
def _makeOne(self):
|
||||
return self._getTargetClass()()
|
||||
|
||||
def test_initial(self):
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
si = self._makeOne()
|
||||
self.assertEqual(si.site, None)
|
||||
self.assertTrue(si.sm is gsm)
|
||||
|
||||
def test_adapter_hook(self):
|
||||
_hook = object()
|
||||
class _Registry(object):
|
||||
adapter_hook = _hook
|
||||
class _SiteManager(object):
|
||||
adapters = _Registry()
|
||||
si = self._makeOne()
|
||||
si.sm = _SiteManager()
|
||||
self.assertFalse('adapter_hook' in si.__dict__)
|
||||
self.assertTrue(si.adapter_hook is _hook)
|
||||
self.assertTrue('adapter_hook' in si.__dict__)
|
||||
del si.adapter_hook
|
||||
self.assertFalse('adapter_hook' in si.__dict__)
|
||||
|
||||
|
||||
class Test_setSite(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, site):
|
||||
from zope.component.hooks import setSite
|
||||
return setSite(site)
|
||||
|
||||
def test_w_None(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
_SM2 = object()
|
||||
_SITE = object()
|
||||
_HOOK = object()
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.sm = _SM2
|
||||
siteinfo.site = _SITE
|
||||
siteinfo.adapterhook = _HOOK
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self._callFUT(None)
|
||||
self.assertTrue(siteinfo.sm is gsm)
|
||||
self.assertTrue(siteinfo.site is None)
|
||||
self.assertFalse('adapter_hook' in siteinfo.__dict__)
|
||||
|
||||
def test_w_site(self):
|
||||
from zope.component import hooks
|
||||
_SM2 = object()
|
||||
class _Site(object):
|
||||
def getSiteManager(self):
|
||||
return _SM2
|
||||
siteinfo = _DummySiteInfo()
|
||||
_site = _Site()
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self._callFUT(_site)
|
||||
self.assertTrue(siteinfo.sm is _SM2)
|
||||
self.assertTrue(siteinfo.site is _site)
|
||||
self.assertFalse('adapter_hook' in siteinfo.__dict__)
|
||||
|
||||
|
||||
class Test_getSite(unittest.TestCase):
|
||||
|
||||
def _callFUT(self):
|
||||
from zope.component.hooks import getSite
|
||||
return getSite()
|
||||
|
||||
def test_w_None(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
siteinfo = _DummySiteInfo()
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self.assertTrue(self._callFUT() is None)
|
||||
|
||||
def test_w_site(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
_SM2 = object()
|
||||
_SITE = object()
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.sm = _SM2
|
||||
siteinfo.site = _SITE
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self.assertTrue(self._callFUT() is _SITE)
|
||||
|
||||
|
||||
class Test_site(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, new_site):
|
||||
from zope.component.hooks import site
|
||||
return site(new_site)
|
||||
|
||||
def test_it(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
_SM2 = object()
|
||||
class _Site(object):
|
||||
def getSiteManager(self):
|
||||
return _SM2
|
||||
_site = _Site()
|
||||
siteinfo = _DummySiteInfo()
|
||||
self.assertTrue(siteinfo.site is None)
|
||||
self.assertTrue(siteinfo.sm is _SM)
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
with self._callFUT(_site):
|
||||
self.assertTrue(siteinfo.site is _site)
|
||||
self.assertTrue(siteinfo.sm is _SM2)
|
||||
self.assertTrue(siteinfo.site is None)
|
||||
self.assertTrue(siteinfo.sm is gsm)
|
||||
|
||||
|
||||
class Test_getSiteManager(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, context=None):
|
||||
from zope.component.hooks import getSiteManager
|
||||
return getSiteManager(context)
|
||||
|
||||
def test_default(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
_SM2 = object()
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.sm = _SM2
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self.assertTrue(self._callFUT() is _SM2)
|
||||
|
||||
def test_w_explicit_context_no_IComponentLookup(self):
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
_SM2 = object()
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.sm = _SM2
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
self.assertTrue(self._callFUT(object()) is gsm)
|
||||
|
||||
def test_w_explicit_context_w_IComponentLookup(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.interface.interfaces import IComponentLookup
|
||||
class _Lookup(object):
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
gsm = getGlobalSiteManager()
|
||||
gsm.registerAdapter(_Lookup, (Interface,), IComponentLookup, '')
|
||||
_SM2 = object()
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.sm = _SM2
|
||||
context = object()
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
sm = self._callFUT(context)
|
||||
self.assertTrue(isinstance(sm, _Lookup))
|
||||
self.assertTrue(sm.context is context)
|
||||
|
||||
|
||||
class Test_adapter_hook(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, interface, object, name='', default=None):
|
||||
from zope.component.hooks import adapter_hook
|
||||
return adapter_hook(interface, object, name, default)
|
||||
|
||||
def test_success(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm = getGlobalSiteManager()
|
||||
_ADAPTER = object()
|
||||
_DEFAULT = object()
|
||||
_CONTEXT = object()
|
||||
_called = []
|
||||
def _adapter_hook(interface, object, name, default):
|
||||
_called.append((interface, object, name, default))
|
||||
return _ADAPTER
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.adapter_hook = _adapter_hook
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
adapter = self._callFUT(IFoo, _CONTEXT, 'bar', _DEFAULT)
|
||||
self.assertTrue(adapter is _ADAPTER)
|
||||
self.assertEqual(_called, [(IFoo, _CONTEXT, 'bar', _DEFAULT)])
|
||||
|
||||
def test_hook_raises(self):
|
||||
from zope.interface import Interface
|
||||
from zope.component import hooks
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm = getGlobalSiteManager()
|
||||
_DEFAULT = object()
|
||||
_CONTEXT = object()
|
||||
_called = []
|
||||
def _adapter_hook(interface, object, name, default):
|
||||
_called.append((interface, object, name, default))
|
||||
raise ComponentLookupError('testing')
|
||||
siteinfo = _DummySiteInfo()
|
||||
siteinfo.adapter_hook = _adapter_hook
|
||||
with _Monkey(hooks, siteinfo=siteinfo):
|
||||
adapter = self._callFUT(IFoo, _CONTEXT, 'bar', _DEFAULT)
|
||||
self.assertTrue(adapter is _DEFAULT)
|
||||
self.assertEqual(_called, [(IFoo, _CONTEXT, 'bar', _DEFAULT)])
|
||||
|
||||
|
||||
class Test_setHooks(unittest.TestCase):
|
||||
|
||||
def _callFUT(self):
|
||||
from zope.component.hooks import setHooks
|
||||
return setHooks()
|
||||
|
||||
def test_it(self):
|
||||
import zope.component._api
|
||||
from zope.component import hooks
|
||||
class _Hook(object):
|
||||
def __init__(self):
|
||||
self._hooked = None
|
||||
def sethook(self, value):
|
||||
self._hooked = value
|
||||
adapter_hook = _Hook()
|
||||
getSiteManager = _Hook()
|
||||
with _Monkey(zope.component._api,
|
||||
adapter_hook=adapter_hook,
|
||||
getSiteManager=getSiteManager):
|
||||
self._callFUT()
|
||||
self.assertEqual(adapter_hook._hooked, hooks.adapter_hook)
|
||||
self.assertEqual(getSiteManager._hooked, hooks.getSiteManager)
|
||||
|
||||
|
||||
class Test_resetHooks(unittest.TestCase):
|
||||
|
||||
def _callFUT(self):
|
||||
from zope.component.hooks import resetHooks
|
||||
return resetHooks()
|
||||
|
||||
def test_it(self):
|
||||
import zope.component._api
|
||||
from zope.component import hooks
|
||||
class _Hook(object):
|
||||
def __init__(self):
|
||||
self._reset = False
|
||||
def reset(self):
|
||||
self._reset = True
|
||||
adapter_hook = _Hook()
|
||||
getSiteManager = _Hook()
|
||||
with _Monkey(zope.component._api,
|
||||
adapter_hook=adapter_hook,
|
||||
getSiteManager=getSiteManager):
|
||||
# Access the adapter_hook of the site info to be
|
||||
# sure it caches
|
||||
getattr(hooks.siteinfo, 'adapter_hook')
|
||||
self.assertTrue('adapter_hook' in hooks.siteinfo.__dict__)
|
||||
|
||||
self._callFUT()
|
||||
|
||||
self.assertTrue(adapter_hook._reset)
|
||||
self.assertTrue(getSiteManager._reset)
|
||||
# adapter_hook cache also reset
|
||||
self.assertFalse('adapter_hook' in hooks.siteinfo.__dict__)
|
||||
|
||||
|
||||
_SM = object()
|
||||
class _DummySiteInfo(object):
|
||||
sm = _SM
|
||||
site = None
|
||||
|
||||
class _Monkey(object):
|
||||
# context-manager for replacing module names in the scope of a test.
|
||||
def __init__(self, module, **kw):
|
||||
self.module = module
|
||||
self.to_restore = dict([(key, getattr(module, key)) for key in kw])
|
||||
for key, value in kw.items():
|
||||
setattr(module, key, value)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
for key, value in self.to_restore.items():
|
||||
setattr(self.module, key, value)
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test_read_property),
|
||||
unittest.makeSuite(SiteInfoTests),
|
||||
unittest.makeSuite(Test_setSite),
|
||||
unittest.makeSuite(Test_getSite),
|
||||
unittest.makeSuite(Test_site),
|
||||
unittest.makeSuite(Test_getSiteManager),
|
||||
unittest.makeSuite(Test_adapter_hook),
|
||||
unittest.makeSuite(Test_setHooks),
|
||||
unittest.makeSuite(Test_resetHooks),
|
||||
))
|
||||
@@ -0,0 +1,396 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for z.c.interface
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
class Test_provideInterface(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import provideInterface
|
||||
return provideInterface(*args, **kw)
|
||||
|
||||
def test_w_interface_not_IInterface(self):
|
||||
self.assertRaises(TypeError, self._callFUT, 'xxx', object())
|
||||
|
||||
def test_w_iface_type_not_IInterface(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interface import InterfaceClass
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
IBar = InterfaceClass('IBar')
|
||||
self.assertRaises(TypeError, self._callFUT, 'xxx', IFoo, IBar)
|
||||
|
||||
def test_w_class(self):
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IBar(IInterface):
|
||||
pass
|
||||
class Foo(object):
|
||||
pass
|
||||
self._callFUT('', Foo, IBar)
|
||||
self.assertFalse(IBar.providedBy(Foo))
|
||||
self.assertEqual(len(list(gsm.getUtilitiesFor(IBar))), 0)
|
||||
|
||||
def test_wo_name_w_iface_type(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(IInterface):
|
||||
pass
|
||||
self._callFUT('', IFoo, IBar)
|
||||
self.assertTrue(IBar.providedBy(IFoo))
|
||||
nm = 'zope.component.tests.test_interface.IFoo'
|
||||
self.assertTrue(gsm.getUtility(IBar, nm) is IFoo)
|
||||
|
||||
def test_w_name_wo_ifact_type(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
self._callFUT('foo', IFoo)
|
||||
self.assertTrue(IInterface.providedBy(IFoo))
|
||||
registered = gsm.getUtility(IInterface, name='foo')
|
||||
self.assertTrue(registered is IFoo)
|
||||
|
||||
|
||||
class Test_getInterface(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import getInterface
|
||||
return getInterface(*args, **kw)
|
||||
|
||||
def test_miss(self):
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
self.assertRaises(ComponentLookupError,
|
||||
self._callFUT, object(), 'nonesuch')
|
||||
|
||||
def test_hit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertTrue(self._callFUT(object(), 'foo') is IFoo)
|
||||
|
||||
|
||||
class Test_queryInterface(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import queryInterface
|
||||
return queryInterface(*args, **kw)
|
||||
|
||||
def test_miss(self):
|
||||
_DEFAULT = object()
|
||||
self.assertTrue(
|
||||
self._callFUT('nonesuch', default=_DEFAULT) is _DEFAULT)
|
||||
|
||||
def test_hit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertTrue(self._callFUT('foo') is IFoo)
|
||||
|
||||
|
||||
class Test_searchInterface(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import searchInterface
|
||||
return searchInterface(*args, **kw)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual(self._callFUT(object()), [])
|
||||
|
||||
def test_no_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertEqual(self._callFUT(object()), [IFoo])
|
||||
|
||||
def test_w_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), 'IFoo'), [IFoo])
|
||||
|
||||
def test_no_search_string_w_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IBase(Interface):
|
||||
pass
|
||||
class IFoo(IBase):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), base=IBase), [IFoo])
|
||||
|
||||
|
||||
class Test_searchInterfaceIds(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import searchInterfaceIds
|
||||
return searchInterfaceIds(*args, **kw)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual(self._callFUT(object()), [])
|
||||
|
||||
def test_no_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertEqual(self._callFUT(object()), ['foo'])
|
||||
|
||||
def test_w_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), 'IFoo'), ['foo'])
|
||||
|
||||
def test_no_search_string_w_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IBase(Interface):
|
||||
pass
|
||||
class IFoo(IBase):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), base=IBase), ['foo'])
|
||||
|
||||
|
||||
class Test_searchInterfaceUtilities(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import searchInterfaceUtilities
|
||||
return searchInterfaceUtilities(*args, **kw)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual(self._callFUT(object()), [])
|
||||
|
||||
def test_no_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertEqual(self._callFUT(object()), [('foo', IFoo)])
|
||||
|
||||
def test_w_search_string_no_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), 'IFoo'), [('foo', IFoo)])
|
||||
|
||||
def test_no_search_string_w_base(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IBase(Interface):
|
||||
pass
|
||||
class IFoo(IBase):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), base=IBase), [('foo', IFoo)])
|
||||
|
||||
def test_no_search_string_w_base_is_same(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
class IBar(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
gsm.registerUtility(IBar, IInterface, 'bar')
|
||||
self.assertEqual(self._callFUT(object(), base=IFoo), [('foo', IFoo)])
|
||||
|
||||
|
||||
class Test_getInterfaceAllDocs(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import getInterfaceAllDocs
|
||||
return getInterfaceAllDocs(*args, **kw)
|
||||
|
||||
def test_w_class(self):
|
||||
class Foo(object):
|
||||
"""DOCSTRING"""
|
||||
bar = None
|
||||
def baz(self):
|
||||
"""BAZ"""
|
||||
self.assertEqual(self._callFUT(Foo),
|
||||
'zope.component.tests.test_interface.foo\n' +
|
||||
'docstring')
|
||||
|
||||
def test_w_interface_no_members(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
"""DOCSTRING"""
|
||||
self.assertEqual(self._callFUT(IFoo),
|
||||
'zope.component.tests.test_interface.ifoo\n' +
|
||||
'docstring')
|
||||
|
||||
def test_w_interface_w_members(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
"""DOCSTRING"""
|
||||
bar = Attribute('bar', 'Do bar')
|
||||
def baz(self):
|
||||
"""BAZ"""
|
||||
self.assertEqual(self._callFUT(IFoo),
|
||||
'zope.component.tests.test_interface.ifoo\n' +
|
||||
'docstring\n' +
|
||||
'do bar\n' +
|
||||
'baz')
|
||||
|
||||
|
||||
class Test_nameToInterface(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import nameToInterface
|
||||
return nameToInterface(*args, **kw)
|
||||
|
||||
def test_w_None(self):
|
||||
self.assertTrue(self._callFUT(object(), 'None') is None)
|
||||
|
||||
def test_miss(self):
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
self.assertRaises(ComponentLookupError,
|
||||
self._callFUT, object(), 'nonesuch')
|
||||
|
||||
def test_hit(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
found = self._callFUT(object(), 'foo')
|
||||
self.assertTrue(found is IFoo)
|
||||
|
||||
|
||||
class Test_interfaceToName(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.interface import interfaceToName
|
||||
return interfaceToName(*args, **kw)
|
||||
|
||||
def test_w_None(self):
|
||||
self.assertEqual(self._callFUT(object(), None), 'None')
|
||||
|
||||
def test_w_unregistered(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(object(), IFoo),
|
||||
'zope.component.tests.test_interface.IFoo')
|
||||
|
||||
def test_w_registered(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interfaces import IInterface
|
||||
from zope.component.globalregistry import getGlobalSiteManager
|
||||
gsm = getGlobalSiteManager()
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
gsm.registerUtility(IFoo, IInterface, 'foo')
|
||||
self.assertEqual(self._callFUT(object(), IFoo),
|
||||
'zope.component.tests.test_interface.IFoo')
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.TestSuite((
|
||||
unittest.makeSuite(Test_provideInterface),
|
||||
unittest.makeSuite(Test_getInterface),
|
||||
unittest.makeSuite(Test_queryInterface),
|
||||
unittest.makeSuite(Test_searchInterface),
|
||||
unittest.makeSuite(Test_searchInterfaceIds),
|
||||
unittest.makeSuite(Test_searchInterfaceUtilities),
|
||||
unittest.makeSuite(Test_getInterfaceAllDocs),
|
||||
unittest.makeSuite(Test_nameToInterface),
|
||||
unittest.makeSuite(Test_interfaceToName),
|
||||
))
|
||||
@@ -0,0 +1,53 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2017 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
Tests for zope.component.interfaces
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
class TestBackwardsCompat(unittest.TestCase):
|
||||
|
||||
def test_interface_warnings(self):
|
||||
from zope.component import interfaces
|
||||
import warnings
|
||||
for name in (
|
||||
'ComponentLookupError',
|
||||
'Invalid',
|
||||
'IObjectEvent',
|
||||
'ObjectEvent',
|
||||
'IComponentLookup',
|
||||
'IRegistration',
|
||||
'IUtilityRegistration',
|
||||
'_IBaseAdapterRegistration',
|
||||
'IAdapterRegistration',
|
||||
'ISubscriptionAdapterRegistration',
|
||||
'IHandlerRegistration',
|
||||
'IRegistrationEvent',
|
||||
'RegistrationEvent',
|
||||
'IRegistered',
|
||||
'Registered',
|
||||
'IUnregistered',
|
||||
'Unregistered',
|
||||
'IComponentRegistry',
|
||||
'IComponents',
|
||||
):
|
||||
with warnings.catch_warnings(record=True) as log:
|
||||
warnings.simplefilter("always")
|
||||
getattr(interfaces, name)
|
||||
|
||||
self.assertEqual(1, len(log), name)
|
||||
message = str(log[0].message)
|
||||
self.assertIn(name, message)
|
||||
self.assertIn("Import from zope.interface.interfaces", message)
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for z.c.hooks
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
def skipIfNoPersistent(testfunc):
|
||||
try:
|
||||
import persistent
|
||||
except ImportError: # pragma: no cover
|
||||
return unittest.skip("persistent not installed")(testfunc)
|
||||
return testfunc
|
||||
|
||||
@skipIfNoPersistent
|
||||
class PersistentAdapterRegistryTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.persistentregistry import PersistentAdapterRegistry
|
||||
return PersistentAdapterRegistry
|
||||
|
||||
def _makeOne(self, *args, **kw):
|
||||
return self._getTargetClass()(*args, **kw)
|
||||
|
||||
def _makeCache(self, jar):
|
||||
# Borrowed from persistent.tests.test_pyPersistence.
|
||||
|
||||
class _Cache(object):
|
||||
def __init__(self, jar):
|
||||
self._jar = jar
|
||||
self._mru = []
|
||||
# mru(oid) is only called in pure-Python runs
|
||||
self.mru = self._mru.append
|
||||
def new_ghost(self, oid, obj):
|
||||
obj._p_jar = self._jar
|
||||
obj._p_oid = oid
|
||||
def update_object_size_estimation(self, oid, size):
|
||||
"This is only called in pure-Python runs"
|
||||
|
||||
return _Cache(jar)
|
||||
|
||||
def _makeJar(self):
|
||||
# Borrowed from persistent.tests.test_pyPersistence.
|
||||
from zope.interface import implementer
|
||||
from persistent.interfaces import IPersistentDataManager
|
||||
|
||||
@implementer(IPersistentDataManager)
|
||||
class _Jar(object):
|
||||
def __init__(self):
|
||||
self._loaded = []
|
||||
self._registered = []
|
||||
def setstate(self, obj):
|
||||
self._loaded.append(obj._p_oid)
|
||||
def register(self, obj):
|
||||
self._registered.append(obj._p_oid)
|
||||
|
||||
jar = _Jar()
|
||||
jar._cache = self._makeCache(jar)
|
||||
return jar
|
||||
|
||||
def _makeOneWithJar(self, dirty=False, **kw):
|
||||
# Borrowed from persistent.tests.test_pyPersistence.
|
||||
OID = _makeOctets('\x01' * 8)
|
||||
inst = self._makeOne(**kw)
|
||||
jar = self._makeJar()
|
||||
jar._cache.new_ghost(OID, inst) # assigns _p_jar, _p_oid
|
||||
return inst, jar, OID
|
||||
|
||||
def test_changed_original_is_not_us(self):
|
||||
registry, jar, OID = self._makeOneWithJar()
|
||||
self.assertEqual(registry._generation, 1)
|
||||
registry.changed(object())
|
||||
# 'originally_changed' is not us, but we are still dirty because
|
||||
# '_generation' gets bumped.
|
||||
self.assertEqual(registry._p_changed, True)
|
||||
# base class gets called
|
||||
self.assertEqual(registry._generation, 2)
|
||||
|
||||
def test_changed_original_is_us(self):
|
||||
registry, jar, OID = self._makeOneWithJar()
|
||||
self.assertEqual(registry._generation, 1)
|
||||
registry.changed(registry)
|
||||
# 'originally_changed' is not us, so not dirty
|
||||
self.assertEqual(registry._p_changed, True)
|
||||
# base class gets called
|
||||
self.assertEqual(registry._generation, 2)
|
||||
|
||||
def test___getstate___simple(self):
|
||||
from zope.component import globalSiteManager
|
||||
bases = (globalSiteManager.adapters, globalSiteManager.utilities)
|
||||
registry, jar, OID = self._makeOneWithJar(bases=bases)
|
||||
state = registry.__getstate__()
|
||||
self.assertEqual(state['__bases__'], bases)
|
||||
self.assertEqual(state['_generation'], 1)
|
||||
self.assertEqual(state['_provided'], {})
|
||||
self.assertEqual(state['_adapters'], [])
|
||||
self.assertEqual(state['_subscribers'], [])
|
||||
self.assertFalse('ro' in state)
|
||||
|
||||
def test___getstate___skips_delegated_names(self):
|
||||
registry, jar, OID = self._makeOneWithJar()
|
||||
registry.names = lambda *args: ['a', 'b', 'c']
|
||||
self.assertFalse('names' in registry.__getstate__())
|
||||
|
||||
def test___setstate___rebuilds__v_lookup(self):
|
||||
registry, jar, OID = self._makeOneWithJar()
|
||||
state = registry.__getstate__()
|
||||
self.assertTrue('_v_lookup' in registry.__dict__)
|
||||
registry._p_changed = None # clears volatile '_v_lookup'
|
||||
self.assertFalse('_v_lookup' in registry.__dict__)
|
||||
registry.__setstate__(state)
|
||||
self.assertTrue('_v_lookup' in registry.__dict__)
|
||||
|
||||
def test___setstate___rebuilds__ro(self):
|
||||
from zope.component import globalSiteManager
|
||||
bases = (globalSiteManager.adapters, globalSiteManager.utilities)
|
||||
registry, jar, OID = self._makeOneWithJar(bases=bases)
|
||||
state = registry.__getstate__()
|
||||
registry.__setstate__(state)
|
||||
self.assertEqual(registry.__bases__, bases)
|
||||
self.assertEqual(registry.ro, [registry] + list(bases))
|
||||
|
||||
@skipIfNoPersistent
|
||||
class PersistentComponentsTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.persistentregistry import PersistentComponents
|
||||
return PersistentComponents
|
||||
|
||||
def _makeOne(self, *args, **kw):
|
||||
return self._getTargetClass()(*args, **kw)
|
||||
|
||||
def test_ctor_initializes_registries_and_registrations(self):
|
||||
from persistent.mapping import PersistentMapping
|
||||
from persistent.list import PersistentList
|
||||
from zope.component.persistentregistry import PersistentAdapterRegistry
|
||||
registry = self._makeOne()
|
||||
self.assertTrue(isinstance(registry.adapters,
|
||||
PersistentAdapterRegistry))
|
||||
self.assertTrue(isinstance(registry.utilities,
|
||||
PersistentAdapterRegistry))
|
||||
self.assertTrue(isinstance(registry._adapter_registrations,
|
||||
PersistentMapping))
|
||||
self.assertTrue(isinstance(registry._utility_registrations,
|
||||
PersistentMapping))
|
||||
self.assertTrue(isinstance(registry._subscription_registrations,
|
||||
PersistentList))
|
||||
self.assertTrue(isinstance(registry._handler_registrations,
|
||||
PersistentList))
|
||||
|
||||
def _makeOctets(s):
|
||||
return bytes(s) if bytes is str else bytes(s, 'ascii')
|
||||
@@ -0,0 +1,146 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for z.c.registry
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.component.tests import fails_if_called
|
||||
|
||||
class Test_dispatchUtilityRegistrationEvent(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.registry import dispatchUtilityRegistrationEvent
|
||||
return dispatchUtilityRegistrationEvent(*args, **kw)
|
||||
|
||||
def test_it(self):
|
||||
from zope.component import registry
|
||||
class _Registration(object):
|
||||
component = object()
|
||||
_EVENT = object()
|
||||
_handled = []
|
||||
def _handle(*args):
|
||||
_handled.append(args)
|
||||
with _Monkey(registry, handle=_handle):
|
||||
self._callFUT(_Registration(), _EVENT)
|
||||
self.assertEqual(_handled, [(_Registration.component, _EVENT)])
|
||||
|
||||
|
||||
class Test_dispatchAdapterRegistrationEvent(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.registry import dispatchAdapterRegistrationEvent
|
||||
return dispatchAdapterRegistrationEvent(*args, **kw)
|
||||
|
||||
def test_it(self):
|
||||
from zope.component import registry
|
||||
class _Registration(object):
|
||||
factory = fails_if_called(self)
|
||||
_registration = _Registration()
|
||||
_EVENT = object()
|
||||
_handled = []
|
||||
def _handle(*args):
|
||||
_handled.append(args)
|
||||
with _Monkey(registry, handle=_handle):
|
||||
self._callFUT(_registration, _EVENT)
|
||||
self.assertEqual(_handled, [(_registration.factory, _EVENT)])
|
||||
|
||||
|
||||
class Test_dispatchSubscriptionAdapterRegistrationEvent(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.registry \
|
||||
import dispatchSubscriptionAdapterRegistrationEvent
|
||||
return dispatchSubscriptionAdapterRegistrationEvent(*args, **kw)
|
||||
|
||||
def test_it(self):
|
||||
from zope.component import registry
|
||||
class _Registration(object):
|
||||
factory = fails_if_called(self)
|
||||
_registration = _Registration()
|
||||
_EVENT = object()
|
||||
_handled = []
|
||||
def _handle(*args):
|
||||
_handled.append(args)
|
||||
with _Monkey(registry, handle=_handle):
|
||||
self._callFUT(_registration, _EVENT)
|
||||
self.assertEqual(_handled, [(_registration.factory, _EVENT)])
|
||||
|
||||
|
||||
class Test_dispatchHandlerRegistrationEvent(unittest.TestCase):
|
||||
|
||||
from zope.component.testing import setUp, tearDown
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.registry import dispatchHandlerRegistrationEvent
|
||||
return dispatchHandlerRegistrationEvent(*args, **kw)
|
||||
|
||||
def test_it(self):
|
||||
from zope.component import registry
|
||||
class _Registration(object):
|
||||
handler = fails_if_called(self)
|
||||
_registration = _Registration()
|
||||
_EVENT = object()
|
||||
_handled = []
|
||||
def _handle(*args):
|
||||
_handled.append(args)
|
||||
with _Monkey(registry, handle=_handle):
|
||||
self._callFUT(_registration, _EVENT)
|
||||
self.assertEqual(_handled, [(_registration.handler, _EVENT)])
|
||||
|
||||
|
||||
class TestBackwardsCompat(unittest.TestCase):
|
||||
|
||||
def test_interface_warnings(self):
|
||||
from zope.component import registry
|
||||
import warnings
|
||||
for name in (
|
||||
'Components',
|
||||
'_getUtilityProvided',
|
||||
'_getAdapterProvided',
|
||||
'_getAdapterRequired',
|
||||
'UtilityRegistration',
|
||||
'AdapterRegistration',
|
||||
'SubscriptionRegistration',
|
||||
'HandlerRegistration',
|
||||
):
|
||||
with warnings.catch_warnings(record=True) as log:
|
||||
warnings.simplefilter("always")
|
||||
getattr(registry, name)
|
||||
|
||||
self.assertEqual(1, len(log), name)
|
||||
message = str(log[0].message)
|
||||
self.assertIn(name, message)
|
||||
self.assertIn("Import from zope.interface.registry", message)
|
||||
|
||||
|
||||
class _Monkey(object):
|
||||
# context-manager for replacing module names in the scope of a test.
|
||||
def __init__(self, module, **kw):
|
||||
self.module = module
|
||||
self.to_restore = dict([(key, getattr(module, key)) for key in kw])
|
||||
for key, value in kw.items():
|
||||
setattr(module, key, value)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
for key, value in self.to_restore.items():
|
||||
setattr(self.module, key, value)
|
||||
@@ -0,0 +1,240 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
Tests for zope.component.security
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.component.tests import skipIfNoSecurity
|
||||
from zope.component.tests import fails_if_called
|
||||
|
||||
@skipIfNoSecurity
|
||||
class PermissionProxyTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.component.security import PermissionProxy
|
||||
return PermissionProxy
|
||||
|
||||
def _makeOne(self, wrapped):
|
||||
return self._getTargetClass()(wrapped)
|
||||
|
||||
def test_proxy_delegates___provided_by__(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface import providedBy
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
@implementer(IFoo)
|
||||
class Foo(object):
|
||||
pass
|
||||
foo = Foo()
|
||||
proxy = self._makeOne(foo)
|
||||
self.assertEqual(providedBy(proxy), providedBy(foo))
|
||||
|
||||
@skipIfNoSecurity
|
||||
class Test__checker(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.security import _checker
|
||||
return _checker(*args, **kw)
|
||||
|
||||
def test_no_allowed_attributes_no_allowed_interfaces(self):
|
||||
from zope.security.checker import CheckerPublic
|
||||
checker = self._callFUT(object(), 'zope.Public', (), ())
|
||||
self.assertEqual(checker.get_permissions, {'__call__': CheckerPublic})
|
||||
self.assertFalse(checker.set_permissions)
|
||||
|
||||
def test_w_allowed_interfaces(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
def baz(self):
|
||||
"baz"
|
||||
class ISpam(Interface):
|
||||
def qux(self):
|
||||
"qux"
|
||||
checker = self._callFUT(object(), 'testing', (IFoo, ISpam), ())
|
||||
self.assertEqual(checker.get_permissions,
|
||||
{'bar': 'testing', 'baz': 'testing', 'qux': 'testing'})
|
||||
self.assertFalse(checker.set_permissions)
|
||||
|
||||
def test_w_allowed_attributes(self):
|
||||
checker = self._callFUT(object(), 'testing', (), ('foo', 'bar'))
|
||||
self.assertEqual(checker.get_permissions,
|
||||
{'foo': 'testing', 'bar': 'testing'})
|
||||
self.assertFalse(checker.set_permissions)
|
||||
|
||||
@skipIfNoSecurity
|
||||
class Test_proxify(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.security import proxify
|
||||
return proxify(*args, **kw)
|
||||
|
||||
def _makeContext(self):
|
||||
class _Context(object):
|
||||
bar = fails_if_called(self)
|
||||
return _Context()
|
||||
|
||||
def test_no_checker_no_provides(self):
|
||||
ctx = self._makeContext()
|
||||
self.assertRaises(ValueError, self._callFUT, ctx, permission='testing')
|
||||
|
||||
def test_no_checker_no_permission(self):
|
||||
from zope.interface import Interface
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
ctx = self._makeContext()
|
||||
self.assertRaises(ValueError, self._callFUT, ctx, provides=IFoo)
|
||||
|
||||
def test_no_checker_w_provides_and_permission_public(self):
|
||||
from zope.interface import Interface
|
||||
from zope.security.checker import CheckerPublic
|
||||
from zope.proxy import getProxiedObject
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
ctx = self._makeContext()
|
||||
proxy = self._callFUT(ctx, provides=IFoo, permission='zope.Public')
|
||||
self.assertTrue(getProxiedObject(proxy) is ctx)
|
||||
checker = proxy.__Security_checker__
|
||||
self.assertEqual(checker.get_permissions, {'bar': CheckerPublic})
|
||||
self.assertFalse(checker.set_permissions)
|
||||
|
||||
def test_no_checker_w_provides_and_permission_protected(self):
|
||||
from zope.interface import Interface
|
||||
from zope.proxy import getProxiedObject
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
ctx = self._makeContext()
|
||||
proxy = self._callFUT(ctx, provides=IFoo, permission='testing')
|
||||
self.assertTrue(getProxiedObject(proxy) is ctx)
|
||||
checker = proxy.__Security_checker__
|
||||
self.assertEqual(checker.get_permissions, {'bar': 'testing'})
|
||||
self.assertFalse(checker.set_permissions)
|
||||
|
||||
def test_w_checker(self):
|
||||
from zope.proxy import getProxiedObject
|
||||
_CHECKER = object()
|
||||
ctx = self._makeContext()
|
||||
proxy = self._callFUT(ctx, _CHECKER)
|
||||
self.assertTrue(getProxiedObject(proxy) is ctx)
|
||||
self.assertTrue(proxy.__Security_checker__ is _CHECKER)
|
||||
|
||||
@skipIfNoSecurity
|
||||
class Test_protectedFactory(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.security import protectedFactory
|
||||
return protectedFactory(*args, **kw)
|
||||
|
||||
def test_public_not_already_proxied(self):
|
||||
from zope.interface import Interface
|
||||
from zope.security.checker import CheckerPublic
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
class _Factory(object):
|
||||
bar = fails_if_called(self)
|
||||
protected = self._callFUT(_Factory, IFoo, 'zope.Public')
|
||||
self.assertTrue(protected.factory is _Factory)
|
||||
foo = protected()
|
||||
self.assertEqual(foo.__Security_checker__.get_permissions,
|
||||
{'bar': CheckerPublic})
|
||||
|
||||
def test_nonpublic_already_proxied(self):
|
||||
from zope.interface import Interface
|
||||
from zope.security.proxy import getTestProxyItems
|
||||
class IFoo(Interface):
|
||||
def bar(self):
|
||||
"bar"
|
||||
class _Factory(object):
|
||||
__slots__ = ('one',)
|
||||
bar = fails_if_called(self)
|
||||
protected = self._callFUT(_Factory, IFoo, 'testing')
|
||||
self.assertTrue(protected.factory is _Factory)
|
||||
foo = protected()
|
||||
self.assertEqual(getTestProxyItems(foo), [('bar', 'testing')])
|
||||
|
||||
@skipIfNoSecurity
|
||||
class Test_securityAdapterFactory(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.component.security import securityAdapterFactory
|
||||
return securityAdapterFactory(*args, **kw)
|
||||
|
||||
def test_no_permission_untrusted_no_location(self):
|
||||
class _Factory(object):
|
||||
pass
|
||||
self.assertTrue(self._callFUT(_Factory, None, False, False)
|
||||
is _Factory)
|
||||
|
||||
def test_public_untrusted_no_location(self):
|
||||
class _Factory(object):
|
||||
pass
|
||||
self.assertTrue(self._callFUT(_Factory, 'zope.Public', False, False)
|
||||
is _Factory)
|
||||
|
||||
def test_CheckerPublic_untrusted_no_location(self):
|
||||
from zope.security.checker import CheckerPublic
|
||||
class _Factory(object):
|
||||
pass
|
||||
self.assertTrue(self._callFUT(_Factory, CheckerPublic, False, False)
|
||||
is _Factory)
|
||||
|
||||
def test_protected_untrusted_no_location(self):
|
||||
from zope.security.adapter import LocatingUntrustedAdapterFactory
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, 'testing', False, False)
|
||||
self.assertTrue(isinstance(proxy, LocatingUntrustedAdapterFactory))
|
||||
|
||||
def test_no_permission_trusted_no_location(self):
|
||||
from zope.security.adapter import LocatingTrustedAdapterFactory
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, None, False, True)
|
||||
self.assertTrue(isinstance(proxy, LocatingTrustedAdapterFactory))
|
||||
|
||||
def test_public_trusted_no_location(self):
|
||||
from zope.security.adapter import LocatingTrustedAdapterFactory
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, 'zope.Public', False, True)
|
||||
self.assertTrue(isinstance(proxy, LocatingTrustedAdapterFactory))
|
||||
|
||||
def test_CheckerPublic_trusted_no_location(self):
|
||||
from zope.security.adapter import LocatingTrustedAdapterFactory
|
||||
from zope.security.checker import CheckerPublic
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, CheckerPublic, False, True)
|
||||
self.assertTrue(isinstance(proxy, LocatingTrustedAdapterFactory))
|
||||
|
||||
def test_protected_trusted_no_location(self):
|
||||
from zope.security.adapter import LocatingTrustedAdapterFactory
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, 'testing', False, True)
|
||||
self.assertTrue(isinstance(proxy, LocatingTrustedAdapterFactory))
|
||||
|
||||
def test_protected_trusted_w_location(self):
|
||||
from zope.security.adapter import LocatingTrustedAdapterFactory
|
||||
class _Factory(object):
|
||||
pass
|
||||
proxy = self._callFUT(_Factory, 'testing', True, True)
|
||||
self.assertTrue(isinstance(proxy, LocatingTrustedAdapterFactory))
|
||||
@@ -0,0 +1,55 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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 unittest
|
||||
|
||||
from zope.component.tests import skipIfNoSecurity
|
||||
|
||||
@skipIfNoSecurity
|
||||
class StandaloneTests(unittest.TestCase):
|
||||
def testStandalone(self):
|
||||
# See: https://bugs.launchpad.net/zope3/+bug/98401
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import pickle
|
||||
|
||||
executable = os.path.abspath(sys.executable)
|
||||
where = os.path.dirname(os.path.dirname(__file__))
|
||||
program = os.path.join(where, 'standalonetests.py')
|
||||
process = subprocess.Popen([executable, program],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=subprocess.PIPE)
|
||||
try:
|
||||
pickle.dump(sys.path, process.stdin)
|
||||
process.stdin.close()
|
||||
|
||||
try:
|
||||
rc = process.wait()
|
||||
except OSError as e: # pragma: no cover
|
||||
# MacIntel raises apparently unimportant EINTR?
|
||||
if e.errno != 4:
|
||||
raise # TODO verify sanity of a pass on EINTR :-/
|
||||
if rc != 0: # pragma: no cover
|
||||
output = process.stdout.read()
|
||||
if isinstance(output, bytes):
|
||||
output = output.decode()
|
||||
sys.stderr.write('#' * 80 + '\n')
|
||||
sys.stdout.write(output)
|
||||
sys.stderr.write('#' * 80 + '\n')
|
||||
self.fail('Output code: %d' % rc)
|
||||
finally:
|
||||
process.stdout.close()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,649 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2005 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 configuration handlers
|
||||
"""
|
||||
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, getName
|
||||
from zope.component.interface import provideInterface
|
||||
|
||||
try:
|
||||
from zope.security.zcml import 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:
|
||||
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')
|
||||
|
||||
class ComponentConfigurationError(ValueError, ConfigurationError):
|
||||
pass
|
||||
|
||||
def handler(methodName, *args, **kwargs):
|
||||
method = getattr(getSiteManager(), methodName)
|
||||
method(*args, **kwargs)
|
||||
|
||||
class IBasicComponentInformation(Interface):
|
||||
|
||||
component = GlobalObject(
|
||||
title=_("Component to use"),
|
||||
description=_("Python name of the implementation object. This"
|
||||
" must identify an object in a module using the"
|
||||
" full dotted name. If specified, the"
|
||||
" ``factory`` field must be left blank."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
permission = Permission(
|
||||
title=_("Permission"),
|
||||
description=_("Permission required to use this component."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
factory = GlobalObject(
|
||||
title=_("Factory"),
|
||||
description=_("Python name of a factory which can create the"
|
||||
" implementation object. This must identify an"
|
||||
" object in a module using the full dotted name."
|
||||
" If specified, the ``component`` field must"
|
||||
" be left blank."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class IAdapterDirective(Interface):
|
||||
"""
|
||||
Register an adapter
|
||||
"""
|
||||
|
||||
factory = Tokens(
|
||||
title=_("Adapter factory/factories"),
|
||||
description=_("A list of factories (usually just one) that create"
|
||||
" the adapter instance."),
|
||||
required=True,
|
||||
value_type=GlobalObject()
|
||||
)
|
||||
|
||||
provides = GlobalInterface(
|
||||
title=_("Interface the component provides"),
|
||||
description=_("This attribute specifies the interface the adapter"
|
||||
" instance must provide."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
for_ = Tokens(
|
||||
title=_("Specifications to be adapted"),
|
||||
description=_("This should be a list of interfaces or classes"),
|
||||
required=False,
|
||||
value_type=GlobalObject(
|
||||
missing_value=object(),
|
||||
),
|
||||
)
|
||||
|
||||
permission = Permission(
|
||||
title=_("Permission"),
|
||||
description=_("This adapter is only available, if the principal"
|
||||
" has this permission."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
name = TextLine(
|
||||
title=_("Name"),
|
||||
description=_("Adapters can have names.\n\n"
|
||||
"This attribute allows you to specify the name for"
|
||||
" this adapter."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
trusted = Bool(
|
||||
title=_("Trusted"),
|
||||
description=_("""Make the adapter a trusted adapter
|
||||
|
||||
Trusted adapters have unfettered access to the objects they
|
||||
adapt. If asked to adapt security-proxied objects, then,
|
||||
rather than getting an unproxied adapter of security-proxied
|
||||
objects, you get a security-proxied adapter of unproxied
|
||||
objects.
|
||||
"""),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
locate = Bool(
|
||||
title=_("Locate"),
|
||||
description=_("""Make the adapter a locatable adapter
|
||||
|
||||
Located adapter should be used if a non-public permission
|
||||
is used.
|
||||
"""),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
def _rolledUpFactory(factories):
|
||||
# This has to be named 'factory', aparently, so as not to confuse
|
||||
# apidoc :(
|
||||
def factory(ob):
|
||||
for f in factories:
|
||||
ob = f(ob)
|
||||
return ob
|
||||
# Store the original factory for documentation
|
||||
factory.factory = factories[0]
|
||||
return factory
|
||||
|
||||
def adapter(_context, factory, provides=None, for_=None, permission=None,
|
||||
name='', trusted=False, locate=False):
|
||||
|
||||
if for_ is None:
|
||||
if len(factory) == 1:
|
||||
for_ = adaptedBy(factory[0])
|
||||
|
||||
if for_ is None:
|
||||
raise TypeError("No for attribute was provided and can't "
|
||||
"determine what the factory adapts.")
|
||||
|
||||
for_ = tuple(for_)
|
||||
|
||||
if provides is None:
|
||||
if len(factory) == 1:
|
||||
p = list(implementedBy(factory[0]))
|
||||
if len(p) == 1:
|
||||
provides = p[0]
|
||||
|
||||
if provides is None:
|
||||
raise TypeError("Missing 'provides' attribute")
|
||||
|
||||
if name == '':
|
||||
if len(factory) == 1:
|
||||
name = getName(factory[0])
|
||||
|
||||
# Generate a single factory from multiple factories:
|
||||
factories = factory
|
||||
if len(factories) == 1:
|
||||
factory = factories[0]
|
||||
elif len(factories) < 1:
|
||||
raise ComponentConfigurationError("No factory specified")
|
||||
elif len(factories) > 1 and len(for_) != 1:
|
||||
raise ComponentConfigurationError(
|
||||
"Can't use multiple factories and multiple for")
|
||||
else:
|
||||
factory = _rolledUpFactory(factories)
|
||||
|
||||
if permission is not None:
|
||||
factory = protectedFactory(factory, provides, permission)
|
||||
|
||||
# invoke custom adapter factories
|
||||
if locate or permission is not None or trusted:
|
||||
factory = securityAdapterFactory(factory, permission, locate, trusted)
|
||||
|
||||
_context.action(
|
||||
discriminator = ('adapter', for_, provides, name),
|
||||
callable = handler,
|
||||
args = ('registerAdapter',
|
||||
factory, for_, provides, name, _context.info),
|
||||
)
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', provides)
|
||||
)
|
||||
if for_:
|
||||
for iface in for_:
|
||||
if iface is not None:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', iface)
|
||||
)
|
||||
|
||||
class ISubscriberDirective(Interface):
|
||||
"""
|
||||
Register a subscriber
|
||||
"""
|
||||
|
||||
factory = GlobalObject(
|
||||
title=_("Subscriber factory"),
|
||||
description=_("A factory used to create the subscriber instance."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
handler = GlobalObject(
|
||||
title=_("Handler"),
|
||||
description=_("A callable object that handles events."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
provides = GlobalInterface(
|
||||
title=_("Interface the component provides"),
|
||||
description=_("This attribute specifies the interface the adapter"
|
||||
" instance must provide."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
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=GlobalObject(
|
||||
missing_value = object(),
|
||||
),
|
||||
)
|
||||
|
||||
permission = Permission(
|
||||
title=_("Permission"),
|
||||
description=_("This subscriber is only available, if the"
|
||||
" principal has this permission."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
trusted = Bool(
|
||||
title=_("Trusted"),
|
||||
description=_("""Make the subscriber a trusted subscriber
|
||||
|
||||
Trusted subscribers have unfettered access to the objects they
|
||||
adapt. If asked to adapt security-proxied objects, then,
|
||||
rather than getting an unproxied subscriber of security-proxied
|
||||
objects, you get a security-proxied subscriber of unproxied
|
||||
objects.
|
||||
"""),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
locate = Bool(
|
||||
title=_("Locate"),
|
||||
description=_("""Make the subscriber a locatable subscriber
|
||||
|
||||
Located subscribers should be used if a non-public permission
|
||||
is used.
|
||||
"""),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
_handler = handler
|
||||
def subscriber(_context, for_=None, factory=None, handler=None, provides=None,
|
||||
permission=None, trusted=False, locate=False):
|
||||
if factory is None:
|
||||
if handler is None:
|
||||
raise TypeError("No factory or handler provided")
|
||||
if provides is not None:
|
||||
raise TypeError("Cannot use handler with provides")
|
||||
factory = handler
|
||||
else:
|
||||
if handler is not None:
|
||||
raise TypeError("Cannot use handler with factory")
|
||||
if provides is None:
|
||||
raise TypeError(
|
||||
"You must specify a provided interface when registering "
|
||||
"a factory")
|
||||
|
||||
if for_ is None:
|
||||
for_ = 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:
|
||||
factory = protectedFactory(factory, provides, permission)
|
||||
|
||||
for_ = tuple(for_)
|
||||
|
||||
# invoke custom adapter factories
|
||||
if locate or permission is not None or trusted:
|
||||
factory = securityAdapterFactory(factory, permission, locate, trusted)
|
||||
|
||||
if handler is not None:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = _handler,
|
||||
args = ('registerHandler',
|
||||
handler, for_, u'', _context.info),
|
||||
)
|
||||
else:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = _handler,
|
||||
args = ('registerSubscriptionAdapter',
|
||||
factory, for_, provides, u'', _context.info),
|
||||
)
|
||||
|
||||
if provides is not None:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', provides)
|
||||
)
|
||||
|
||||
# For each interface, state that the adapter provides that interface.
|
||||
for iface in for_:
|
||||
if iface is not None:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', iface)
|
||||
)
|
||||
|
||||
class IUtilityDirective(IBasicComponentInformation):
|
||||
"""Register a utility."""
|
||||
|
||||
provides = GlobalInterface(
|
||||
title=_("Provided interface"),
|
||||
description=_("Interface provided by the utility."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
name = TextLine(
|
||||
title=_("Name"),
|
||||
description=_("Name of the registration. This is used by"
|
||||
" application code when locating a utility."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def utility(_context, provides=None, component=None, factory=None,
|
||||
permission=None, name=''):
|
||||
if factory and component:
|
||||
raise TypeError("Can't specify factory and component.")
|
||||
|
||||
if provides is None:
|
||||
if factory:
|
||||
provides = list(implementedBy(factory))
|
||||
else:
|
||||
provides = list(providedBy(component))
|
||||
if len(provides) == 1:
|
||||
provides = provides[0]
|
||||
else:
|
||||
raise TypeError("Missing 'provides' attribute")
|
||||
|
||||
if name == '':
|
||||
if factory:
|
||||
name = getName(factory)
|
||||
else:
|
||||
name = getName(component)
|
||||
|
||||
if permission is not None:
|
||||
component = proxify(component, provides=provides, permission=permission)
|
||||
|
||||
_context.action(
|
||||
discriminator = ('utility', provides, name),
|
||||
callable = handler,
|
||||
args = ('registerUtility', component, provides, name, _context.info),
|
||||
kw = dict(factory=factory),
|
||||
)
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', provides),
|
||||
)
|
||||
|
||||
class IInterfaceDirective(Interface):
|
||||
"""
|
||||
Define an interface
|
||||
"""
|
||||
|
||||
interface = GlobalInterface(
|
||||
title=_("Interface"),
|
||||
required=True,
|
||||
)
|
||||
|
||||
type = GlobalInterface(
|
||||
title=_("Interface type"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
name = TextLine(
|
||||
title=_("Name"),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def interface(_context, interface, type=None, name=''):
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = (name, interface, type)
|
||||
)
|
||||
|
||||
class IBasicViewInformation(Interface):
|
||||
"""This is the basic information for all views."""
|
||||
|
||||
for_ = Tokens(
|
||||
title=_("Specifications of the objects to be viewed"),
|
||||
description=_("""This should be a list of interfaces or classes
|
||||
"""),
|
||||
required=True,
|
||||
value_type=GlobalObject(
|
||||
missing_value=object(),
|
||||
),
|
||||
)
|
||||
|
||||
permission = Permission(
|
||||
title=_("Permission"),
|
||||
description=_("The permission needed to use the view."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class_ = GlobalObject(
|
||||
title=_("Class"),
|
||||
description=_("A class that provides attributes used by the view."),
|
||||
required=False,
|
||||
)
|
||||
|
||||
allowed_interface = Tokens(
|
||||
title=_("Interface that is also allowed if user has permission."),
|
||||
description=_("""
|
||||
By default, 'permission' only applies to viewing the view and
|
||||
any possible sub views. By specifying this attribute, you can
|
||||
make the permission also apply to everything described in the
|
||||
supplied interface.
|
||||
|
||||
Multiple interfaces can be provided, separated by
|
||||
whitespace."""),
|
||||
required=False,
|
||||
value_type=GlobalInterface(),
|
||||
)
|
||||
|
||||
allowed_attributes = Tokens(
|
||||
title=_("View attributes that are also allowed if the user"
|
||||
" has permission."),
|
||||
description=_("""
|
||||
By default, 'permission' only applies to viewing the view and
|
||||
any possible sub views. By specifying 'allowed_attributes',
|
||||
you can make the permission also apply to the extra attributes
|
||||
on the view object."""),
|
||||
required=False,
|
||||
value_type=PythonIdentifier(),
|
||||
)
|
||||
|
||||
class IBasicResourceInformation(Interface):
|
||||
"""
|
||||
Basic information for resources
|
||||
"""
|
||||
|
||||
name = TextLine(
|
||||
title=_("The name of the resource."),
|
||||
description=_("The name shows up in URLs/paths. For example 'foo'."),
|
||||
required=True,
|
||||
default=u'',
|
||||
)
|
||||
|
||||
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=Interface,
|
||||
)
|
||||
|
||||
type = GlobalInterface(
|
||||
title=_("Request type"),
|
||||
required=True
|
||||
)
|
||||
|
||||
|
||||
class IViewDirective(IBasicViewInformation, IBasicResourceInformation):
|
||||
"""Register a view for a component"""
|
||||
|
||||
factory = Tokens(
|
||||
title=_("Factory"),
|
||||
required=False,
|
||||
value_type=GlobalObject(),
|
||||
)
|
||||
|
||||
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 ComponentConfigurationError(
|
||||
"'permission' required with 'allowed_interface' or "
|
||||
"'allowed_attributes'")
|
||||
|
||||
if permission is not None:
|
||||
|
||||
checker = _checker(_context, permission,
|
||||
allowed_interface, allowed_attributes)
|
||||
|
||||
class ProxyView(object):
|
||||
"""Class to create simple proxy views."""
|
||||
|
||||
def __init__(self, factory, checker):
|
||||
self.factory = factory
|
||||
self.checker = checker
|
||||
|
||||
def __call__(self, *objects):
|
||||
return proxify(self.factory(*objects), self.checker)
|
||||
|
||||
factory[-1] = ProxyView(factory[-1], checker)
|
||||
|
||||
|
||||
if not for_:
|
||||
raise ComponentConfigurationError("No for interfaces specified");
|
||||
for_ = tuple(for_)
|
||||
|
||||
# Generate a single factory from multiple factories:
|
||||
factories = factory
|
||||
if len(factories) == 1:
|
||||
factory = factories[0]
|
||||
elif len(factories) < 1:
|
||||
raise ComponentConfigurationError("No view factory specified")
|
||||
elif len(factories) > 1 and len(for_) > 1:
|
||||
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]
|
||||
|
||||
for_ = for_ + (type,)
|
||||
|
||||
_context.action(
|
||||
discriminator = ('view', for_, name, provides),
|
||||
callable = handler,
|
||||
args = ('registerAdapter',
|
||||
factory, for_, provides, name, _context.info),
|
||||
)
|
||||
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', provides)
|
||||
)
|
||||
|
||||
if for_ is not None:
|
||||
for iface in for_:
|
||||
if iface is not None:
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', iface)
|
||||
)
|
||||
|
||||
|
||||
class IResourceDirective(IBasicComponentInformation,
|
||||
IBasicResourceInformation):
|
||||
"""Register a resource"""
|
||||
|
||||
allowed_interface = Tokens(
|
||||
title=_("Interface that is also allowed if user has permission."),
|
||||
required=False,
|
||||
value_type=GlobalInterface(),
|
||||
)
|
||||
|
||||
allowed_attributes = Tokens(
|
||||
title=_("View attributes that are also allowed if user"
|
||||
" has permission."),
|
||||
required=False,
|
||||
value_type=PythonIdentifier(),
|
||||
)
|
||||
|
||||
def resource(_context, factory, type, name,
|
||||
permission=None,
|
||||
allowed_interface=None, allowed_attributes=None,
|
||||
provides=Interface):
|
||||
|
||||
if ((allowed_attributes or allowed_interface)
|
||||
and (not permission)):
|
||||
raise ComponentConfigurationError(
|
||||
"Must use name attribute with allowed_interface or "
|
||||
"allowed_attributes"
|
||||
)
|
||||
|
||||
if permission is not None:
|
||||
|
||||
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
|
||||
|
||||
_context.action(
|
||||
discriminator = ('resource', name, type, provides),
|
||||
callable = handler,
|
||||
args = ('registerAdapter',
|
||||
factory, (type,), provides, name, _context.info))
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', type))
|
||||
_context.action(
|
||||
discriminator = None,
|
||||
callable = provideInterface,
|
||||
args = ('', provides))
|
||||
@@ -0,0 +1,22 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Zope configuration support
|
||||
|
||||
Software that wants to provide new config directives calls
|
||||
zope.configuration.meta.register.
|
||||
"""
|
||||
|
||||
def namespace(suffix):
|
||||
return 'http://namespaces.zope.org/'+suffix
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2012 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
|
||||
|
||||
PY3 = sys.version_info[0] >= 3
|
||||
|
||||
if PY3: # pragma: no cover
|
||||
|
||||
import builtins
|
||||
|
||||
string_types = (str,)
|
||||
text_type = str
|
||||
|
||||
# borrowed from 'six'
|
||||
def reraise(tp, value, tb=None):
|
||||
if value is None:
|
||||
value = tp
|
||||
if value.__traceback__ is not tb:
|
||||
raise value.with_traceback(tb)
|
||||
raise value
|
||||
|
||||
else: # pragma: no cover
|
||||
|
||||
import __builtin__ as builtins
|
||||
|
||||
text_type = unicode
|
||||
string_types = (basestring,)
|
||||
|
||||
# borrowed from 'six'
|
||||
exec("""\
|
||||
def reraise(tp, value, tb=None):
|
||||
raise tp, value, tb
|
||||
""")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,97 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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 Utility to wrap a text to a set width of characters
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
import re
|
||||
|
||||
__all__ = [
|
||||
'wrap',
|
||||
'makeDocStructures',
|
||||
]
|
||||
|
||||
para_sep = re.compile('\n{2,}')
|
||||
whitespace = re.compile('[ \t\n\r]+')
|
||||
|
||||
def wrap(text, width=78, indent=0):
|
||||
"""
|
||||
Makes sure that we keep a line length of a certain width.
|
||||
|
||||
Examples:
|
||||
|
||||
>>> from zope.configuration.docutils import wrap
|
||||
>>> print(wrap('foo bar')[:-2])
|
||||
foo bar
|
||||
>>> print(wrap('foo bar', indent=2)[:-2])
|
||||
foo bar
|
||||
>>> print(wrap('foo bar, more foo bar', 10)[:-2])
|
||||
foo bar,
|
||||
more foo
|
||||
bar
|
||||
>>> print(wrap('foo bar, more foo bar', 10, 2)[:-2])
|
||||
foo bar,
|
||||
more foo
|
||||
bar
|
||||
"""
|
||||
paras = para_sep.split(text.strip())
|
||||
|
||||
new_paras = []
|
||||
for par in paras:
|
||||
words = filter(None, whitespace.split(par))
|
||||
|
||||
lines = []
|
||||
line = []
|
||||
length = indent
|
||||
for word in words:
|
||||
if length + len(word) <= width:
|
||||
line.append(word)
|
||||
length += len(word) + 1
|
||||
else:
|
||||
lines.append(' '*indent + ' '.join(line))
|
||||
line = [word]
|
||||
length = len(word) + 1 + indent
|
||||
|
||||
lines.append(' '*indent + ' '.join(line))
|
||||
|
||||
new_paras.append('\n'.join(lines))
|
||||
|
||||
return '\n\n'.join(new_paras) + '\n\n'
|
||||
|
||||
|
||||
def makeDocStructures(context):
|
||||
"""
|
||||
makeDocStructures(context) -> namespaces, subdirs
|
||||
|
||||
Creates two structures that provide a friendly format for
|
||||
documentation.
|
||||
|
||||
*namespaces* is a dictionary that maps namespaces to a directives
|
||||
dictionary with the key being the name of the directive and the
|
||||
value is a tuple: (schema, handler, info).
|
||||
|
||||
*subdirs* maps a (namespace, name) pair to a list of subdirectives
|
||||
that have the form (namespace, name, schema, info).
|
||||
"""
|
||||
namespaces = {}
|
||||
subdirs = {}
|
||||
registry = context._docRegistry
|
||||
for (namespace, name), schema, usedIn, handler, info, parent in registry:
|
||||
if not parent:
|
||||
ns_entry = namespaces.setdefault(namespace, {})
|
||||
ns_entry[name] = (schema, handler, info)
|
||||
else:
|
||||
sd_entry = subdirs.setdefault((parent.namespace, parent.name), [])
|
||||
sd_entry.append((namespace, name, schema, handler, info))
|
||||
return namespaces, subdirs
|
||||
@@ -0,0 +1,70 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Standard configuration errors
|
||||
"""
|
||||
|
||||
import traceback
|
||||
|
||||
__all__ = [
|
||||
'ConfigurationError',
|
||||
]
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
"""There was an error in a configuration
|
||||
"""
|
||||
|
||||
# A list of strings or things that can be converted to strings,
|
||||
# added by append_details as we walk back up the call/include stack.
|
||||
# We will print them in reverse order so that the most recent detail is
|
||||
# last.
|
||||
_details = ()
|
||||
|
||||
def add_details(self, info):
|
||||
if isinstance(info, BaseException):
|
||||
info = traceback.format_exception_only(type(info), info)
|
||||
# Trim trailing newline
|
||||
info[-1] = info[-1].rstrip()
|
||||
self._details += tuple(info)
|
||||
else:
|
||||
self._details += (info,)
|
||||
return self
|
||||
|
||||
def _with_details(self, opening, detail_formatter):
|
||||
lines = [' ' + detail_formatter(detail) for detail in self._details]
|
||||
lines.append(opening)
|
||||
lines.reverse()
|
||||
return '\n'.join(lines)
|
||||
|
||||
def __str__(self):
|
||||
s = super(ConfigurationError, self).__str__()
|
||||
return self._with_details(s, str)
|
||||
|
||||
def __repr__(self):
|
||||
s = super(ConfigurationError, self).__repr__()
|
||||
return self._with_details(s, repr)
|
||||
|
||||
|
||||
class ConfigurationWrapperError(ConfigurationError):
|
||||
|
||||
USE_INFO_REPR = False
|
||||
|
||||
def __init__(self, info, exception):
|
||||
super(ConfigurationWrapperError, self).__init__(repr(info) if self.USE_INFO_REPR else info)
|
||||
self.add_details(exception)
|
||||
|
||||
# This stuff is undocumented and not used but we store
|
||||
# for backwards compatibility
|
||||
self.info = info
|
||||
self.etype = type(exception)
|
||||
self.evalue = exception
|
||||
@@ -0,0 +1,570 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2003 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Configuration-specific schema fields
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from zope.interface import implementer
|
||||
from zope.schema import Bool as schema_Bool
|
||||
from zope.schema import DottedName
|
||||
from zope.schema import Field
|
||||
from zope.schema import InterfaceField
|
||||
from zope.schema import List
|
||||
from zope.schema import PythonIdentifier as schema_PythonIdentifier
|
||||
from zope.schema import Text
|
||||
from zope.schema import ValidationError
|
||||
from zope.schema.interfaces import IFromUnicode
|
||||
from zope.schema.interfaces import InvalidValue
|
||||
|
||||
from zope.configuration.exceptions import ConfigurationError
|
||||
from zope.configuration.interfaces import InvalidToken
|
||||
|
||||
__all__ = [
|
||||
'Bool',
|
||||
'GlobalObject',
|
||||
'GlobalInterface',
|
||||
'MessageID',
|
||||
'Path',
|
||||
'PythonIdentifier',
|
||||
'Tokens',
|
||||
]
|
||||
|
||||
|
||||
class PythonIdentifier(schema_PythonIdentifier):
|
||||
r"""
|
||||
This class is like `zope.schema.PythonIdentifier`.
|
||||
|
||||
|
||||
Let's look at an example:
|
||||
|
||||
>>> from zope.configuration.fields import PythonIdentifier
|
||||
>>> class FauxContext(object):
|
||||
... pass
|
||||
>>> context = FauxContext()
|
||||
>>> field = PythonIdentifier().bind(context)
|
||||
|
||||
Let's test the fromUnicode method:
|
||||
|
||||
>>> field.fromUnicode(u'foo')
|
||||
'foo'
|
||||
>>> field.fromUnicode(u'foo3')
|
||||
'foo3'
|
||||
>>> field.fromUnicode(u'_foo3')
|
||||
'_foo3'
|
||||
|
||||
Now let's see whether validation works alright
|
||||
|
||||
>>> for value in (u'foo', u'foo3', u'foo_', u'_foo3', u'foo_3', u'foo3_'):
|
||||
... _ = field.fromUnicode(value)
|
||||
>>> from zope.schema import ValidationError
|
||||
>>> for value in (u'3foo', u'foo:', u'\\', u''):
|
||||
... try:
|
||||
... field.fromUnicode(value)
|
||||
... except ValidationError:
|
||||
... print('Validation Error ' + repr(value))
|
||||
Validation Error '3foo'
|
||||
Validation Error 'foo:'
|
||||
Validation Error '\\'
|
||||
Validation Error ''
|
||||
|
||||
.. versionchanged:: 4.2.0
|
||||
Extend `zope.schema.PythonIdentifier`, which implies that `fromUnicode`
|
||||
validates the strings.
|
||||
"""
|
||||
|
||||
def _validate(self, value):
|
||||
super(PythonIdentifier, self)._validate(value)
|
||||
if not value:
|
||||
raise ValidationError(value).with_field_and_value(self, value)
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class GlobalObject(Field):
|
||||
"""
|
||||
An object that can be accessed as a module global.
|
||||
|
||||
The special value ``*`` indicates a value of `None`; this is
|
||||
not validated against the *value_type*.
|
||||
"""
|
||||
|
||||
_DOT_VALIDATOR = DottedName()
|
||||
|
||||
def __init__(self, value_type=None, **kw):
|
||||
self.value_type = value_type
|
||||
super(GlobalObject, self).__init__(**kw)
|
||||
|
||||
def _validate(self, value):
|
||||
super(GlobalObject, self)._validate(value)
|
||||
if self.value_type is not None:
|
||||
self.value_type.validate(value)
|
||||
|
||||
def fromUnicode(self, value):
|
||||
r"""
|
||||
Find and return the module global at the path *value*.
|
||||
|
||||
>>> d = {'x': 1, 'y': 42, 'z': 'zope'}
|
||||
>>> class fakeresolver(dict):
|
||||
... def resolve(self, n):
|
||||
... return self[n]
|
||||
>>> fake = fakeresolver(d)
|
||||
|
||||
>>> from zope.schema import Int
|
||||
>>> from zope.configuration.fields import GlobalObject
|
||||
>>> g = GlobalObject(value_type=Int())
|
||||
>>> gg = g.bind(fake)
|
||||
>>> gg.fromUnicode("x")
|
||||
1
|
||||
>>> gg.fromUnicode(" x \n ")
|
||||
1
|
||||
>>> gg.fromUnicode("y")
|
||||
42
|
||||
>>> gg.fromUnicode("z")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
WrongType: ('zope', (<type 'int'>, <type 'long'>), '')
|
||||
|
||||
>>> g = GlobalObject(constraint=lambda x: x%2 == 0)
|
||||
>>> gg = g.bind(fake)
|
||||
>>> gg.fromUnicode("x")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ConstraintNotSatisfied: 1
|
||||
>>> gg.fromUnicode("y")
|
||||
42
|
||||
>>> g = GlobalObject()
|
||||
>>> gg = g.bind(fake)
|
||||
>>> print(gg.fromUnicode('*'))
|
||||
None
|
||||
"""
|
||||
name = str(value.strip())
|
||||
|
||||
# special case, mostly for interfaces
|
||||
if name == '*':
|
||||
return None
|
||||
|
||||
try:
|
||||
# Leading dots are allowed here to indicate current
|
||||
# package, but not accepted by DottedName. Take care,
|
||||
# though, because a single dot is valid to resolve, but
|
||||
# not valid to pass to DottedName (as an empty string)
|
||||
to_validate = name.lstrip('.')
|
||||
if to_validate:
|
||||
self._DOT_VALIDATOR.validate(to_validate)
|
||||
except ValidationError as v:
|
||||
v.with_field_and_value(self, name)
|
||||
raise
|
||||
|
||||
try:
|
||||
value = self.context.resolve(name)
|
||||
except ConfigurationError as v:
|
||||
raise ValidationError(v).with_field_and_value(self, name)
|
||||
|
||||
self.validate(value)
|
||||
return value
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class GlobalInterface(GlobalObject):
|
||||
"""
|
||||
An interface that can be accessed from a module.
|
||||
|
||||
Example:
|
||||
|
||||
First, we need to set up a stub name resolver:
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> class IFoo(Interface):
|
||||
... pass
|
||||
>>> class Foo(object):
|
||||
... pass
|
||||
>>> d = {'Foo': Foo, 'IFoo': IFoo}
|
||||
>>> class fakeresolver(dict):
|
||||
... def resolve(self, n):
|
||||
... return self[n]
|
||||
>>> fake = fakeresolver(d)
|
||||
|
||||
Now verify constraints are checked correctly:
|
||||
|
||||
>>> from zope.configuration.fields import GlobalInterface
|
||||
>>> g = GlobalInterface()
|
||||
>>> gg = g.bind(fake)
|
||||
>>> gg.fromUnicode('IFoo') is IFoo
|
||||
True
|
||||
>>> gg.fromUnicode(' IFoo ') is IFoo
|
||||
True
|
||||
>>> gg.fromUnicode('Foo')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NotAnInterface: (<class 'Foo'>, ...
|
||||
|
||||
"""
|
||||
def __init__(self, **kw):
|
||||
super(GlobalInterface, self).__init__(InterfaceField(), **kw)
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class Tokens(List):
|
||||
"""
|
||||
A list that can be read from a space-separated string.
|
||||
"""
|
||||
|
||||
def fromUnicode(self, value):
|
||||
r"""
|
||||
Split the input string and convert it to *value_type*.
|
||||
|
||||
Consider GlobalObject tokens:
|
||||
|
||||
First, we need to set up a stub name resolver:
|
||||
|
||||
>>> d = {'x': 1, 'y': 42, 'z': 'zope', 'x.y.x': 'foo'}
|
||||
>>> class fakeresolver(dict):
|
||||
... def resolve(self, n):
|
||||
... return self[n]
|
||||
>>> fake = fakeresolver(d)
|
||||
|
||||
>>> from zope.configuration.fields import Tokens
|
||||
>>> from zope.configuration.fields import GlobalObject
|
||||
>>> g = Tokens(value_type=GlobalObject())
|
||||
>>> gg = g.bind(fake)
|
||||
>>> gg.fromUnicode(" \n x y z \n")
|
||||
[1, 42, 'zope']
|
||||
|
||||
>>> from zope.schema import Int
|
||||
>>> g = Tokens(value_type=
|
||||
... GlobalObject(value_type=
|
||||
... Int(constraint=lambda x: x%2 == 0)))
|
||||
>>> gg = g.bind(fake)
|
||||
>>> gg.fromUnicode("x y")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
InvalidToken: 1 in x y
|
||||
|
||||
>>> gg.fromUnicode("z y")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
InvalidToken: ('zope', (<type 'int'>, <type 'long'>), '') in z y
|
||||
>>> gg.fromUnicode("y y")
|
||||
[42, 42]
|
||||
"""
|
||||
value = value.strip()
|
||||
if value:
|
||||
vt = self.value_type.bind(self.context)
|
||||
values = []
|
||||
for s in value.split():
|
||||
try:
|
||||
v = vt.fromUnicode(s)
|
||||
except ValidationError as ex:
|
||||
raise InvalidToken("%s in %r" % (ex, value)).with_field_and_value(self, s)
|
||||
else:
|
||||
values.append(v)
|
||||
else:
|
||||
values = []
|
||||
|
||||
self.validate(values)
|
||||
|
||||
return values
|
||||
|
||||
class PathProcessor(object):
|
||||
# Internal helper for manipulations on paths
|
||||
|
||||
@classmethod
|
||||
def expand(cls, filename):
|
||||
# Perform the expansions we want to have done. Returns a
|
||||
# tuple: (path, needs_processing) If the second value is true,
|
||||
# further processing should be done (the path isn't fully
|
||||
# resolved); if false, the path should be used as is
|
||||
|
||||
filename = filename.strip()
|
||||
# expanding a ~ at the front should generally result
|
||||
# in an absolute path.
|
||||
filename = os.path.expanduser(filename)
|
||||
filename = os.path.expandvars(filename)
|
||||
if os.path.isabs(filename):
|
||||
return os.path.normpath(filename), False
|
||||
return filename, True
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class Path(Text):
|
||||
"""
|
||||
A file path name, which may be input as a relative path
|
||||
|
||||
Input paths are converted to absolute paths and normalized.
|
||||
"""
|
||||
|
||||
def fromUnicode(self, value):
|
||||
r"""
|
||||
Convert the input path to a normalized, absolute path.
|
||||
|
||||
Let's look at an example:
|
||||
|
||||
First, we need a "context" for the field that has a path
|
||||
function for converting relative path to an absolute path.
|
||||
|
||||
We'll be careful to do this in an operating system independent fashion.
|
||||
|
||||
>>> from zope.configuration.fields import Path
|
||||
>>> class FauxContext(object):
|
||||
... def path(self, p):
|
||||
... return os.path.join(os.sep, 'faux', 'context', p)
|
||||
>>> context = FauxContext()
|
||||
>>> field = Path().bind(context)
|
||||
|
||||
Lets try an absolute path first:
|
||||
|
||||
>>> import os
|
||||
>>> p = os.path.join(os.sep, u'a', u'b')
|
||||
>>> n = field.fromUnicode(p)
|
||||
>>> n.split(os.sep)
|
||||
['', 'a', 'b']
|
||||
|
||||
This should also work with extra spaces around the path:
|
||||
|
||||
>>> p = " \n %s \n\n " % p
|
||||
>>> n = field.fromUnicode(p)
|
||||
>>> n.split(os.sep)
|
||||
['', 'a', 'b']
|
||||
|
||||
Environment variables are expanded:
|
||||
|
||||
>>> os.environ['path-test'] = '42'
|
||||
>>> with_env = os.path.join(os.sep, u'a', u'${path-test}')
|
||||
>>> n = field.fromUnicode(with_env)
|
||||
>>> n.split(os.sep)
|
||||
['', 'a', '42']
|
||||
|
||||
Now try a relative path:
|
||||
|
||||
>>> p = os.path.join(u'a', u'b')
|
||||
>>> n = field.fromUnicode(p)
|
||||
>>> n.split(os.sep)
|
||||
['', 'faux', 'context', 'a', 'b']
|
||||
|
||||
The current user is expanded (these are implicitly relative paths):
|
||||
|
||||
>>> old_home = os.environ.get('HOME')
|
||||
>>> os.environ['HOME'] = os.path.join(os.sep, 'HOME')
|
||||
>>> n = field.fromUnicode('~')
|
||||
>>> n.split(os.sep)
|
||||
['', 'HOME']
|
||||
>>> if old_home:
|
||||
... os.environ['HOME'] = old_home
|
||||
... else:
|
||||
... del os.environ['HOME']
|
||||
|
||||
|
||||
.. versionchanged:: 4.2.0
|
||||
Start expanding home directories and environment variables.
|
||||
"""
|
||||
filename, needs_processing = PathProcessor.expand(value)
|
||||
if needs_processing:
|
||||
filename = self.context.path(filename)
|
||||
|
||||
return filename
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class Bool(schema_Bool):
|
||||
"""
|
||||
A boolean value.
|
||||
|
||||
Values may be input (in upper or lower case) as any of:
|
||||
|
||||
- yes / no
|
||||
- y / n
|
||||
- true / false
|
||||
- t / f
|
||||
|
||||
.. caution::
|
||||
|
||||
Do not confuse this with :class:`zope.schema.Bool`.
|
||||
That class will only parse ``"True"`` and ``"true"`` as
|
||||
`True` values. Any other value will silently be accepted as
|
||||
`False`. This class raises a validation error for unrecognized
|
||||
input.
|
||||
|
||||
"""
|
||||
|
||||
def fromUnicode(self, value):
|
||||
"""
|
||||
Convert the input string to a boolean.
|
||||
|
||||
Example:
|
||||
|
||||
>>> from zope.configuration.fields import Bool
|
||||
>>> Bool().fromUnicode(u"yes")
|
||||
True
|
||||
>>> Bool().fromUnicode(u"y")
|
||||
True
|
||||
>>> Bool().fromUnicode(u"true")
|
||||
True
|
||||
>>> Bool().fromUnicode(u"no")
|
||||
False
|
||||
>>> Bool().fromUnicode(u"surprise")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
zope.schema._bootstrapinterfaces.InvalidValue
|
||||
"""
|
||||
value = value.lower()
|
||||
if value in ('1', 'true', 'yes', 't', 'y'):
|
||||
return True
|
||||
if value in ('0', 'false', 'no', 'f', 'n'):
|
||||
return False
|
||||
# Unlike the superclass, anything else is invalid.
|
||||
raise InvalidValue().with_field_and_value(self, value)
|
||||
|
||||
|
||||
|
||||
@implementer(IFromUnicode)
|
||||
class MessageID(Text):
|
||||
"""
|
||||
Text string that should be translated.
|
||||
|
||||
When a string is converted to a message ID, it is also recorded in
|
||||
the context.
|
||||
"""
|
||||
|
||||
__factories = {}
|
||||
|
||||
def fromUnicode(self, u):
|
||||
"""
|
||||
Translate a string to a MessageID.
|
||||
|
||||
>>> from zope.configuration.fields import MessageID
|
||||
>>> class Info(object):
|
||||
... file = 'file location'
|
||||
... line = 8
|
||||
>>> class FauxContext(object):
|
||||
... i18n_strings = {}
|
||||
... info = Info()
|
||||
>>> context = FauxContext()
|
||||
>>> field = MessageID().bind(context)
|
||||
|
||||
There is a fallback domain when no domain has been specified.
|
||||
|
||||
Exchange the warn function so we can make test whether the warning
|
||||
has been issued
|
||||
|
||||
>>> warned = None
|
||||
>>> def fakewarn(*args, **kw):
|
||||
... global warned
|
||||
... warned = args
|
||||
|
||||
>>> import warnings
|
||||
>>> realwarn = warnings.warn
|
||||
>>> warnings.warn = fakewarn
|
||||
|
||||
>>> i = field.fromUnicode(u"Hello world!")
|
||||
>>> i
|
||||
'Hello world!'
|
||||
>>> i.domain
|
||||
'untranslated'
|
||||
>>> warned
|
||||
("You did not specify an i18n translation domain for the '' field in file location",)
|
||||
|
||||
>>> warnings.warn = realwarn
|
||||
|
||||
With the domain specified:
|
||||
|
||||
>>> context.i18n_strings = {}
|
||||
>>> context.i18n_domain = 'testing'
|
||||
|
||||
We can get a message id:
|
||||
|
||||
>>> i = field.fromUnicode(u"Hello world!")
|
||||
>>> i
|
||||
'Hello world!'
|
||||
>>> i.domain
|
||||
'testing'
|
||||
|
||||
In addition, the string has been registered with the context:
|
||||
|
||||
>>> context.i18n_strings
|
||||
{'testing': {'Hello world!': [('file location', 8)]}}
|
||||
|
||||
>>> i = field.fromUnicode(u"Foo Bar")
|
||||
>>> i = field.fromUnicode(u"Hello world!")
|
||||
>>> from pprint import PrettyPrinter
|
||||
>>> pprint=PrettyPrinter(width=70).pprint
|
||||
>>> pprint(context.i18n_strings)
|
||||
{'testing': {'Foo Bar': [('file location', 8)],
|
||||
'Hello world!': [('file location', 8),
|
||||
('file location', 8)]}}
|
||||
|
||||
>>> from zope.i18nmessageid import Message
|
||||
>>> isinstance(list(context.i18n_strings['testing'].keys())[0], Message)
|
||||
True
|
||||
|
||||
Explicit Message IDs
|
||||
|
||||
>>> i = field.fromUnicode(u'[View-Permission] View')
|
||||
>>> i
|
||||
'View-Permission'
|
||||
>>> i.default
|
||||
'View'
|
||||
|
||||
>>> i = field.fromUnicode(u'[] [Some] text')
|
||||
>>> i
|
||||
'[Some] text'
|
||||
>>> i.default is None
|
||||
True
|
||||
|
||||
"""
|
||||
context = self.context
|
||||
domain = getattr(context, 'i18n_domain', '')
|
||||
if not domain:
|
||||
domain = 'untranslated'
|
||||
warnings.warn(
|
||||
"You did not specify an i18n translation domain for the "\
|
||||
"'%s' field in %s" % (self.getName(), context.info.file)
|
||||
)
|
||||
if not isinstance(domain, str):
|
||||
# IZopeConfigure specifies i18n_domain as a BytesLine, but that's
|
||||
# wrong on Python 3, where the filesystem uses str, and hence
|
||||
# zope.i18n registers ITranslationDomain utilities with str names.
|
||||
# If we keep bytes, we can't find those utilities.
|
||||
enc = sys.getfilesystemencoding() or sys.getdefaultencoding()
|
||||
domain = domain.decode(enc)
|
||||
|
||||
v = super(MessageID, self).fromUnicode(u)
|
||||
|
||||
# Check whether there is an explicit message is specified
|
||||
default = None
|
||||
if v.startswith('[]'):
|
||||
v = v[2:].lstrip()
|
||||
elif v.startswith('['):
|
||||
end = v.find(']')
|
||||
default = v[end+2:]
|
||||
v = v[1:end]
|
||||
|
||||
# Convert to a message id, importing the factory, if necessary
|
||||
factory = self.__factories.get(domain)
|
||||
if factory is None:
|
||||
import zope.i18nmessageid
|
||||
factory = zope.i18nmessageid.MessageFactory(domain)
|
||||
self.__factories[domain] = factory
|
||||
|
||||
msgid = factory(v, default)
|
||||
|
||||
# Record the string we got for the domain
|
||||
i18n_strings = context.i18n_strings
|
||||
strings = i18n_strings.get(domain)
|
||||
if strings is None:
|
||||
strings = i18n_strings[domain] = {}
|
||||
locations = strings.setdefault(msgid, [])
|
||||
locations.append((context.info.file, context.info.line))
|
||||
|
||||
return msgid
|
||||
@@ -0,0 +1,137 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Zope Configuration (ZCML) interfaces
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.schema import BytesLine
|
||||
from zope.schema.interfaces import ValidationError
|
||||
|
||||
__all__ = [
|
||||
'InvalidToken',
|
||||
'IConfigurationContext',
|
||||
'IGroupingContext',
|
||||
]
|
||||
|
||||
class InvalidToken(ValidationError):
|
||||
"""Invaid token in list."""
|
||||
|
||||
class IConfigurationContext(Interface):
|
||||
"""Configuration Context
|
||||
|
||||
The configuration context manages information about the state of
|
||||
the configuration system, such as the package containing the
|
||||
configuration file. More importantly, it provides methods for
|
||||
importing objects and opening files relative to the package.
|
||||
"""
|
||||
|
||||
package = BytesLine(
|
||||
title=(u"The current package name"),
|
||||
description=(u"""\
|
||||
This is the name of the package containing the configuration
|
||||
file being executed. If the configuration file was not
|
||||
included by package, then this is None.
|
||||
"""),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def resolve(dottedname):
|
||||
"""Resolve a dotted name to an object
|
||||
|
||||
A dotted name is constructed by concatenating a dotted module
|
||||
name with a global name within the module using a dot. For
|
||||
example, the object named "spam" in the foo.bar module has a
|
||||
dotted name of foo.bar.spam. If the current package is a
|
||||
prefix of a dotted name, then the package name can be relaced
|
||||
with a leading dot, So, for example, if the configuration file
|
||||
is in the foo package, then the dotted name foo.bar.spam can
|
||||
be shortened to .bar.spam.
|
||||
|
||||
If the current package is multiple levels deep, multiple
|
||||
leading dots can be used to refer to higher-level modules.
|
||||
For example, if the current package is x.y.z, the dotted
|
||||
object name ..foo refers to x.y.foo.
|
||||
"""
|
||||
|
||||
def path(filename):
|
||||
"""Compute a full file name for the given file
|
||||
|
||||
If the filename is relative to the package, then the returned
|
||||
name will include the package path, otherwise, the original
|
||||
file name is returned.
|
||||
|
||||
Environment variables in the path are expanded, and if the path
|
||||
begins with the username marker (~), that is expanded as well.
|
||||
|
||||
.. versionchanged:: 4.2.0
|
||||
Start expanding home directories and environment variables.
|
||||
"""
|
||||
|
||||
def checkDuplicate(filename):
|
||||
"""Check for duplicate imports of the same file.
|
||||
|
||||
Raises an exception if this file had been processed before. This
|
||||
is better than an unlimited number of conflict errors.
|
||||
"""
|
||||
|
||||
def processFile(filename):
|
||||
"""Check whether a file needs to be processed.
|
||||
|
||||
Return True if processing is needed and False otherwise. If
|
||||
the file needs to be processed, it will be marked as
|
||||
processed, assuming that the caller will procces the file if
|
||||
it needs to be procssed.
|
||||
"""
|
||||
|
||||
def action(discriminator, callable, args=(), kw={}, order=0,
|
||||
includepath=None, info=None):
|
||||
"""Record a configuration action
|
||||
|
||||
The job of most directives is to compute actions for later
|
||||
processing. The action method is used to record those actions.
|
||||
|
||||
:param callable: The object to call to implement the action.
|
||||
:param tuple args: Arguments to pass to *callable*
|
||||
:param dict kw: Keyword arguments to pass to *callable*
|
||||
|
||||
:param object discriminator: Used to to find actions that conflict.
|
||||
Actions conflict if they have equal discriminators. The
|
||||
exception to this is the special case of the discriminator
|
||||
with the value `None`. An action with a discriminator of `None`
|
||||
never conflicts with other actions.
|
||||
|
||||
:keyword int order: This is possible to add an order argument to crudely control
|
||||
the order of execution.
|
||||
|
||||
:keyword str info: Optional source line information
|
||||
|
||||
:keyword includepath: is None (the default) or a tuple of
|
||||
include paths for this action.
|
||||
"""
|
||||
|
||||
def provideFeature(name):
|
||||
"""Record that a named feature is available in this context."""
|
||||
|
||||
def hasFeature(name):
|
||||
"""Check whether a named feature is available in this context."""
|
||||
|
||||
|
||||
class IGroupingContext(Interface):
|
||||
|
||||
def before():
|
||||
"""Do something before processing nested directives
|
||||
"""
|
||||
|
||||
def after():
|
||||
"""Do something after processing nested directives
|
||||
"""
|
||||
@@ -0,0 +1,98 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
Provide configuration object name resolution.
|
||||
|
||||
.. note:: This module is no longer used by `zope.configuration` and
|
||||
may be deprecated soon. Its functions are not documented.
|
||||
"""
|
||||
|
||||
import os
|
||||
from types import ModuleType
|
||||
|
||||
__all__ = [
|
||||
'resolve',
|
||||
'getNormalizedName',
|
||||
'path',
|
||||
]
|
||||
|
||||
def resolve(name, package='zopeproducts', _silly=('__doc__',), _globals={}):
|
||||
name = name.strip()
|
||||
|
||||
if name.startswith('.'):
|
||||
name = package + name
|
||||
|
||||
if name.endswith('.') or name.endswith('+'):
|
||||
name = name[:-1]
|
||||
repeat = True
|
||||
else:
|
||||
repeat = False
|
||||
|
||||
names = name.split('.')
|
||||
last = names[-1]
|
||||
mod = '.'.join(names[:-1])
|
||||
|
||||
if not mod:
|
||||
return __import__(name, _globals, _globals, _silly)
|
||||
|
||||
while 1:
|
||||
m = __import__(mod, _globals, _globals, _silly)
|
||||
try:
|
||||
a = getattr(m, last)
|
||||
except AttributeError:
|
||||
if not repeat:
|
||||
return __import__(name, _globals, _globals, _silly)
|
||||
|
||||
else:
|
||||
if not repeat or (not isinstance(a, ModuleType)):
|
||||
return a
|
||||
mod += '.' + last
|
||||
|
||||
|
||||
def getNormalizedName(name, package):
|
||||
name = name.strip()
|
||||
if name.startswith('.'):
|
||||
name = package + name
|
||||
|
||||
if name.endswith('.') or name.endswith('+'):
|
||||
name = name[:-1]
|
||||
repeat = True
|
||||
else:
|
||||
repeat = False
|
||||
name = name.split(".")
|
||||
while len(name) > 1 and name[-1] == name[-2]:
|
||||
name.pop()
|
||||
repeat = 1
|
||||
name = ".".join(name)
|
||||
if repeat:
|
||||
name += "+"
|
||||
return name
|
||||
|
||||
def path(file='', package='zopeproducts', _silly=('__doc__',), _globals={}):
|
||||
# XXX WTF? why not look for abspath before importing?
|
||||
try:
|
||||
package = __import__(package, _globals, _globals, _silly)
|
||||
except ImportError:
|
||||
norm = os.path.normpath(file)
|
||||
if file and os.path.abspath(norm) == norm:
|
||||
# The package didn't matter
|
||||
return norm
|
||||
raise
|
||||
|
||||
path = os.path.dirname(package.__file__)
|
||||
|
||||
if file:
|
||||
path = os.path.join(path, file)
|
||||
|
||||
return path
|
||||
@@ -0,0 +1,2 @@
|
||||
#
|
||||
# This file is necessary to make this directory a package.
|
||||
@@ -0,0 +1,3 @@
|
||||
# I'm bad. I want to be bad. Don't try to change me.
|
||||
|
||||
raise ImportError()
|
||||
@@ -0,0 +1,35 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2003 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" Enable "Making specific directives condition" section of narrative docs.
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.schema import Id
|
||||
|
||||
|
||||
class IRegister(Interface):
|
||||
"""Trivial sample registry."""
|
||||
|
||||
id = Id(
|
||||
title=u"Identifier",
|
||||
description=u"Some identifier that can be checked.",
|
||||
required=True,
|
||||
)
|
||||
|
||||
registry = []
|
||||
|
||||
def register(context, id):
|
||||
context.action(discriminator=('Register', id),
|
||||
callable=registry.append,
|
||||
args=(id,)
|
||||
)
|
||||
@@ -0,0 +1,78 @@
|
||||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:meta="http://namespaces.zope.org/meta"
|
||||
xmlns:test="http://sample.namespaces.zope.org/test"
|
||||
xmlns:zcml="http://namespaces.zope.org/zcml"
|
||||
>
|
||||
|
||||
<meta:directive
|
||||
name="register"
|
||||
namespace="http://sample.namespaces.zope.org/test"
|
||||
schema=".conditions.IRegister"
|
||||
handler=".conditions.register"
|
||||
>
|
||||
This registers a directive which creates registrations we can test.
|
||||
</meta:directive>
|
||||
|
||||
<test:register id="unqualified.registration" />
|
||||
|
||||
<meta:provides feature="testfeature" />
|
||||
<meta:provides feature="anothertestfeature" />
|
||||
|
||||
<configure zcml:condition="have testfeature">
|
||||
ZCML directives inside here should be included.
|
||||
|
||||
<configure>
|
||||
<test:register id="nested.true.condition" />
|
||||
</configure>
|
||||
|
||||
<!-- These registrations stand on the basis of their own
|
||||
conditions: -->
|
||||
<test:register
|
||||
zcml:condition="have anothertestfeature"
|
||||
id="true.condition.nested.in.true"
|
||||
/>
|
||||
|
||||
<test:register
|
||||
zcml:condition="have undefinedfeature"
|
||||
id="false.condition.nested.in.true"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
|
||||
<test:register
|
||||
zcml:condition="have testfeature"
|
||||
id="direct.true.condition"
|
||||
>
|
||||
This registration should be included.
|
||||
</test:register>
|
||||
|
||||
<configure zcml:condition="have undefinedfeature">
|
||||
ZCML directives inside here should be ignored.
|
||||
|
||||
<configure>
|
||||
<test:register id="nested.false.condition" />
|
||||
</configure>
|
||||
|
||||
<!-- These registrations are ignored, since the container is
|
||||
ignored: -->
|
||||
<test:register
|
||||
zcml:condition="have testfeature"
|
||||
id="true.condition.nested.in.false"
|
||||
/>
|
||||
|
||||
<test:register
|
||||
zcml:condition="have undefinedfeature"
|
||||
id="false.condition.nested.in.false"
|
||||
/>
|
||||
|
||||
</configure>
|
||||
|
||||
<test:register
|
||||
zcml:condition="have undefinedfeature"
|
||||
id="direct.false.condition"
|
||||
>
|
||||
This registration should be ignored.
|
||||
</test:register>
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1,87 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test directives
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.schema import NativeStringLine
|
||||
from zope.schema import Text
|
||||
|
||||
from zope.configuration.config import GroupingContextDecorator
|
||||
from zope.configuration.interfaces import IConfigurationContext
|
||||
from zope.configuration.fields import GlobalObject
|
||||
|
||||
|
||||
class F(object):
|
||||
def __repr__(self):
|
||||
return 'f'
|
||||
def __call__(self, *a, **k):
|
||||
raise NotImplementedError
|
||||
|
||||
f = F()
|
||||
|
||||
class ISimple(Interface):
|
||||
|
||||
a = Text()
|
||||
b = Text(required=False)
|
||||
c = NativeStringLine()
|
||||
|
||||
def simple(context, a=None, c=None, b=u"xxx"):
|
||||
return [(('simple', a, b, c), f, (a, b, c))]
|
||||
|
||||
def newsimple(context, a, c, b=u"xxx"):
|
||||
context.action(('newsimple', a, b, c), f, (a, b, c))
|
||||
|
||||
|
||||
class IPackaged(Interface):
|
||||
|
||||
package = GlobalObject()
|
||||
|
||||
|
||||
class IPackagedContext(IPackaged, IConfigurationContext):
|
||||
pass
|
||||
|
||||
|
||||
@implementer(IPackagedContext)
|
||||
class Packaged(GroupingContextDecorator):
|
||||
pass
|
||||
|
||||
|
||||
class IFactory(Interface):
|
||||
|
||||
factory = GlobalObject()
|
||||
|
||||
def factory(context, factory):
|
||||
context.action(('factory', 1,2), factory)
|
||||
|
||||
class Complex(object):
|
||||
|
||||
def __init__(self, context, a, c, b=u"xxx"):
|
||||
self.a, self.b, self.c = a, b, c
|
||||
context.action("Complex.__init__")
|
||||
|
||||
def factory(self, context, factory):
|
||||
return [(('Complex.factory', 1, 2), factory, (self.a, ))]
|
||||
|
||||
def __call__(self):
|
||||
return [(('Complex', 1,2), f, (self.b, self.c))]
|
||||
|
||||
|
||||
class Ik(Interface):
|
||||
for_ = NativeStringLine()
|
||||
class_ = NativeStringLine()
|
||||
x = NativeStringLine()
|
||||
|
||||
def k(context, for_, class_, x):
|
||||
context.action(('k', for_), f, (for_, class_, x))
|
||||
@@ -0,0 +1 @@
|
||||
#
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<configure>
|
||||
|
||||
<include package=".sub" />
|
||||
<include file="spam.zcml" />
|
||||
|
||||
</configure>
|
||||
@@ -0,0 +1 @@
|
||||
<configure />
|
||||
+1
@@ -0,0 +1 @@
|
||||
#
|
||||
+1
@@ -0,0 +1 @@
|
||||
<configure />
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user