Commit d18c452b authored by Philipp von Weitershausen's avatar Philipp von Weitershausen

Merge from 2.8 branch:

------------------------------------------------------------------------
r33281 | philikon | 2005-07-12 18:03:36 +0200 (Tue, 12 Jul 2005) | 4 lines

Update Five to the latest bugfix release 1.0.2.
This also includes a patch to HTTPRequest which is implemented
directly in Zope 2 rather than the monkey Five does.
parents 16273d23 2b0d0a01
......@@ -2,10 +2,25 @@
Five Changes
============
Five 1.0.2 (2005-07-12)
=======================
This version is also included in Zope 2.8.1
* Fixed some issues with bridged interfaces: Bases and Methods were not
bridged correctly. extends() was never True.
* zope.security.checkPermission now behaves exactly like
Five.security.checkPermission (in fact, the former now calls the
latter through the indirection of Zope 3 security policies).
* Fixed a bug with resource directories. Resources within those were
not rendering their absolute URL correctly.
Five 1.0.1 (2005-05-31)
=======================
This version is also included in Zope 2.8.
This version is also included in Zope 2.8.0
* Changed license headers to the ones used in the Zope.org repository.
This makes merging between the main development line of Five (hosted
......
......@@ -18,13 +18,16 @@ $Id: bridge.py 12915 2005-05-31 10:23:19Z philikon $
from Interface._InterfaceClass import Interface as Z2_InterfaceClass
from Interface import Interface as Z2_Interface
from Interface import Attribute as Z2_Attribute
from Interface.Method import Method as Z2_Method
from zope.interface.interface import InterfaceClass as Z3_InterfaceClass
from zope.interface.interface import Interface as Z3_Interface
from zope.interface.interface import Attribute as Z3_Attribute
from zope.interface.interface import Method as Z3_Method
def fromZ2Interface(z2i):
_bridges = {Z2_Interface: Z3_Interface}
def fromZ2Interface(z2i):
""" Return a Zope 3 interface corresponding to 'z2i'.
o 'z2i' must be a Zope 2 interface.
......@@ -32,8 +35,8 @@ def fromZ2Interface(z2i):
if not isinstance(z2i, Z2_InterfaceClass):
raise ValueError, 'Not a Zope 2 interface!'
if z2i is Z2_Interface: # special case; root in new hierarchy!
return Z3_Interface
if z2i in _bridges:
return _bridges[z2i]
name = z2i.getName()
......@@ -42,23 +45,25 @@ def fromZ2Interface(z2i):
attrs = {}
for k, v in z2i.namesAndDescriptions():
if isinstance(v, Z2_Method):
v = fromZ2Method(v)
if isinstance(v, Z2_Attribute):
elif isinstance(v, Z2_Attribute):
v = fromZ2Attribute(v)
attrs[k] = v
# XXX: Note that we pass the original interface's __module__;
# we may live to regret that.
return Z3_InterfaceClass(name=name,
bases=bases,
attrs=attrs,
__doc__=z2i.getDoc(),
__module__=z2i.__module__,
)
z3i = Z3_InterfaceClass(name=name,
bases=tuple(bases),
attrs=attrs,
__doc__=z2i.getDoc(),
__module__=z2i.__module__)
_bridges[z2i] = z3i
return z3i
def fromZ2Attribute(z2a):
""" Return a Zope 3 interface attribute corresponding to 'z2a'.
o 'z2a' must be a Zope 2 interface attribute.
......@@ -67,3 +72,20 @@ def fromZ2Attribute(z2a):
raise ValueError, 'Not a Zope 2 interface attribute!'
return Z3_Attribute(z2a.getName(), z2a.getDoc())
def fromZ2Method(z2m):
""" Return a Zope 3 interface method corresponding to 'z2m'.
o 'z2m' must be a Zope 2 interface method.
"""
if not isinstance(z2m, Z2_Method):
raise ValueError, 'Not a Zope 2 interface method!'
z3m = Z3_Method(z2m.getName(), z2m.getDoc())
sig = z2m.getSignatureInfo()
z3m.positional = sig['positional']
z3m.required = sig['required']
z3m.optional = sig['optional']
z3m.varargs = sig['varargs']
z3m.kwargs = sig['kwargs']
return z3m
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<serviceType
id="BrowserMenu"
interface="zope.app.publisher.interfaces.browser.IBrowserMenuService"
/>
<service
serviceType="BrowserMenu"
permission="zope.Public"
component="zope.app.publisher.browser.globalbrowsermenuservice.globalBrowserMenuService"
/>
<browser:page
for="*"
name="absolute_url"
......
......@@ -32,8 +32,13 @@ system for us all.
Download
--------
2005-07-12 -- We have released Five 1.0.2! This is also the version
that will be included in Zope 2.8.1. Download it here:
http://codespeak.net/z3/five/release/Five-1.0.2.tgz
2005-05-31 -- We have released Five 1.0.1! This is also the version
that will be included in Zope 2.8. Download it here:
that will be included in Zope 2.8.0. Download it here:
http://codespeak.net/z3/five/release/Five-1.0.1.tgz
......
......@@ -38,7 +38,6 @@ _marker = []
class Resource(Explicit):
"""A publishable resource
"""
implements(IResource)
def __init__(self, request):
......@@ -55,7 +54,6 @@ class Resource(Explicit):
return "%s/%s" % (url, name)
class PageTemplateResource(BrowserView, Resource):
#implements(IBrowserPublisher)
def __browser_default__(self, request):
......@@ -68,7 +66,6 @@ class PageTemplateResource(BrowserView, Resource):
class FileResource(BrowserView, Resource):
"""A publishable file-based resource"""
#implements(IBrowserPublisher)
def __browser_default__(self, request):
......@@ -76,7 +73,6 @@ class FileResource(BrowserView, Resource):
def GET(self):
"""Default content"""
file = self.context
request = self.request
response = request.response
......@@ -175,7 +171,6 @@ class Directory:
self.__name__ = name
class DirectoryResource(BrowserView, Resource, OFSTraversable):
#implements(IBrowserPublisher)
resource_factories = {
......@@ -189,6 +184,12 @@ class DirectoryResource(BrowserView, Resource, OFSTraversable):
default_factory = FileResourceFactory
def __init__(self, context, request):
BrowserView.__init__(self, context, request)
# OFSTraversable.absolute_url() assumes self.REQUEST being
# accessible:
self.REQUEST = request
def getId(self):
name = self.__name__
if not name.startswith('++resource++'):
......@@ -205,7 +206,6 @@ class DirectoryResource(BrowserView, Resource, OFSTraversable):
raise KeyError, name
return res
def get(self, name, default=_marker):
path = self.context.path
filename = os.path.join(path, name)
......
......@@ -15,8 +15,11 @@
$Id: security.py 12915 2005-05-31 10:23:19Z philikon $
"""
from zope.interface import implements
from zope.interface import implements, classProvides
from zope.component import queryUtility, getUtility
from zope.security.management import thread_local
from zope.security.interfaces import IInteraction, ISecurityPolicy
from zope.security.simplepolicies import ParanoidSecurityPolicy
from zope.app.security.interfaces import IPermission
from zope.app import zapi
......@@ -74,6 +77,29 @@ def checkPermission(permission, object, interaction=None):
return False
class FiveSecurityPolicy(ParanoidSecurityPolicy):
"""Security policy that bridges between Zope 3 security mechanisms and
Zope 2's security policy.
Don't let the name of the base class fool you... This really just
delegates to Zope 2's security manager."""
classProvides(ISecurityPolicy)
implements(IInteraction)
def checkPermission(self, permission, object):
return checkPermission(permission, object)
def newInteraction():
"""Con Zope 3 to use Zope 2's checkPermission.
Zope 3 when it does a checkPermission will turn around and
ask the thread local interaction for the checkPermission method.
By making the interaction *be* Zope 2's security manager, we can
con Zope 3 into using Zope 2's checker...
"""
if getattr(thread_local, 'interaction', None) is None:
thread_local.interaction = FiveSecurityPolicy()
def initializeClass(klass):
InitializeClass(klass)
......
======
Bridge
======
The ``Five.bridge`` module provides functionality to convert a Zope 2
interface into a Zope 3 one. First we'll import all we know about
interfaces from the two generations:
>>> from Interface import Interface as Z2_Interface
>>> from Interface import Attribute as Z2_Attribute
>>> from zope.interface import Interface as Z3_Interface
>>> from zope.interface import Attribute as Z3_Attribute
>>> from zope.interface.interface import Method as Z3_Method
An empty interface
------------------
>>> class IEmpty(Z2_Interface):
... pass
>>> from Products.Five.bridge import fromZ2Interface
>>> IEmptyConverted = fromZ2Interface(IEmpty)
>>> Z3_Interface.isEqualOrExtendedBy(IEmptyConverted)
True
>>> len(IEmptyConverted.names())
0
Bases
-----
>>> class IBase(Z2_Interface):
... pass
>>> class IDerived(IBase):
... pass
>>> IBase.getBases() == (Z2_Interface,)
True
>>> IDerived.getBases() == (IBase,)
True
>>> IDerived.extends(IBase)
1
>>> IDerived.extends(IEmpty)
0
>>> IBaseConverted = fromZ2Interface(IBase)
>>> IDerivedConverted = fromZ2Interface(IDerived)
>>> IBaseConverted.getBases() == (Z3_Interface,)
True
>>> IDerivedConverted.getBases() == (IBaseConverted,)
True
>>> IDerivedConverted.extends(IBaseConverted)
True
>>> IDerivedConverted.extends(IEmptyConverted)
False
Attributes
----------
>>> class IAttributes(Z2_Interface):
... one = Z2_Attribute('one', 'One attribute')
... another = Z2_Attribute('another', 'Another attribute')
>>> converted = fromZ2Interface(IAttributes)
>>> Z3_Interface.isEqualOrExtendedBy(converted)
True
>>> len(converted.names())
2
>>> 'one' in converted.names()
True
>>> 'another' in converted.names()
True
>>> one = converted.getDescriptionFor('one')
>>> isinstance(one, Z3_Attribute)
True
>>> one.getName()
'one'
>>> one.getDoc()
'One attribute'
>>> another = converted.getDescriptionFor('another')
>>> isinstance(another, Z3_Attribute)
True
>>> another.getName()
'another'
>>> another.getDoc()
'Another attribute'
Methods
-------
>>> class IMethods(Z2_Interface):
... def one():
... """One method."""
... def another(arg1, arg2):
... """Another method, taking arguments."""
>>> converted = fromZ2Interface(IMethods)
>>> Z3_Interface.isEqualOrExtendedBy(converted)
True
>>> len(converted.names())
2
>>> 'one' in converted.names()
True
>>> 'another' in converted.names()
True
>>> one = converted.getDescriptionFor('one')
>>> isinstance(one, Z3_Method)
True
>>> one.getName()
'one'
>>> one.getDoc()
'One method.'
>>> one.getSignatureString()
'()'
>>> another = converted.getDescriptionFor('another')
>>> isinstance(another, Z3_Method)
True
>>> another.getName()
'another'
>>> another.getDoc()
'Another method, taking arguments.'
>>> another.getSignatureString()
'(arg1, arg2)'
Invalid parameters
------------------
>>> fromZ2Interface(None)
Traceback (most recent call last):
...
ValueError: Not a Zope 2 interface!
>>> fromZ2Interface(object())
Traceback (most recent call last):
...
ValueError: Not a Zope 2 interface!
>>> class IZ3_NotAllowed(Z3_Interface):
... pass
>>> fromZ2Interface(IZ3_NotAllowed)
Traceback (most recent call last):
...
ValueError: Not a Zope 2 interface!
......@@ -13,114 +13,16 @@
##############################################################################
""" Unit tests for Z2 -> Z3 bridge utilities.
$Id:$
$Id$
"""
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
import unittest
#------------------------------------------------------------------------------
# Running these tests
# ===================
#
# I (Tres) can't figure out your testing framework. These tests run
# in a "normal" Z27 + Z3 + Five instance home via the following:
#
# $ bin/zopectl run Products/Five/tests/test_bridge.py
#------------------------------------------------------------------------------
from Interface import Interface as Z2_Interface
from Interface import Attribute as Z2_Attribute
from zope.interface import Interface as Z3_Interface
from zope.interface import Attribute as Z3_Attribute
from zope.interface import Attribute as Z3_Method
class BridgeTests(unittest.TestCase):
def test_fromZ2Interface_invalid(self):
from Products.Five.bridge import fromZ2Interface
self.assertRaises(ValueError, fromZ2Interface, None)
self.assertRaises(ValueError, fromZ2Interface, object())
class IZ3_NotAllowed(Z3_Interface):
pass
self.assertRaises(ValueError, fromZ2Interface, IZ3_NotAllowed)
def test_fromZ2Interface_empty(self):
from Products.Five.bridge import fromZ2Interface
class IEmpty(Z2_Interface):
pass
converted = fromZ2Interface(IEmpty)
self.failUnless(Z3_Interface.isEqualOrExtendedBy(converted))
self.assertEqual(len(converted.names()), 0)
def test_fromZ2Interface_attributes(self):
from Products.Five.bridge import fromZ2Interface
class IAttributes(Z2_Interface):
one = Z2_Attribute('one', 'One attribute')
another = Z2_Attribute('another', 'Another attribute')
converted = fromZ2Interface(IAttributes)
self.failUnless(Z3_Interface.isEqualOrExtendedBy(converted))
self.assertEqual(len(converted.names()), 2)
self.failUnless('one' in converted.names())
self.failUnless('another' in converted.names())
one = converted.getDescriptionFor('one')
self.failUnless(isinstance(one, Z3_Attribute))
self.assertEqual(one.getName(), 'one')
self.assertEqual(one.getDoc(), 'One attribute')
another = converted.getDescriptionFor('another')
self.failUnless(isinstance(another, Z3_Attribute))
self.assertEqual(another.getName(), 'another')
self.assertEqual(another.getDoc(), 'Another attribute')
def test_fromZ2Interface_methods(self):
from Products.Five.bridge import fromZ2Interface
class IMethods(Z2_Interface):
def one():
"""One method."""
def another(arg1, arg2):
"""Another method, taking arguments."""
converted = fromZ2Interface(IMethods)
self.failUnless(Z3_Interface.isEqualOrExtendedBy(converted))
self.assertEqual(len(converted.names()), 2)
self.failUnless('one' in converted.names())
self.failUnless('another' in converted.names())
one = converted.getDescriptionFor('one')
self.failUnless(isinstance(one, Z3_Method))
self.assertEqual(one.getName(), 'one')
self.assertEqual(one.getDoc(), 'One method.')
another = converted.getDescriptionFor('another')
self.failUnless(isinstance(another, Z3_Method))
self.assertEqual(another.getName(), 'another')
self.assertEqual(another.getDoc(), 'Another method, taking arguments.')
def test_suite():
return unittest.defaultTestLoader.loadTestsFromTestCase( BridgeTests )
from Testing.ZopeTestCase import installProduct, ZopeDocFileSuite
installProduct('Five')
return ZopeDocFileSuite('bridge.txt', package="Products.Five.tests")
if __name__ == '__main__':
framework()
......@@ -218,16 +218,17 @@ class FiveTest(FiveTestCase):
def test_resource_directory(self):
base = 'testoid/++resource++fivetest_resources/%s'
base_url = 'test_folder_1_/%s' % base
base_url = 'http://nohost/test_folder_1_/' + base
abs_url = self.folder.unrestrictedTraverse(base % '')()
self.assertEquals(abs_url + '/', base_url % '')
for r in dir_resource_names:
resource = self.folder.unrestrictedTraverse(base % r)
self.assert_(isinstance(resource, Resource))
# PageTemplateResource's __call__ renders the template
if not isinstance(resource, PageTemplateResource):
self.assertEquals(resource(), base_url % r)
abs_url = self.folder.unrestrictedTraverse(base % '')()
expected = 'http://nohost/test_folder_1_/testoid/++resource++fivetest_resources'
self.assertEquals(abs_url, expected)
def test_breadcrumbs(self):
view = self.folder.unrestrictedTraverse('testoid/@@absolute_url')
......@@ -348,13 +349,21 @@ class PublishTest(Functional, FiveTestCase):
url = '/test_folder_1_/testoid/++resource++cockatiel.html'
response = self.publish(url, basic='manager:r00t')
self.assertEquals(200, response.getStatus())
# Disabled __call__ overriding for now. Causes more trouble
# than it fixes.
# def test_existing_call(self):
# response = self.publish('/test_folder_1_/testcall')
# self.assertEquals("Default __call__ called", response.getBody())
def test_publish_resource_directory(self):
base_url = '/test_folder_1_/testoid/++resource++fivetest_resources/%s'
for r in dir_resource_names:
if r.endswith('.pt'):
# page templates aren't guaranteed to render
continue
response = self.publish(base_url % r, basic='manager:r00t')
self.assertEquals(200, response.getStatus())
def test_existing_index(self):
response = self.publish('/test_folder_1_/testindex')
self.assertEquals("Default index_html called", response.getBody())
......
......@@ -21,11 +21,14 @@ if __name__ == '__main__':
from Products.Five.tests.fivetest import *
import zope.security
from zope.component import getView
from zope.testing.cleanup import CleanUp
import Products.Five.security
from Products.Five import zcml
from Products.Five.traversable import FakeRequest
from Products.Five.security import clearSecurityInfo, checkPermission
from Products.Five.security import clearSecurityInfo, newInteraction
from Products.Five.tests.dummy import Dummy1, Dummy2
from Globals import InitializeClass
......@@ -147,29 +150,38 @@ class SecurityEquivalenceTest(FiveTestCase):
assertRolesEqual(baz_roles2, ())
class CheckPermissionTest(FiveTestCase):
class FiveCheckPermissionTest(FiveTestCase):
def afterSetUp(self):
self.checkPermission = Products.Five.security.checkPermission
def test_publicPermissionId(self):
self.failUnless(checkPermission('zope2.Public', self.folder))
self.failUnless(self.checkPermission('zope2.Public', self.folder))
def test_privatePermissionId(self):
self.failIf(checkPermission('zope.Private', self.folder))
self.failIf(checkPermission('zope2.Private', self.folder))
self.failIf(self.checkPermission('zope.Private', self.folder))
self.failIf(self.checkPermission('zope2.Private', self.folder))
def test_accessPermissionId(self):
self.failUnless(checkPermission('zope2.AccessContentsInformation',
self.folder))
self.failUnless(self.checkPermission('zope2.AccessContentsInformation',
self.folder))
def test_invalidPermissionId(self):
self.failIf(checkPermission('notapermission', self.folder))
self.failIf(self.checkPermission('notapermission', self.folder))
class Zope3CheckPermissionTest(FiveCheckPermissionTest):
def afterSetUp(self):
self.checkPermission = zope.security.checkPermission
newInteraction()
def test_suite():
from unittest import TestSuite, makeSuite
suite = TestSuite()
suite.addTest(makeSuite(SecurityEquivalenceTest))
suite.addTest(makeSuite(PageSecurityTest))
suite.addTest(makeSuite(CheckPermissionTest))
suite.addTest(makeSuite(FiveCheckPermissionTest))
suite.addTest(makeSuite(Zope3CheckPermissionTest))
return suite
if __name__ == '__main__':
......
......@@ -24,8 +24,8 @@ from zope.app.traversing.interfaces import ITraverser, ITraversable
from zope.app.traversing.adapters import DefaultTraversable
from zope.app.traversing.adapters import traversePathElement
from zope.security.management import thread_local
from AccessControl import getSecurityManager
from Products.Five.security import newInteraction
_marker = object
......@@ -38,17 +38,6 @@ class FakeRequest:
def has_key(self, key):
return False
def newInteraction():
"""Con Zope 3 to use Zope 2's checkPermission.
Zope 3 when it does a checkPermission will turn around and
ask the thread local interaction for the checkPermission method.
By making the interaction *be* Zope 2's security manager, we can
con Zope 3 into using Zope 2's checker...
"""
if getattr(thread_local, 'interaction', None) is None:
thread_local.interaction = getSecurityManager()
class Traversable:
"""A mixin to make an object traversable using an ITraverser adapter.
"""
......
......@@ -1346,6 +1346,8 @@ class HTTPRequest(BaseRequest):
"""see zope.publisher.interfaces.IPublicationRequest"""
self._presentation_skin = skin
def getURL(self):
return self.URL
class TaintRequestWrapper:
def __init__(self, req):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment