Commit 9a2be05e authored by 's avatar

backported r33270 from trunk:

- added z3 -> z2 interface bridge
parents 67b5488d 16273d23
......@@ -24,6 +24,12 @@ Zope Changes
after Zope 2.8.1 b1
Features added
- Interface: Added Z3 -> Z2 bridge utilities.
This allows to migrate interfaces to Zope 3 style interfaces and
bridge them back to oldstyle interfaces for backwards compatibility.
Bugs Fixed
- Zope2.Startup.zopectl: fork before execv when running unit tests
......
##############################################################################
#
# Copyright (c) 2005 Zope Corporation 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.
#
##############################################################################
""" Z3 -> Z2 bridge utilities.
$Id$
"""
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
_bridges = {Z3_Interface: Z2_Interface}
def fromZ3Interface(z3i):
""" Return a Zope 2 interface corresponding to 'z3i'.
o 'z3i' must be a Zope 3 interface.
"""
if not isinstance(z3i, Z3_InterfaceClass):
raise ValueError, 'Not a Zope 3 interface!'
if z3i in _bridges:
return _bridges[z3i]
name = z3i.getName()
bases = [ fromZ3Interface(x) for x in z3i.getBases() ]
attrs = {}
for k, v in z3i.namesAndDescriptions():
if isinstance(v, Z3_Method):
v = fromZ3Method(v)
elif isinstance(v, Z3_Attribute):
v = fromZ3Attribute(v)
attrs[k] = v
# XXX: Note that we pass the original interface's __module__;
# we may live to regret that.
z2i = Z2_InterfaceClass(name=name,
bases=tuple(bases),
attrs=attrs,
__doc__=z3i.getDoc(),
__module__=z3i.__module__)
_bridges[z3i] = z2i
return z2i
def fromZ3Attribute(z3a):
""" Return a Zope 2 interface attribute corresponding to 'z3a'.
o 'z3a' must be a Zope 3 interface attribute.
"""
if not isinstance(z3a, Z3_Attribute):
raise ValueError, 'Not a Zope 3 interface attribute!'
return Z2_Attribute(z3a.getName(), z3a.getDoc())
def fromZ3Method(z3m):
""" Return a Zope 2 interface method corresponding to 'z3m'.
o 'z3m' must be a Zope 3 interface method.
"""
if not isinstance(z3m, Z3_Method):
raise ValueError, 'Not a Zope 3 interface method!'
z2m = Z2_Method(z3m.getName(), z3m.getDoc())
sig = z3m.getSignatureInfo()
z2m.positional = sig['positional']
z2m.required = sig['required']
z2m.optional = sig['optional']
z2m.varargs = sig['varargs']
z2m.kwargs = sig['kwargs']
return z2m
def createZope3Bridge(zope3, package, name):
# Map a Zope 3 interface into a Zope2 interface, seated within 'package'
# as 'name'.
z2i = fromZ3Interface(zope3)
if name is not None:
z2i.__dict__['__name__'] = name
z2i.__dict__['__module__'] = package.__name__
setattr(package, z2i.getName(), z2i)
======
Bridge
======
The ``bridge`` module provides functionality to convert a Zope 3
interface into a Zope 2 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 Interface.Method import Method as Z2_Method
>>> from zope.interface import Interface as Z3_Interface
>>> from zope.interface import Attribute as Z3_Attribute
>>> from zope.schema import List, TextLine
An empty interface
------------------
>>> class IEmpty(Z3_Interface):
... pass
>>> from Interface.bridge import fromZ3Interface
>>> IEmptyConverted = fromZ3Interface(IEmpty)
>>> Z2_Interface.isEqualOrExtendedBy(IEmptyConverted)
1
>>> len(IEmptyConverted.names())
0
Bases
-----
>>> class IBase(Z3_Interface):
... pass
>>> class IDerived(IBase):
... pass
>>> IBase.getBases() == (Z3_Interface,)
True
>>> IDerived.getBases() == (IBase,)
True
>>> IDerived.extends(IBase)
True
>>> IDerived.extends(IEmpty)
False
>>> IBaseConverted = fromZ3Interface(IBase)
>>> IDerivedConverted = fromZ3Interface(IDerived)
>>> IBaseConverted.getBases() == (Z2_Interface,)
True
>>> IDerivedConverted.getBases() == (IBaseConverted,)
True
>>> IDerivedConverted.extends(IBaseConverted)
1
>>> IDerivedConverted.extends(IEmptyConverted)
0
Attributes
----------
>>> class IAttributes(Z3_Interface):
... one = Z3_Attribute('one', 'One attribute')
... another = Z3_Attribute('another', 'Another attribute')
>>> converted = fromZ3Interface(IAttributes)
>>> Z2_Interface.isEqualOrExtendedBy(converted)
1
>>> len(converted.names())
2
>>> 'one' in converted.names()
True
>>> 'another' in converted.names()
True
>>> one = converted.getDescriptionFor('one')
>>> isinstance(one, Z2_Attribute)
True
>>> one.getName()
'one'
>>> one.getDoc()
'One attribute'
>>> another = converted.getDescriptionFor('another')
>>> isinstance(another, Z2_Attribute)
True
>>> another.getName()
'another'
>>> another.getDoc()
'Another attribute'
Fields
------
>>> class IFields(Z3_Interface):
... one = TextLine(title=u'one', description=u'One field')
... another = List(title=u'another', description=u'Another field',
... value_type = TextLine())
>>> converted = fromZ3Interface(IFields)
>>> Z2_Interface.isEqualOrExtendedBy(converted)
1
>>> len(converted.names())
2
>>> 'one' in converted.names()
True
>>> 'another' in converted.names()
True
>>> one = converted.getDescriptionFor('one')
>>> isinstance(one, Z2_Attribute)
True
>>> one.getName()
'one'
>>> one.getDoc()
u'one\n\nOne field'
>>> another = converted.getDescriptionFor('another')
>>> isinstance(another, Z2_Attribute)
True
>>> another.getName()
'another'
>>> another.getDoc()
u'another\n\nAnother field'
Methods
-------
>>> class IMethods(Z3_Interface):
... def one():
... """One method."""
... def another(arg1, arg2):
... """Another method, taking arguments."""
>>> converted = fromZ3Interface(IMethods)
>>> Z2_Interface.isEqualOrExtendedBy(converted)
1
>>> len(converted.names())
2
>>> 'one' in converted.names()
True
>>> 'another' in converted.names()
True
>>> one = converted.getDescriptionFor('one')
>>> isinstance(one, Z2_Method)
True
>>> one.getName()
'one'
>>> one.getDoc()
'One method.'
>>> one.getSignatureString()
'()'
>>> another = converted.getDescriptionFor('another')
>>> isinstance(another, Z2_Method)
True
>>> another.getName()
'another'
>>> another.getDoc()
'Another method, taking arguments.'
>>> another.getSignatureString()
'(arg1, arg2)'
Invalid parameters
------------------
>>> fromZ3Interface(None)
Traceback (most recent call last):
...
ValueError: Not a Zope 3 interface!
>>> fromZ3Interface(object())
Traceback (most recent call last):
...
ValueError: Not a Zope 3 interface!
>>> class IZ2_NotAllowed(Z2_Interface):
... pass
>>> fromZ3Interface(IZ2_NotAllowed)
Traceback (most recent call last):
...
ValueError: Not a Zope 3 interface!
##############################################################################
#
# Copyright (c) 2005 Zope Corporation 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.
#
##############################################################################
"""ZopeTestCase framework
COPY THIS FILE TO YOUR 'tests' DIRECTORY.
This version of framework.py will use the SOFTWARE_HOME
environment variable to locate Zope and the Testing package.
If the tests are run in an INSTANCE_HOME installation of Zope,
Products.__path__ and sys.path with be adjusted to include the
instance's Products and lib/python directories respectively.
If you explicitly set INSTANCE_HOME prior to running the tests,
auto-detection is disabled and the specified path will be used
instead.
If the 'tests' directory contains a custom_zodb.py file, INSTANCE_HOME
will be adjusted to use it.
If you set the ZEO_INSTANCE_HOME environment variable a ZEO setup
is assumed, and you can attach to a running ZEO server (via the
instance's custom_zodb.py).
The following code should be at the top of every test module:
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
...and the following at the bottom:
if __name__ == '__main__':
framework()
$Id$
"""
__version__ = '0.2.4'
# Save start state
#
__SOFTWARE_HOME = os.environ.get('SOFTWARE_HOME', '')
__INSTANCE_HOME = os.environ.get('INSTANCE_HOME', '')
if __SOFTWARE_HOME.endswith(os.sep):
__SOFTWARE_HOME = os.path.dirname(__SOFTWARE_HOME)
if __INSTANCE_HOME.endswith(os.sep):
__INSTANCE_HOME = os.path.dirname(__INSTANCE_HOME)
# Find and import the Testing package
#
if not sys.modules.has_key('Testing'):
p0 = sys.path[0]
if p0 and __name__ == '__main__':
os.chdir(p0)
p0 = ''
s = __SOFTWARE_HOME
p = d = s and s or os.getcwd()
while d:
if os.path.isdir(os.path.join(p, 'Testing')):
zope_home = os.path.dirname(os.path.dirname(p))
sys.path[:1] = [p0, p, zope_home]
break
p, d = s and ('','') or os.path.split(p)
else:
print 'Unable to locate Testing package.',
print 'You might need to set SOFTWARE_HOME.'
sys.exit(1)
import Testing, unittest
execfile(os.path.join(os.path.dirname(Testing.__file__), 'common.py'))
# Include ZopeTestCase support
#
if 1: # Create a new scope
p = os.path.join(os.path.dirname(Testing.__file__), 'ZopeTestCase')
if not os.path.isdir(p):
print 'Unable to locate ZopeTestCase package.',
print 'You might need to install ZopeTestCase.'
sys.exit(1)
ztc_common = 'ztc_common.py'
ztc_common_global = os.path.join(p, ztc_common)
f = 0
if os.path.exists(ztc_common_global):
execfile(ztc_common_global)
f = 1
if os.path.exists(ztc_common):
execfile(ztc_common)
f = 1
if not f:
print 'Unable to locate %s.' % ztc_common
sys.exit(1)
# Debug
#
print 'SOFTWARE_HOME: %s' % os.environ.get('SOFTWARE_HOME', 'Not set')
print 'INSTANCE_HOME: %s' % os.environ.get('INSTANCE_HOME', 'Not set')
sys.stdout.flush()
##############################################################################
#
# Copyright (c) 2005 Zope Corporation 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.
#
##############################################################################
""" Unit tests for Z3 -> Z2 bridge utilities.
$Id$
"""
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
def test_suite():
from Testing.ZopeTestCase import ZopeDocFileSuite
return ZopeDocFileSuite('bridge.txt', package="Interface.tests")
if __name__ == '__main__':
framework()
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