[Zope3-checkins] CVS: Zope3/src/zope/app/services/tests - test_surrogates.py:1.1.2.1

Jim Fulton cvs-admin at zope.org
Wed Nov 12 15:08:14 EST 2003


Update of /cvs-repository/Zope3/src/zope/app/services/tests
In directory cvs.zope.org:/tmp/cvs-serv25370/src/zope/app/services/tests

Added Files:
      Tag: adaptergeddon-branch
	test_surrogates.py 
Log Message:
Added local surrogates, to be used for local adapter and presentation
services.


=== Added File Zope3/src/zope/app/services/tests/test_surrogates.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Local Surrogate Tests

   Local surrogates and surrogate registries share declarations with
   those "above" them.

   Suppose we have a global SurrogateRegistry:

   >>> G = SurrogateRegistry()

   we also have a local surrogate registry, with G as it's base:

   >>> L1 = LocalSurrogateRegistry(G)

   and so on:

   >>> L2 = LocalSurrogateRegistry(G, L1)

   Now, if we declare an adapter globally:

   >>> G.provideAdapter(IF1, IB1, [A11G])

   we can query it locally:

   >>> f2 = F2()

   >>> a = L1.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   >>> a = L2.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   We can add local definitions:

   >>> ra011 = Registration(required = IF0, provided=IB1, factory=A011)
   >>> L1.createRegistrationsFor(ra011).activate(ra011)

   and use it:

   >>> f0 = F0()

   >>> a = L1.queryAdapter(f0, IB1)
   >>> a.__class__.__name__
   'A011'
   >>> a.args == (f0, )
   True

   >>> a = L2.queryAdapter(f0, IB1)
   >>> a.__class__.__name__
   'A011'
   >>> a.args == (f0, )
   True

   but not outside L1:

   >>> G.queryAdapter(f0, IB1)

   Note that it doesn't override the non-local adapter:

   >>> a = L1.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   >>> a = L2.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   because it was more specific.

   Let's override the adapter in L2:

   >>> ra112 = Registration(required = IF1, provided=IB1, factory=A112)
   >>> L2.createRegistrationsFor(ra112).activate(ra112)

   Now, in L2, we get the new adapter, because it's as specific and more
   local than the one from G:

   >>> a = L2.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A112'
   >>> a.args == (f2, )
   True

   But we still get thye old one in L1

   >>> a = L1.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   Note that we can ask for less specific interfaces and still get the adapter:

   >>> a = L2.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A112'
   >>> a.args == (f2, )
   True

   >>> a = L1.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A11G'
   >>> a.args == (f2, )
   True

   We get the more specific adapter even if there is a less-specific
   adapter to B0:

   >>> G.provideAdapter(IF1, IB1, [A10G])

   >>> a = L2.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A112'
   >>> a.args == (f2, )
   True

   But if we have an equally specific and equally local adapter to B0, it
   will win:

   >>> ra102 = Registration(required = IF1, provided=IB0, factory=A102)
   >>> L2.createRegistrationsFor(ra102).activate(ra102)

   >>> a = L2.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A102'
   >>> a.args == (f2, )
   True

   We can deactivate registrations, which has the effect of deleting adapters:


   >>> L2.queryRegistrationsFor(ra112).deactivate(ra112)

   >>> a = L2.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A102'
   >>> a.args == (f2, )
   True

   >>> a = L2.queryAdapter(f2, IB1)
   >>> a.__class__.__name__
   'A10G'
   >>> a.args == (f2, )
   True

   >>> L2.queryRegistrationsFor(ra102).deactivate(ra102)

   >>> a = L2.queryAdapter(f2, IB0)
   >>> a.__class__.__name__
   'A10G'
   >>> a.args == (f2, )
   True

   $Id: test_surrogates.py,v 1.1.2.1 2003/11/12 20:08:13 jim Exp $
   """

def test_named_adapters():
    """
    Suppose we have a global SurrogateRegistry:

    >>> G = SurrogateRegistry()

    we also have a local surrogate registry, with G as it's base:

    >>> L1 = LocalSurrogateRegistry(G)

    and so on:

    >>> L2 = LocalSurrogateRegistry(G, L1)

    Now, if we declare an adapter globally:

    >>> G.provideAdapter(IF1, IB1, [A11G], name='bob')

    we can query it locally:

    >>> f2 = F2()

    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    We can add local definitions:

    >>> ra011 = Registration(required = IF0, provided=IB1, factory=A011,
    ...                      name='bob')
    >>> L1.createRegistrationsFor(ra011).activate(ra011)
    
    and use it:

    >>> f0 = F0()

    >>> L1.queryAdapter(f0, IB1)
    >>> a = L1.queryNamedAdapter(f0, IB1, 'bob')
    >>> a.__class__.__name__
    'A011'
    >>> a.args == (f0, )
    True

    >>> L2.queryAdapter(f0, IB1)
    >>> a = L2.queryNamedAdapter(f0, IB1, 'bob')
    >>> a.__class__.__name__
    'A011'
    >>> a.args == (f0, )
    True

    but not outside L1:

    >>> G.queryAdapter(f0, IB1)

    Note that it doesn't override the non-local adapter:

    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    because it was more specific.

    Let's override the adapter in L2:

    >>> ra112 = Registration(required = IF1, provided=IB1, factory=A112,
    ...                      name='bob')
    >>> L2.createRegistrationsFor(ra112).activate(ra112)

    Now, in L2, we get the new adapter, because it's as specific and more
    local than the one from G:

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    But we still get thye old one in L1

    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    Note that we can ask for less specific interfaces and still get the adapter:

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    >>> L1.queryAdapter(f2, IB0)
    >>> a = L1.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    We get the more specific adapter even if there is a less-specific
    adapter to B0:

    >>> G.provideAdapter(IF1, IB1, [A10G], name='bob')

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    But if we have an equally specific and equally local adapter to B0, it
    will win:

    >>> ra102 = Registration(required = IF1, provided=IB0, factory=A102,
    ...                      name='bob')
    >>> L2.createRegistrationsFor(ra102).activate(ra102)
    
    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A102'
    >>> a.args == (f2, )
    True

    We can deactivate registrations, which has the effect of deleting adapters:


    >>> L2.queryRegistrationsFor(ra112).deactivate(ra112)

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A102'
    >>> a.args == (f2, )
    True

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A10G'
    >>> a.args == (f2, )
    True

    >>> L2.queryRegistrationsFor(ra102).deactivate(ra102)

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A10G'
    >>> a.args == (f2, )
    True
    """





def test_persistence():
    """
    >>> storage = MemoryFullStorage('test')
    >>> db = DB(storage)
    >>> conn1 = db.open()

    >>> G = globalSurrogateRegistry
    >>> L1 = LocalSurrogateRegistry(G)
    >>> L2 = LocalSurrogateRegistry(G, L1)

    >>> conn1.root()['L1'] = L1
    >>> conn1.root()['L2'] = L2
    
    >>> G.provideAdapter(IF1, IB1, [A11G], name='bob')
    >>> f2 = F2()
    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    We can add local definitions:

    >>> ra011 = Registration(required = IF0, provided=IB1, factory=A011,
    ...                      name='bob')
    >>> L1.createRegistrationsFor(ra011).activate(ra011)

    and use it:

    >>> f0 = F0()

    >>> L1.queryAdapter(f0, IB1)
    >>> a = L1.queryNamedAdapter(f0, IB1, 'bob')
    >>> a.__class__.__name__
    'A011'
    >>> a.args == (f0, )
    True

    >>> L2.queryAdapter(f0, IB1)
    >>> a = L2.queryNamedAdapter(f0, IB1, 'bob')
    >>> a.__class__.__name__
    'A011'
    >>> a.args == (f0, )
    True

    but not outside L1:

    >>> G.queryAdapter(f0, IB1)

    Note that it doesn't override the non-local adapter:

    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    because it was more specific.

    Let's override the adapter in L2:

    >>> ra112 = Registration(required = IF1, provided=IB1, factory=A112,
    ...                      name='bob')
    >>> L2.createRegistrationsFor(ra112).activate(ra112)

    Now, in L2, we get the new adapter, because it's as specific and more
    local than the one from G:

    >>> L2.queryAdapter(f2, IB1)
    >>> a = L2.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    But we still get the old one in L1

    >>> L1.queryAdapter(f2, IB1)
    >>> a = L1.queryNamedAdapter(f2, IB1, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    Note that we can ask for less specific interfaces and still get the adapter:

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    >>> L1.queryAdapter(f2, IB0)
    >>> a = L1.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A11G'
    >>> a.args == (f2, )
    True

    We get the more specific adapter even if there is a less-specific
    adapter to B0:

    >>> G.provideAdapter(IF0, IB0, [A00G], name='bob')

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A112'
    >>> a.args == (f2, )
    True

    But if we have an equally specific and equally local adapter to B0, it
    will win:

    >>> ra102 = Registration(required = IF1, provided=IB0, factory=A102,
    ...                      name='bob')
    >>> L2.createRegistrationsFor(ra102).activate(ra102)

    >>> L2.queryAdapter(f2, IB0)
    >>> a = L2.queryNamedAdapter(f2, IB0, 'bob')
    >>> a.__class__.__name__
    'A102'
    >>> a.args == (f2, )
    True

    >>> L1.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L1.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A102'
    >>> L2.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A112'

    >>> get_transaction().commit()

    Now, let's open another transaction:

    >>> conn2 = db.open()

    >>> L1 = conn2.root()['L1']
    >>> L2 = conn2.root()['L2']

    We should get the same outputs:

    >>> L1.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L1.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A102'
    >>> L2.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A112'
    
    We can deactivate registrations, which has the effect of deleting adapters:

    >>> L2.queryRegistrationsFor(ra112).deactivate(ra112)
    >>> L2.queryRegistrationsFor(ra102).deactivate(ra102)

    >>> L1.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L1.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'

    >>> get_transaction().commit()

    If we look back at the first connection, we should get the same data:

    >>> conn1.sync()
    >>> L1 = conn1.root()['L1']
    >>> L2 = conn1.root()['L2']

    We should see the result of the deactivations:
    
    >>> L1.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L1.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB0, 'bob').__class__.__name__
    'A11G'
    >>> L2.queryNamedAdapter(f2, IB1, 'bob').__class__.__name__
    'A11G'

    Cleanup:
    >>> G.__init__()
    >>> db.close()
    """

import unittest
from zope.testing.doctestunit import DocTestSuite
from zope.interface.surrogate import SurrogateRegistry
from zope.app.services.surrogate import LocalSurrogateRegistry
import zope.interface
from zodb.storage.memory import MemoryFullStorage
from zodb.db import DB
from transaction import get_transaction

class IF0(zope.interface.Interface):
    pass

class IF1(IF0):
    pass

class IF2(IF1):
    pass

class IB0(zope.interface.Interface):
    pass

class IB1(IB0):
    pass

class F0:
    zope.interface.implements(IF0)

class F2:
    zope.interface.implements(IF2)

class Adapter:
    def __init__(self, *args):
        self.args = args

class A00G(Adapter):
    pass

class A11G(Adapter):
    pass

class A112(Adapter):
    pass

class A10G(Adapter):
    pass

class A102(Adapter):
    pass

class A011(Adapter):
    pass

class Registration:
    name=u''
    with=()
    provided=zope.interface.Interface
    required=None
    
    def __init__(self, **kw):
        self.__dict__.update(kw)
    def __call__(self, *args):
        return self.factory(*args)

# Create a picklable global registry. The pickleability of other
# global surrogate registries is beyond the scope of these tests:
class GlobalSurogateRegistry(SurrogateRegistry):
    def __reduce__(self):
        return 'globalSurrogateRegistry'

globalSurrogateRegistry = GlobalSurogateRegistry()

class TestStack:
    registration = None

    def __init__(self, parent):
        self.__parent__ = parent

    def activate(self, registration):
        self.registration = registration
        self.__parent__.notifyActivated(self, registration)

    def deactivate(self, registration):
        self.registration = None
        self.__parent__.notifyDeactivated(self, registration)

    def active(self):
        return self.registration
    

class LocalSurrogateRegistry(LocalSurrogateRegistry):
    """For testing, use custom stack type
    """
    _stackType = TestStack
    

def test_suite():
    return unittest.TestSuite((
        DocTestSuite(),
        ))

if __name__ == '__main__': unittest.main()




More information about the Zope3-Checkins mailing list