Mini Shell
##############################################################################
#
# 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.
#
##############################################################################
"""Adapter registry tests
"""
import unittest
from zope.interface.tests import OptimizationTestMixin
# pylint:disable=inherit-non-class,protected-access,too-many-lines
# pylint:disable=attribute-defined-outside-init,blacklisted-name
def _makeInterfaces():
from zope.interface import Interface
class IB0(Interface):
pass
class IB1(IB0):
pass
class IB2(IB0):
pass
class IB3(IB2, IB1):
pass
class IB4(IB1, IB2):
pass
class IF0(Interface):
pass
class IF1(IF0):
pass
class IR0(Interface):
pass
class IR1(IR0):
pass
return IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1
# Custom types to use as part of the AdapterRegistry data structures.
# Our custom types do strict type checking to make sure
# types propagate through the data tree as expected.
class CustomDataTypeBase:
_data = None
def __getitem__(self, name):
return self._data[name]
def __setitem__(self, name, value):
self._data[name] = value
def __delitem__(self, name):
del self._data[name]
def __len__(self):
return len(self._data)
def __contains__(self, name):
return name in self._data
def __eq__(self, other):
if other is self:
return True
# pylint:disable=unidiomatic-typecheck
if type(other) is not type(self):
return False
return other._data == self._data
def __repr__(self):
return repr(self._data)
class CustomMapping(CustomDataTypeBase):
def __init__(self, other=None):
self._data = {}
if other:
self._data.update(other)
self.get = self._data.get
self.items = self._data.items
class CustomSequence(CustomDataTypeBase):
def __init__(self, other=None):
self._data = []
if other:
self._data.extend(other)
self.append = self._data.append
class CustomLeafSequence(CustomSequence):
pass
class CustomProvided(CustomMapping):
pass
class BaseAdapterRegistryTests(unittest.TestCase):
maxDiff = None
def _getBaseAdapterRegistry(self):
from zope.interface.adapter import BaseAdapterRegistry
return BaseAdapterRegistry
def _getTargetClass(self):
BaseAdapterRegistry = self._getBaseAdapterRegistry()
class _CUT(BaseAdapterRegistry):
class LookupClass:
_changed = _extendors = ()
def __init__(self, reg):
pass
def changed(self, orig):
self._changed += (orig,)
def add_extendor(self, provided):
self._extendors += (provided,)
def remove_extendor(self, provided):
self._extendors = tuple([x for x in self._extendors
if x != provided])
for name in BaseAdapterRegistry._delegated:
setattr(_CUT.LookupClass, name, object())
return _CUT
def _makeOne(self):
return self._getTargetClass()()
def _getMappingType(self):
return dict
def _getProvidedType(self):
return dict
def _getMutableListType(self):
return list
def _getLeafSequenceType(self):
return tuple
def test_lookup_delegation(self):
CUT = self._getTargetClass()
registry = CUT()
for name in CUT._delegated:
self.assertIs(
getattr(registry, name), getattr(registry._v_lookup, name)
)
def test__generation_on_first_creation(self):
registry = self._makeOne()
# Bumped to 1 in BaseAdapterRegistry.__init__
self.assertEqual(registry._generation, 1)
def test__generation_after_calling_changed(self):
registry = self._makeOne()
orig = object()
registry.changed(orig)
# Bumped to 1 in BaseAdapterRegistry.__init__
self.assertEqual(registry._generation, 2)
self.assertEqual(registry._v_lookup._changed, (registry, orig,))
def test__generation_after_changing___bases__(self):
class _Base:
pass
registry = self._makeOne()
registry.__bases__ = (_Base,)
self.assertEqual(registry._generation, 2)
def _check_basic_types_of_adapters(self, registry, expected_order=2):
self.assertEqual(
len(registry._adapters), expected_order,
) # order 0 and order 1
self.assertIsInstance(registry._adapters, self._getMutableListType())
MT = self._getMappingType()
for mapping in registry._adapters:
self.assertIsInstance(mapping, MT)
self.assertEqual(registry._adapters[0], MT())
self.assertIsInstance(registry._adapters[1], MT)
self.assertEqual(len(registry._adapters[expected_order - 1]), 1)
def _check_basic_types_of_subscribers(self, registry, expected_order=2):
self.assertEqual(
len(registry._subscribers), expected_order,
) # order 0 and order 1
self.assertIsInstance(
registry._subscribers, self._getMutableListType(),
)
MT = self._getMappingType()
for mapping in registry._subscribers:
self.assertIsInstance(mapping, MT)
if expected_order:
self.assertEqual(registry._subscribers[0], MT())
self.assertIsInstance(registry._subscribers[1], MT)
self.assertEqual(len(registry._subscribers[expected_order - 1]), 1)
def test_register(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.register([IB0], IR0, '', 'A1')
self.assertEqual(registry.registered([IB0], IR0, ''), 'A1')
self.assertEqual(registry._generation, 2)
self._check_basic_types_of_adapters(registry)
MT = self._getMappingType()
self.assertEqual(registry._adapters[1], MT({
IB0: MT({
IR0: MT({'': 'A1'})
})
}))
PT = self._getProvidedType()
self.assertEqual(registry._provided, PT({
IR0: 1
}))
registered = list(registry.allRegistrations())
self.assertEqual(registered, [(
(IB0,), # required
IR0, # provided
'', # name
'A1' # value
)])
def test_register_multiple_allRegistrations(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
# Use several different depths and several different names
registry.register([], IR0, '', 'A1')
registry.register([], IR0, 'name1', 'A2')
registry.register([IB0], IR0, '', 'A1')
registry.register([IB0], IR0, 'name2', 'A2')
registry.register([IB0], IR1, '', 'A3')
registry.register([IB0], IR1, 'name3', 'A4')
registry.register([IB0, IB1], IR0, '', 'A1')
registry.register([IB0, IB2], IR0, 'name2', 'A2')
registry.register([IB0, IB2], IR1, 'name4', 'A4')
registry.register([IB0, IB3], IR1, '', 'A3')
def build_adapters(L, MT):
return L([
# 0
MT({
IR0: MT({
'': 'A1',
'name1': 'A2'
})
}),
# 1
MT({
IB0: MT({
IR0: MT({
'': 'A1',
'name2': 'A2'
}),
IR1: MT({
'': 'A3',
'name3': 'A4'
})
})
}),
# 3
MT({
IB0: MT({
IB1: MT({
IR0: MT({'': 'A1'})
}),
IB2: MT({
IR0: MT({'name2': 'A2'}),
IR1: MT({'name4': 'A4'}),
}),
IB3: MT({
IR1: MT({'': 'A3'})
})
}),
}),
])
self.assertEqual(registry._adapters,
build_adapters(L=self._getMutableListType(),
MT=self._getMappingType()))
registered = sorted(registry.allRegistrations())
self.assertEqual(registered, [
((), IR0, '', 'A1'),
((), IR0, 'name1', 'A2'),
((IB0,), IR0, '', 'A1'),
((IB0,), IR0, 'name2', 'A2'),
((IB0,), IR1, '', 'A3'),
((IB0,), IR1, 'name3', 'A4'),
((IB0, IB1), IR0, '', 'A1'),
((IB0, IB2), IR0, 'name2', 'A2'),
((IB0, IB2), IR1, 'name4', 'A4'),
((IB0, IB3), IR1, '', 'A3')
])
# We can duplicate to another object.
registry2 = self._makeOne()
for args in registered:
registry2.register(*args)
self.assertEqual(registry2._adapters, registry._adapters)
self.assertEqual(registry2._provided, registry._provided)
# We can change the types and rebuild the data structures.
registry._mappingType = CustomMapping
registry._leafSequenceType = CustomLeafSequence
registry._sequenceType = CustomSequence
registry._providedType = CustomProvided
def addValue(existing, new):
existing = (
existing if existing is not None else CustomLeafSequence()
)
existing.append(new)
return existing
registry._addValueToLeaf = addValue
registry.rebuild()
self.assertEqual(registry._adapters,
build_adapters(
L=CustomSequence,
MT=CustomMapping
))
def test_register_with_invalid_name(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
with self.assertRaises(ValueError):
registry.register([IB0], IR0, object(), 'A1')
def test_register_with_value_None_unregisters(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.register([None], IR0, '', 'A1')
registry.register([None], IR0, '', None)
self.assertEqual(len(registry._adapters), 0)
self.assertIsInstance(registry._adapters, self._getMutableListType())
registered = list(registry.allRegistrations())
self.assertEqual(registered, [])
def test_register_with_same_value(self):
from zope.interface import Interface
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
_value = object()
registry.register([None], IR0, '', _value)
_before = registry._generation
registry.register([None], IR0, '', _value)
self.assertEqual(registry._generation, _before) # skipped changed()
self._check_basic_types_of_adapters(registry)
MT = self._getMappingType()
self.assertEqual(registry._adapters[1], MT(
{
Interface: MT(
{
IR0: MT({'': _value})
}
)
}
))
registered = list(registry.allRegistrations())
self.assertEqual(registered, [(
(Interface,), # required
IR0, # provided
'', # name
_value # value
)])
def test_registered_empty(self):
registry = self._makeOne()
self.assertEqual(registry.registered([None], None, ''), None)
registered = list(registry.allRegistrations())
self.assertEqual(registered, [])
def test_registered_non_empty_miss(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.register([IB1], None, '', 'A1')
self.assertEqual(registry.registered([IB2], None, ''), None)
def test_registered_non_empty_hit(self):
registry = self._makeOne()
registry.register([None], None, '', 'A1')
self.assertEqual(registry.registered([None], None, ''), 'A1')
def test_unregister_empty(self):
registry = self._makeOne()
registry.unregister([None], None, '') # doesn't raise
self.assertEqual(registry.registered([None], None, ''), None)
self.assertEqual(len(registry._provided), 0)
def test_unregister_non_empty_miss_on_required(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.register([IB1], None, '', 'A1')
registry.unregister([IB2], None, '') # doesn't raise
self.assertEqual(registry.registered([IB1], None, ''), 'A1')
self._check_basic_types_of_adapters(registry)
MT = self._getMappingType()
self.assertEqual(registry._adapters[1], MT(
{
IB1: MT(
{
None: MT({'': 'A1'})
}
)
}
))
PT = self._getProvidedType()
self.assertEqual(registry._provided, PT({
None: 1
}))
def test_unregister_non_empty_miss_on_name(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.register([IB1], None, '', 'A1')
registry.unregister([IB1], None, 'nonesuch') # doesn't raise
self.assertEqual(registry.registered([IB1], None, ''), 'A1')
self._check_basic_types_of_adapters(registry)
MT = self._getMappingType()
self.assertEqual(registry._adapters[1], MT(
{
IB1: MT(
{
None: MT({'': 'A1'})
}
)
}
))
PT = self._getProvidedType()
self.assertEqual(registry._provided, PT({
None: 1
}))
def test_unregister_with_value_not_None_miss(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
orig = object()
nomatch = object()
registry.register([IB1], None, '', orig)
registry.unregister([IB1], None, '', nomatch) # doesn't raise
self.assertIs(registry.registered([IB1], None, ''), orig)
def test_unregister_hit_clears_empty_subcomponents(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
one = object()
another = object()
registry.register([IB1, IB2], None, '', one)
registry.register([IB1, IB3], None, '', another)
self._check_basic_types_of_adapters(registry, expected_order=3)
self.assertIn(IB2, registry._adapters[2][IB1])
self.assertIn(IB3, registry._adapters[2][IB1])
MT = self._getMappingType()
self.assertEqual(registry._adapters[2], MT(
{
IB1: MT(
{
IB2: MT({None: MT({'': one})}),
IB3: MT({None: MT({'': another})})
}
)
}
))
PT = self._getProvidedType()
self.assertEqual(registry._provided, PT({
None: 2
}))
registry.unregister([IB1, IB3], None, '', another)
self.assertIn(IB2, registry._adapters[2][IB1])
self.assertNotIn(IB3, registry._adapters[2][IB1])
self.assertEqual(registry._adapters[2], MT(
{
IB1: MT(
{
IB2: MT({None: MT({'': one})}),
}
)
}
))
self.assertEqual(registry._provided, PT({
None: 1
}))
def test_unsubscribe_empty(self):
registry = self._makeOne()
registry.unsubscribe([None], None, '') # doesn't raise
self.assertEqual(registry.registered([None], None, ''), None)
self._check_basic_types_of_subscribers(registry, expected_order=0)
def test_unsubscribe_hit(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
orig = object()
registry.subscribe([IB1], None, orig)
MT = self._getMappingType()
L = self._getLeafSequenceType()
PT = self._getProvidedType()
self._check_basic_types_of_subscribers(registry)
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
None: MT({
'': L((orig,))
})
})
}))
self.assertEqual(registry._provided, PT({}))
registry.unsubscribe([IB1], None, orig) # doesn't raise
self.assertEqual(len(registry._subscribers), 0)
self.assertEqual(registry._provided, PT({}))
def assertLeafIdentity(self, leaf1, leaf2):
"""
Implementations may choose to use new, immutable objects
instead of mutating existing subscriber leaf objects, or vice versa.
The default implementation uses immutable tuples, so they are never
the same. Other implementations may use persistent lists so they
should be the same and mutated in place. Subclasses testing this
behaviour need to override this method.
"""
self.assertIsNot(leaf1, leaf2)
def test_unsubscribe_after_multiple(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
first = object()
second = object()
third = object()
fourth = object()
registry.subscribe([IB1], None, first)
registry.subscribe([IB1], None, second)
registry.subscribe([IB1], IR0, third)
registry.subscribe([IB1], IR0, fourth)
self._check_basic_types_of_subscribers(registry, expected_order=2)
MT = self._getMappingType()
L = self._getLeafSequenceType()
PT = self._getProvidedType()
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
None: MT({'': L((first, second))}),
IR0: MT({'': L((third, fourth))}),
})
}))
self.assertEqual(registry._provided, PT({
IR0: 2
}))
# The leaf objects may or may not stay the same as they are
# unsubscribed, depending on the implementation
IR0_leaf_orig = registry._subscribers[1][IB1][IR0]['']
Non_leaf_orig = registry._subscribers[1][IB1][None]['']
registry.unsubscribe([IB1], None, first)
registry.unsubscribe([IB1], IR0, third)
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
None: MT({'': L((second,))}),
IR0: MT({'': L((fourth,))}),
})
}))
self.assertEqual(registry._provided, PT({
IR0: 1
}))
IR0_leaf_new = registry._subscribers[1][IB1][IR0]['']
Non_leaf_new = registry._subscribers[1][IB1][None]['']
self.assertLeafIdentity(IR0_leaf_orig, IR0_leaf_new)
self.assertLeafIdentity(Non_leaf_orig, Non_leaf_new)
registry.unsubscribe([IB1], None, second)
registry.unsubscribe([IB1], IR0, fourth)
self.assertEqual(len(registry._subscribers), 0)
self.assertEqual(len(registry._provided), 0)
def test_subscribe_unsubscribe_identical_objects_provided(self):
# https://github.com/zopefoundation/zope.interface/issues/227
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
first = object()
registry.subscribe([IB1], IR0, first)
registry.subscribe([IB1], IR0, first)
MT = self._getMappingType()
L = self._getLeafSequenceType()
PT = self._getProvidedType()
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
IR0: MT({'': L((first, first))}),
})
}))
self.assertEqual(registry._provided, PT({
IR0: 2
}))
registry.unsubscribe([IB1], IR0, first)
registry.unsubscribe([IB1], IR0, first)
self.assertEqual(len(registry._subscribers), 0)
self.assertEqual(registry._provided, PT())
def test_subscribe_unsubscribe_nonequal_objects_provided(self):
# https://github.com/zopefoundation/zope.interface/issues/227
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
first = object()
second = object()
registry.subscribe([IB1], IR0, first)
registry.subscribe([IB1], IR0, second)
MT = self._getMappingType()
L = self._getLeafSequenceType()
PT = self._getProvidedType()
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
IR0: MT({'': L((first, second))}),
})
}))
self.assertEqual(registry._provided, PT({
IR0: 2
}))
registry.unsubscribe([IB1], IR0, first)
registry.unsubscribe([IB1], IR0, second)
self.assertEqual(len(registry._subscribers), 0)
self.assertEqual(registry._provided, PT())
def test_subscribed_empty(self):
registry = self._makeOne()
self.assertIsNone(registry.subscribed([None], None, ''))
subscribed = list(registry.allSubscriptions())
self.assertEqual(subscribed, [])
def test_subscribed_non_empty_miss(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.subscribe([IB1], IF0, 'A1')
# Mismatch required
self.assertIsNone(registry.subscribed([IB2], IF0, ''))
# Mismatch provided
self.assertIsNone(registry.subscribed([IB1], IF1, ''))
# Mismatch value
self.assertIsNone(registry.subscribed([IB1], IF0, ''))
def test_subscribed_non_empty_hit(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.subscribe([IB0], IF0, 'A1')
self.assertEqual(registry.subscribed([IB0], IF0, 'A1'), 'A1')
def test_unsubscribe_w_None_after_multiple(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
first = object()
second = object()
registry.subscribe([IB1], None, first)
registry.subscribe([IB1], None, second)
self._check_basic_types_of_subscribers(registry, expected_order=2)
registry.unsubscribe([IB1], None)
self.assertEqual(len(registry._subscribers), 0)
def test_unsubscribe_non_empty_miss_on_required(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.subscribe([IB1], None, 'A1')
self._check_basic_types_of_subscribers(registry, expected_order=2)
registry.unsubscribe([IB2], None, '') # doesn't raise
self.assertEqual(len(registry._subscribers), 2)
MT = self._getMappingType()
L = self._getLeafSequenceType()
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
None: MT({'': L(('A1',))}),
})
}))
def test_unsubscribe_non_empty_miss_on_value(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
registry.subscribe([IB1], None, 'A1')
self._check_basic_types_of_subscribers(registry, expected_order=2)
registry.unsubscribe([IB1], None, 'A2') # doesn't raise
self.assertEqual(len(registry._subscribers), 2)
MT = self._getMappingType()
L = self._getLeafSequenceType()
self.assertEqual(registry._subscribers[1], MT({
IB1: MT({
None: MT({'': L(('A1',))}),
})
}))
def test_unsubscribe_with_value_not_None_miss(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
orig = object()
nomatch = object()
registry.subscribe([IB1], None, orig)
registry.unsubscribe([IB1], None, nomatch) # doesn't raise
self.assertEqual(len(registry._subscribers), 2)
def _instance_method_notify_target(self):
self.fail("Example method, not intended to be called.")
def test_unsubscribe_instance_method(self):
# Checking that the values are compared by equality, not identity
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
self.assertEqual(len(registry._subscribers), 0)
registry.subscribe([IB1], None, self._instance_method_notify_target)
registry.unsubscribe([IB1], None, self._instance_method_notify_target)
self.assertEqual(len(registry._subscribers), 0)
def test_subscribe_multiple_allRegistrations(self):
(
IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1,
) = _makeInterfaces() # pylint:disable=unused-variable
registry = self._makeOne()
# Use several different depths and several different values
registry.subscribe([], IR0, 'A1')
registry.subscribe([], IR0, 'A2')
registry.subscribe([IB0], IR0, 'A1')
registry.subscribe([IB0], IR0, 'A2')
registry.subscribe([IB0], IR1, 'A3')
registry.subscribe([IB0], IR1, 'A4')
registry.subscribe([IB0, IB1], IR0, 'A1')
registry.subscribe([IB0, IB2], IR0, 'A2')
registry.subscribe([IB0, IB2], IR1, 'A4')
registry.subscribe([IB0, IB3], IR1, 'A3')
def build_subscribers(L, F, MT):
return L([
# 0
MT({
IR0: MT({
'': F(['A1', 'A2'])
})
}),
# 1
MT({
IB0: MT({
IR0: MT({
'': F(['A1', 'A2'])
}),
IR1: MT({
'': F(['A3', 'A4'])
})
})
}),
# 3
MT({
IB0: MT({
IB1: MT({
IR0: MT({'': F(['A1'])})
}),
IB2: MT({
IR0: MT({'': F(['A2'])}),
IR1: MT({'': F(['A4'])}),
}),
IB3: MT({
IR1: MT({'': F(['A3'])})
})
}),
}),
])
self.assertEqual(registry._subscribers,
build_subscribers(
L=self._getMutableListType(),
F=self._getLeafSequenceType(),
MT=self._getMappingType()
))
def build_provided(P):
return P({
IR0: 6,
IR1: 4,
})
self.assertEqual(registry._provided,
build_provided(P=self._getProvidedType()))
registered = sorted(registry.allSubscriptions())
self.assertEqual(registered, [
((), IR0, 'A1'),
((), IR0, 'A2'),
((IB0,), IR0, 'A1'),
((IB0,), IR0, 'A2'),
((IB0,), IR1, 'A3'),
((IB0,), IR1, 'A4'),
((IB0, IB1), IR0, 'A1'),
((IB0, IB2), IR0, 'A2'),
((IB0, IB2), IR1, 'A4'),
((IB0, IB3), IR1, 'A3')
])
# We can duplicate this to another object
registry2 = self._makeOne()
for args in registered:
registry2.subscribe(*args)
self.assertEqual(registry2._subscribers, registry._subscribers)
self.assertEqual(registry2._provided, registry._provided)
# We can change the types and rebuild the data structures.
registry._mappingType = CustomMapping
registry._leafSequenceType = CustomLeafSequence
registry._sequenceType = CustomSequence
registry._providedType = CustomProvided
def addValue(existing, new):
existing = (
existing if existing is not None else CustomLeafSequence()
)
existing.append(new)
return existing
registry._addValueToLeaf = addValue
registry.rebuild()
self.assertEqual(registry._subscribers,
build_subscribers(
L=CustomSequence,
F=CustomLeafSequence,
MT=CustomMapping
))
class CustomTypesBaseAdapterRegistryTests(BaseAdapterRegistryTests):
"""
This class may be extended by other packages to test their own
adapter registries that use custom types. (So be cautious about
breaking changes.)
One known user is ``zope.component.persistentregistry``.
"""
def _getMappingType(self):
return CustomMapping
def _getProvidedType(self):
return CustomProvided
def _getMutableListType(self):
return CustomSequence
def _getLeafSequenceType(self):
return CustomLeafSequence
def _getBaseAdapterRegistry(self):
from zope.interface.adapter import BaseAdapterRegistry
class CustomAdapterRegistry(BaseAdapterRegistry):
_mappingType = self._getMappingType()
_sequenceType = self._getMutableListType()
_leafSequenceType = self._getLeafSequenceType()
_providedType = self._getProvidedType()
def _addValueToLeaf(self, existing_leaf_sequence, new_item):
if not existing_leaf_sequence:
existing_leaf_sequence = self._leafSequenceType()
existing_leaf_sequence.append(new_item)
return existing_leaf_sequence
def _removeValueFromLeaf(self, existing_leaf_sequence, to_remove):
without_removed = BaseAdapterRegistry._removeValueFromLeaf(
self,
existing_leaf_sequence,
to_remove)
existing_leaf_sequence[:] = without_removed
assert to_remove not in existing_leaf_sequence
return existing_leaf_sequence
return CustomAdapterRegistry
def assertLeafIdentity(self, leaf1, leaf2):
self.assertIs(leaf1, leaf2)
class LookupBaseFallbackTests(unittest.TestCase):
def _getFallbackClass(self):
from zope.interface.adapter import LookupBaseFallback
return LookupBaseFallback
_getTargetClass = _getFallbackClass
def _makeOne(
self, uc_lookup=None, uc_lookupAll=None, uc_subscriptions=None,
):
# pylint:disable=function-redefined
if uc_lookup is None:
def uc_lookup(self, required, provided, name):
pass
if uc_lookupAll is None:
def uc_lookupAll(self, required, provided):
raise NotImplementedError()
if uc_subscriptions is None:
def uc_subscriptions(self, required, provided):
raise NotImplementedError()
class Derived(self._getTargetClass()):
_uncached_lookup = uc_lookup
_uncached_lookupAll = uc_lookupAll
_uncached_subscriptions = uc_subscriptions
return Derived()
def test_lookup_w_invalid_name(self):
def _lookup(self, required, provided, name):
self.fail("This should never be called")
lb = self._makeOne(uc_lookup=_lookup)
with self.assertRaises(ValueError):
lb.lookup(('A',), 'B', object())
def test_lookup_miss_no_default(self):
_called_with = []
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C')
self.assertIsNone(found)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
def test_lookup_miss_w_default(self):
_called_with = []
_default = object()
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C', _default)
self.assertIs(found, _default)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
def test_lookup_not_cached(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup_cached(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C')
found = lb.lookup(('A',), 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup_not_cached_multi_required(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A', 'D'), 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A', 'D'), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup_cached_multi_required(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A', 'D'), 'B', 'C')
found = lb.lookup(('A', 'D'), 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A', 'D'), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup_not_cached_after_changed(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C')
lb.changed(lb)
found = lb.lookup(('A',), 'B', 'C')
self.assertIs(found, b)
self.assertEqual(_called_with,
[(('A',), 'B', 'C'), (('A',), 'B', 'C')])
self.assertEqual(_results, [c])
def test_lookup1_w_invalid_name(self):
def _lookup(self, required, provided, name):
self.fail("This should never be called")
lb = self._makeOne(uc_lookup=_lookup)
with self.assertRaises(ValueError):
lb.lookup1('A', 'B', object())
def test_lookup1_miss_no_default(self):
_called_with = []
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C')
self.assertIsNone(found)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
def test_lookup1_miss_w_default(self):
_called_with = []
_default = object()
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C', _default)
self.assertIs(found, _default)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
def test_lookup1_miss_w_default_negative_cache(self):
_called_with = []
_default = object()
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C', _default)
self.assertIs(found, _default)
found = lb.lookup1('A', 'B', 'C', _default)
self.assertIs(found, _default)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
def test_lookup1_not_cached(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup1_cached(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C')
found = lb.lookup1('A', 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
def test_lookup1_not_cached_after_changed(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
lb = self._makeOne(uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C')
lb.changed(lb)
found = lb.lookup1('A', 'B', 'C')
self.assertIs(found, b)
self.assertEqual(_called_with,
[(('A',), 'B', 'C'), (('A',), 'B', 'C')])
self.assertEqual(_results, [c])
def test_adapter_hook_w_invalid_name(self):
req, prv = object(), object()
lb = self._makeOne()
with self.assertRaises(ValueError):
lb.adapter_hook(prv, req, object())
def test_adapter_hook_miss_no_default(self):
req, prv = object(), object()
lb = self._makeOne()
found = lb.adapter_hook(prv, req, '')
self.assertIsNone(found)
def test_adapter_hook_miss_w_default(self):
req, prv, _default = object(), object(), object()
lb = self._makeOne()
found = lb.adapter_hook(prv, req, '', _default)
self.assertIs(found, _default)
def test_adapter_hook_hit_factory_returns_None(self):
_f_called_with = []
def _factory(context):
_f_called_with.append(context)
def _lookup(self, required, provided, name):
return _factory
req, prv, _default = object(), object(), object()
lb = self._makeOne(uc_lookup=_lookup)
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, _default)
self.assertEqual(_f_called_with, [req])
def test_adapter_hook_hit_factory_returns_adapter(self):
_f_called_with = []
_adapter = object()
def _factory(context):
_f_called_with.append(context)
return _adapter
def _lookup(self, required, provided, name):
return _factory
req, prv, _default = object(), object(), object()
lb = self._makeOne(uc_lookup=_lookup)
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, _adapter)
self.assertEqual(_f_called_with, [req])
def test_adapter_hook_super_unwraps(self):
_f_called_with = []
def _factory(context):
_f_called_with.append(context)
return context
def _lookup(self, required, provided, name=''):
return _factory
required = super()
provided = object()
lb = self._makeOne(uc_lookup=_lookup)
adapted = lb.adapter_hook(provided, required)
self.assertIs(adapted, self)
self.assertEqual(_f_called_with, [self])
def test_queryAdapter(self):
_f_called_with = []
_adapter = object()
def _factory(context):
_f_called_with.append(context)
return _adapter
def _lookup(self, required, provided, name):
return _factory
req, prv, _default = object(), object(), object()
lb = self._makeOne(uc_lookup=_lookup)
adapted = lb.queryAdapter(req, prv, 'C', _default)
self.assertIs(adapted, _adapter)
self.assertEqual(_f_called_with, [req])
def test_lookupAll_uncached(self):
_called_with = []
_results = [object(), object(), object()]
def _lookupAll(self, required, provided):
_called_with.append((required, provided))
return tuple(_results)
lb = self._makeOne(uc_lookupAll=_lookupAll)
found = lb.lookupAll('A', 'B')
self.assertEqual(found, tuple(_results))
self.assertEqual(_called_with, [(('A',), 'B')])
def test_lookupAll_cached(self):
_called_with = []
_results = [object(), object(), object()]
def _lookupAll(self, required, provided):
_called_with.append((required, provided))
return tuple(_results)
lb = self._makeOne(uc_lookupAll=_lookupAll)
found = lb.lookupAll('A', 'B')
found = lb.lookupAll('A', 'B')
self.assertEqual(found, tuple(_results))
self.assertEqual(_called_with, [(('A',), 'B')])
def test_subscriptions_uncached(self):
_called_with = []
_results = [object(), object(), object()]
def _subscriptions(self, required, provided):
_called_with.append((required, provided))
return tuple(_results)
lb = self._makeOne(uc_subscriptions=_subscriptions)
found = lb.subscriptions('A', 'B')
self.assertEqual(found, tuple(_results))
self.assertEqual(_called_with, [(('A',), 'B')])
def test_subscriptions_cached(self):
_called_with = []
_results = [object(), object(), object()]
def _subscriptions(self, required, provided):
_called_with.append((required, provided))
return tuple(_results)
lb = self._makeOne(uc_subscriptions=_subscriptions)
found = lb.subscriptions('A', 'B')
found = lb.subscriptions('A', 'B')
self.assertEqual(found, tuple(_results))
self.assertEqual(_called_with, [(('A',), 'B')])
class LookupBaseTests(LookupBaseFallbackTests,
OptimizationTestMixin):
def _getTargetClass(self):
from zope.interface.adapter import LookupBase
return LookupBase
class VerifyingBaseFallbackTests(unittest.TestCase):
def _getFallbackClass(self):
from zope.interface.adapter import VerifyingBaseFallback
return VerifyingBaseFallback
_getTargetClass = _getFallbackClass
def _makeOne(self, registry, uc_lookup=None, uc_lookupAll=None,
uc_subscriptions=None):
# pylint:disable=function-redefined
if uc_lookup is None:
def uc_lookup(self, required, provided, name):
raise NotImplementedError()
if uc_lookupAll is None:
def uc_lookupAll(self, required, provided):
raise NotImplementedError()
if uc_subscriptions is None:
def uc_subscriptions(self, required, provided):
raise NotImplementedError()
class Derived(self._getTargetClass()):
_uncached_lookup = uc_lookup
_uncached_lookupAll = uc_lookupAll
_uncached_subscriptions = uc_subscriptions
def __init__(self, registry):
super().__init__()
self._registry = registry
derived = Derived(registry)
derived.changed(derived) # init. '_verify_ro' / '_verify_generations'
return derived
def _makeRegistry(self, depth):
class WithGeneration:
_generation = 1
class Registry:
def __init__(self, depth):
self.ro = [WithGeneration() for i in range(depth)]
return Registry(depth)
def test_lookup(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_lookup=_lookup)
found = lb.lookup(('A',), 'B', 'C')
found = lb.lookup(('A',), 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
reg.ro[1]._generation += 1
found = lb.lookup(('A',), 'B', 'C')
self.assertIs(found, b)
self.assertEqual(_called_with,
[(('A',), 'B', 'C'), (('A',), 'B', 'C')])
self.assertEqual(_results, [c])
def test_lookup1(self):
_called_with = []
a, b, c = object(), object(), object()
_results = [a, b, c]
def _lookup(self, required, provided, name):
_called_with.append((required, provided, name))
return _results.pop(0)
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_lookup=_lookup)
found = lb.lookup1('A', 'B', 'C')
found = lb.lookup1('A', 'B', 'C')
self.assertIs(found, a)
self.assertEqual(_called_with, [(('A',), 'B', 'C')])
self.assertEqual(_results, [b, c])
reg.ro[1]._generation += 1
found = lb.lookup1('A', 'B', 'C')
self.assertIs(found, b)
self.assertEqual(_called_with,
[(('A',), 'B', 'C'), (('A',), 'B', 'C')])
self.assertEqual(_results, [c])
def test_adapter_hook(self):
a, b, _c = [object(), object(), object()] # noqa F841
def _factory1(context):
return a
def _factory2(context):
return b
def _factory3(context):
self.fail("This should never be called")
_factories = [_factory1, _factory2, _factory3]
def _lookup(self, required, provided, name):
return _factories.pop(0)
req, prv, _default = object(), object(), object()
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_lookup=_lookup)
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, a)
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, a)
reg.ro[1]._generation += 1
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, b)
def test_queryAdapter(self):
a, b, _c = [object(), object(), object()] # noqa F841
def _factory1(context):
return a
def _factory2(context):
return b
def _factory3(context):
self.fail("This should never be called")
_factories = [_factory1, _factory2, _factory3]
def _lookup(self, required, provided, name):
return _factories.pop(0)
req, prv, _default = object(), object(), object()
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_lookup=_lookup)
adapted = lb.queryAdapter(req, prv, 'C', _default)
self.assertIs(adapted, a)
adapted = lb.queryAdapter(req, prv, 'C', _default)
self.assertIs(adapted, a)
reg.ro[1]._generation += 1
adapted = lb.adapter_hook(prv, req, 'C', _default)
self.assertIs(adapted, b)
def test_lookupAll(self):
_results_1 = [object(), object(), object()]
_results_2 = [object(), object(), object()]
_results = [_results_1, _results_2]
def _lookupAll(self, required, provided):
return tuple(_results.pop(0))
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_lookupAll=_lookupAll)
found = lb.lookupAll('A', 'B')
self.assertEqual(found, tuple(_results_1))
found = lb.lookupAll('A', 'B')
self.assertEqual(found, tuple(_results_1))
reg.ro[1]._generation += 1
found = lb.lookupAll('A', 'B')
self.assertEqual(found, tuple(_results_2))
def test_subscriptions(self):
_results_1 = [object(), object(), object()]
_results_2 = [object(), object(), object()]
_results = [_results_1, _results_2]
def _subscriptions(self, required, provided):
return tuple(_results.pop(0))
reg = self._makeRegistry(3)
lb = self._makeOne(reg, uc_subscriptions=_subscriptions)
found = lb.subscriptions('A', 'B')
self.assertEqual(found, tuple(_results_1))
found = lb.subscriptions('A', 'B')
self.assertEqual(found, tuple(_results_1))
reg.ro[1]._generation += 1
found = lb.subscriptions('A', 'B')
self.assertEqual(found, tuple(_results_2))
class VerifyingBaseTests(VerifyingBaseFallbackTests,
OptimizationTestMixin):
def _getTargetClass(self):
from zope.interface.adapter import VerifyingBase
return VerifyingBase
class AdapterLookupBaseTests(unittest.TestCase):
def _getTargetClass(self):
from zope.interface.adapter import AdapterLookupBase
return AdapterLookupBase
def _makeOne(self, registry):
return self._getTargetClass()(registry)
def _makeSubregistry(self, *provided):
class Subregistry:
def __init__(self):
self._adapters = []
self._subscribers = []
return Subregistry()
def _makeRegistry(self, *provided):
class Registry:
def __init__(self, provided):
self._provided = provided
self.ro = []
return Registry(provided)
def test_ctor_empty_registry(self):
registry = self._makeRegistry()
alb = self._makeOne(registry)
self.assertEqual(alb._extendors, {})
def test_ctor_w_registry_provided(self):
from zope.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
alb = self._makeOne(registry)
self.assertEqual(sorted(alb._extendors.keys()),
sorted([IBar, IFoo, Interface]))
self.assertEqual(alb._extendors[IFoo], [IFoo, IBar])
self.assertEqual(alb._extendors[IBar], [IBar])
self.assertEqual(sorted(alb._extendors[Interface]),
sorted([IFoo, IBar]))
def test_changed_empty_required(self):
# ALB.changed expects to call a mixed in changed.
class Mixin:
def changed(self, *other):
pass
class Derived(self._getTargetClass(), Mixin):
pass
registry = self._makeRegistry()
alb = Derived(registry)
alb.changed(alb)
def test_changed_w_required(self):
# ALB.changed expects to call a mixed in changed.
class Mixin:
def changed(self, *other):
pass
class Derived(self._getTargetClass(), Mixin):
pass
class FauxWeakref:
_unsub = None
def __init__(self, here):
self._here = here
def __call__(self):
return self if self._here else None
def unsubscribe(self, target):
self._unsub = target
gone = FauxWeakref(False)
here = FauxWeakref(True)
registry = self._makeRegistry()
alb = Derived(registry)
alb._required[gone] = 1
alb._required[here] = 1
alb.changed(alb)
self.assertEqual(len(alb._required), 0)
self.assertEqual(gone._unsub, None)
self.assertEqual(here._unsub, alb)
def test_init_extendors_after_registry_update(self):
from zope.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
alb = self._makeOne(registry)
registry._provided = [IFoo, IBar]
alb.init_extendors()
self.assertEqual(sorted(alb._extendors.keys()),
sorted([IBar, IFoo, Interface]))
self.assertEqual(alb._extendors[IFoo], [IFoo, IBar])
self.assertEqual(alb._extendors[IBar], [IBar])
self.assertEqual(sorted(alb._extendors[Interface]),
sorted([IFoo, IBar]))
def test_add_extendor(self):
from zope.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
alb = self._makeOne(registry)
alb.add_extendor(IFoo)
alb.add_extendor(IBar)
self.assertEqual(sorted(alb._extendors.keys()),
sorted([IBar, IFoo, Interface]))
self.assertEqual(alb._extendors[IFoo], [IFoo, IBar])
self.assertEqual(alb._extendors[IBar], [IBar])
self.assertEqual(sorted(alb._extendors[Interface]),
sorted([IFoo, IBar]))
def test_remove_extendor(self):
from zope.interface import Interface
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
alb = self._makeOne(registry)
alb.remove_extendor(IFoo)
self.assertEqual(sorted(alb._extendors.keys()),
sorted([IFoo, IBar, Interface]))
self.assertEqual(alb._extendors[IFoo], [IBar])
self.assertEqual(alb._extendors[IBar], [IBar])
self.assertEqual(sorted(alb._extendors[Interface]),
sorted([IBar]))
# test '_subscribe' via its callers, '_uncached_lookup', etc.
def test__uncached_lookup_empty_ro(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
alb = self._makeOne(registry)
result = alb._uncached_lookup((IFoo,), IBar)
self.assertEqual(result, None)
self.assertEqual(len(alb._required), 1)
self.assertIn(IFoo.weakref(), alb._required)
def test__uncached_lookup_order_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
registry.ro.append(subr)
alb = self._makeOne(registry)
result = alb._uncached_lookup((IFoo,), IBar)
self.assertEqual(result, None)
def test__uncached_lookup_extendors_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
subr = self._makeSubregistry()
subr._adapters = [{}, {}] # utilities, single adapters
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookup((IFoo,), IBar)
self.assertEqual(result, None)
def test__uncached_lookup_components_miss_wrong_iface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
IQux = InterfaceClass('IQux')
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
irrelevant = object()
subr._adapters = [ # utilities, single adapters
{},
{
IFoo: {
IQux: {'': irrelevant},
},
},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookup((IFoo,), IBar)
self.assertEqual(result, None)
def test__uncached_lookup_components_miss_wrong_name(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
wrongname = object()
subr._adapters = [ # utilities, single adapters
{},
{
IFoo: {
IBar: {'wrongname': wrongname},
},
},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookup((IFoo,), IBar)
self.assertEqual(result, None)
def test__uncached_lookup_simple_hit(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_expected = object()
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _expected}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookup((IFoo,), IBar)
self.assertIs(result, _expected)
def test__uncached_lookup_repeated_hit(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_expected = object()
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _expected}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookup((IFoo,), IBar)
result2 = alb._uncached_lookup((IFoo,), IBar)
self.assertIs(result, _expected)
self.assertIs(result2, _expected)
def test_queryMultiAdaptor_lookup_miss(self):
from zope.interface.declarations import implementer
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
@implementer(IFoo)
class Foo:
pass
foo = Foo()
registry = self._makeRegistry()
subr = self._makeSubregistry()
subr._adapters = [ # utilities, single adapters
{},
{},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.lookup = alb._uncached_lookup # provided by derived
subr._v_lookup = alb
_default = object()
result = alb.queryMultiAdapter((foo,), IBar, default=_default)
self.assertIs(result, _default)
def test_queryMultiAdapter_errors_on_attribute_access(self):
# Any error on attribute access previously lead to using the _empty
# singleton as "requires" argument (See
# https://github.com/zopefoundation/zope.interface/issues/162)
# but after https://github.com/zopefoundation/zope.interface/issues/200
# they get propagated.
from zope.interface.interface import InterfaceClass
from zope.interface.tests import MissingSomeAttrs
IFoo = InterfaceClass('IFoo')
registry = self._makeRegistry()
alb = self._makeOne(registry)
alb.lookup = alb._uncached_lookup
def test(ob):
return alb.queryMultiAdapter(
(ob,),
IFoo,
)
MissingSomeAttrs.test_raises(self, test, expected_missing='__class__')
def test_queryMultiAdaptor_factory_miss(self):
from zope.interface.declarations import implementer
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
@implementer(IFoo)
class Foo:
pass
foo = Foo()
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_called_with = []
def _factory(context):
_called_with.append(context)
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _factory}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.lookup = alb._uncached_lookup # provided by derived
subr._v_lookup = alb
_default = object()
result = alb.queryMultiAdapter((foo,), IBar, default=_default)
self.assertIs(result, _default)
self.assertEqual(_called_with, [foo])
def test_queryMultiAdaptor_factory_hit(self):
from zope.interface.declarations import implementer
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
@implementer(IFoo)
class Foo:
pass
foo = Foo()
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_expected = object()
_called_with = []
def _factory(context):
_called_with.append(context)
return _expected
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _factory}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.lookup = alb._uncached_lookup # provided by derived
subr._v_lookup = alb
_default = object()
result = alb.queryMultiAdapter((foo,), IBar, default=_default)
self.assertIs(result, _expected)
self.assertEqual(_called_with, [foo])
def test_queryMultiAdapter_super_unwraps(self):
alb = self._makeOne(self._makeRegistry())
def lookup(*args):
return factory
def factory(*args):
return args
alb.lookup = lookup
objects = [
super(),
42,
"abc",
super(),
]
result = alb.queryMultiAdapter(objects, None)
self.assertEqual(result, (
self,
42,
"abc",
self,
))
def test__uncached_lookupAll_empty_ro(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
alb = self._makeOne(registry)
result = alb._uncached_lookupAll((IFoo,), IBar)
self.assertEqual(result, ())
self.assertEqual(len(alb._required), 1)
self.assertIn(IFoo.weakref(), alb._required)
def test__uncached_lookupAll_order_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookupAll((IFoo,), IBar)
self.assertEqual(result, ())
def test__uncached_lookupAll_extendors_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
subr = self._makeSubregistry()
subr._adapters = [{}, {}] # utilities, single adapters
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookupAll((IFoo,), IBar)
self.assertEqual(result, ())
def test__uncached_lookupAll_components_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
IQux = InterfaceClass('IQux')
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
irrelevant = object()
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IQux: {'': irrelevant}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookupAll((IFoo,), IBar)
self.assertEqual(result, ())
def test__uncached_lookupAll_simple_hit(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_expected = object()
_named = object()
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _expected, 'named': _named}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_lookupAll((IFoo,), IBar)
self.assertEqual(sorted(result), [('', _expected), ('named', _named)])
def test_names(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_expected = object()
_named = object()
subr._adapters = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': _expected, 'named': _named}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.lookupAll = alb._uncached_lookupAll
subr._v_lookup = alb
result = alb.names((IFoo,), IBar)
self.assertEqual(sorted(result), ['', 'named'])
def test__uncached_subscriptions_empty_ro(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
alb = self._makeOne(registry)
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(result, [])
self.assertEqual(len(alb._required), 1)
self.assertIn(IFoo.weakref(), alb._required)
def test__uncached_subscriptions_order_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(result, [])
def test__uncached_subscriptions_extendors_miss(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry()
subr = self._makeSubregistry()
subr._subscribers = [{}, {}] # utilities, single adapters
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(result, [])
def test__uncached_subscriptions_components_miss_wrong_iface(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
IQux = InterfaceClass('IQux')
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
irrelevant = object()
subr._subscribers = [ # utilities, single adapters
{},
{IFoo: {IQux: {'': irrelevant}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(result, [])
def test__uncached_subscriptions_components_miss_wrong_name(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
wrongname = object()
subr._subscribers = [ # utilities, single adapters
{},
{IFoo: {IBar: {'wrongname': wrongname}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(result, [])
def test__uncached_subscriptions_simple_hit(self):
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
class Foo:
def __lt__(self, other):
return True
_exp1, _exp2 = Foo(), Foo()
subr._subscribers = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': (_exp1, _exp2)}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
subr._v_lookup = alb
result = alb._uncached_subscriptions((IFoo,), IBar)
self.assertEqual(sorted(result), sorted([_exp1, _exp2]))
def test_subscribers_wo_provided(self):
from zope.interface.declarations import implementer
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
@implementer(IFoo)
class Foo:
pass
foo = Foo()
registry = self._makeRegistry(IFoo, IBar)
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_called = {}
def _factory1(context):
_called.setdefault('_factory1', []).append(context)
def _factory2(context):
_called.setdefault('_factory2', []).append(context)
subr._subscribers = [ # utilities, single adapters
{},
{IFoo: {None: {'': (_factory1, _factory2)}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.subscriptions = alb._uncached_subscriptions
subr._v_lookup = alb
result = alb.subscribers((foo,), None)
self.assertEqual(result, ())
self.assertEqual(_called, {'_factory1': [foo], '_factory2': [foo]})
def test_subscribers_w_provided(self):
from zope.interface.declarations import implementer
from zope.interface.interface import InterfaceClass
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
@implementer(IFoo)
class Foo:
pass
foo = Foo()
registry = self._makeRegistry(IFoo, IBar)
registry = self._makeRegistry(IFoo, IBar)
subr = self._makeSubregistry()
_called = {}
_exp1, _exp2 = object(), object()
def _factory1(context):
_called.setdefault('_factory1', []).append(context)
return _exp1
def _factory2(context):
_called.setdefault('_factory2', []).append(context)
return _exp2
def _side_effect_only(context):
_called.setdefault('_side_effect_only', []).append(context)
subr._subscribers = [ # utilities, single adapters
{},
{IFoo: {IBar: {'': (_factory1, _factory2, _side_effect_only)}}},
]
registry.ro.append(subr)
alb = self._makeOne(registry)
alb.subscriptions = alb._uncached_subscriptions
subr._v_lookup = alb
result = alb.subscribers((foo,), IBar)
self.assertEqual(result, [_exp1, _exp2])
self.assertEqual(
_called, {
'_factory1': [foo],
'_factory2': [foo],
'_side_effect_only': [foo],
}
)
class VerifyingAdapterRegistryTests(unittest.TestCase):
# This is also the base for AdapterRegistryTests. That makes the
# inheritance seems backwards, but even though they implement the
# same interfaces, VAR and AR each only extend BAR; and neither
# one will pass the test cases for BAR (it uses a special
# LookupClass just for the tests).
def _getTargetClass(self):
from zope.interface.adapter import VerifyingAdapterRegistry
return VerifyingAdapterRegistry
def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)
def test_verify_object_provides_IAdapterRegistry(self):
from zope.interface.interfaces import IAdapterRegistry
from zope.interface.verify import verifyObject
registry = self._makeOne()
verifyObject(IAdapterRegistry, registry)
class AdapterRegistryTests(VerifyingAdapterRegistryTests):
def _getTargetClass(self):
from zope.interface.adapter import AdapterRegistry
return AdapterRegistry
def test_ctor_no_bases(self):
ar = self._makeOne()
self.assertEqual(len(ar._v_subregistries), 0)
def test_ctor_w_bases(self):
base = self._makeOne()
sub = self._makeOne([base])
self.assertEqual(len(sub._v_subregistries), 0)
self.assertEqual(len(base._v_subregistries), 1)
self.assertIn(sub, base._v_subregistries)
# test _addSubregistry / _removeSubregistry via only caller, _setBases
def test__setBases_removing_existing_subregistry(self):
before = self._makeOne()
after = self._makeOne()
sub = self._makeOne([before])
sub.__bases__ = [after]
self.assertEqual(len(before._v_subregistries), 0)
self.assertEqual(len(after._v_subregistries), 1)
self.assertIn(sub, after._v_subregistries)
def test__setBases_wo_stray_entry(self):
before = self._makeOne()
stray = self._makeOne()
after = self._makeOne()
sub = self._makeOne([before])
sub.__dict__['__bases__'].append(stray)
sub.__bases__ = [after]
self.assertEqual(len(before._v_subregistries), 0)
self.assertEqual(len(after._v_subregistries), 1)
self.assertIn(sub, after._v_subregistries)
def test__setBases_w_existing_entry_continuing(self):
before = self._makeOne()
after = self._makeOne()
sub = self._makeOne([before])
sub.__bases__ = [before, after]
self.assertEqual(len(before._v_subregistries), 1)
self.assertEqual(len(after._v_subregistries), 1)
self.assertIn(sub, before._v_subregistries)
self.assertIn(sub, after._v_subregistries)
def test_changed_w_subregistries(self):
base = self._makeOne()
class Derived:
_changed = None
def changed(self, originally_changed):
self._changed = originally_changed
derived1, derived2 = Derived(), Derived()
base._addSubregistry(derived1)
base._addSubregistry(derived2)
orig = object()
base.changed(orig)
self.assertIs(derived1._changed, orig)
self.assertIs(derived2._changed, orig)
class Test_utils(unittest.TestCase):
def test__convert_None_to_Interface_w_None(self):
from zope.interface.adapter import _convert_None_to_Interface
from zope.interface.interface import Interface
self.assertIs(_convert_None_to_Interface(None), Interface)
def test__convert_None_to_Interface_w_other(self):
from zope.interface.adapter import _convert_None_to_Interface
other = object()
self.assertIs(_convert_None_to_Interface(other), other)
def test__normalize_name_str(self):
from zope.interface.adapter import _normalize_name
STR = b'str'
UNICODE = 'str'
norm = _normalize_name(STR)
self.assertEqual(norm, UNICODE)
self.assertIsInstance(norm, type(UNICODE))
def test__normalize_name_unicode(self):
from zope.interface.adapter import _normalize_name
USTR = 'ustr'
self.assertEqual(_normalize_name(USTR), USTR)
def test__normalize_name_other(self):
from zope.interface.adapter import _normalize_name
for other in 1, 1.0, (), [], {}, object():
self.assertRaises(TypeError, _normalize_name, other)
# _lookup, _lookupAll, and _subscriptions tested via their callers
# (AdapterLookupBase.{lookup,lookupAll,subscriptions}).
Zerion Mini Shell 1.0