Viewing file: test_declarations.py (11.1 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
############################################################################## # # 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. # ############################################################################## """Test the new API for making and checking interface declarations
$Id: test_declarations.py 106268 2009-12-08 08:29:06Z wosc $ """ import unittest from zope.interface import * from zope.testing.doctestunit import DocTestSuite from zope.interface import Interface
class I1(Interface): pass class I2(Interface): pass class I3(Interface): pass class I4(Interface): pass class I5(Interface): pass
class A(object): implements(I1) class B(object): implements(I2) class C(A, B): implements(I3)
class COnly(A, B): implementsOnly(I3)
class COnly_old(A, B): __implemented__ = I3 class D(COnly): implements(I5) def test_ObjectSpecification_Simple(): """ >>> c = C() >>> directlyProvides(c, I4) >>> [i.__name__ for i in providedBy(c)] ['I4', 'I3', 'I1', 'I2'] """
def test_ObjectSpecification_Simple_w_only(): """ >>> c = COnly() >>> directlyProvides(c, I4) >>> [i.__name__ for i in providedBy(c)] ['I4', 'I3'] """
def test_ObjectSpecification_Simple_old_style(): """ >>> c = COnly_old() >>> directlyProvides(c, I4) >>> [i.__name__ for i in providedBy(c)] ['I4', 'I3'] """
class Test(unittest.TestCase):
# Note that most of the tests are in the doc strings of the # declarations module.
def test_backward_compat(self):
class C1(object): __implemented__ = I1 class C2(C1): __implemented__ = I2, I5 class C3(C2): __implemented__ = I3, C2.__implemented__
self.assert_(C3.__implemented__.__class__ is tuple)
self.assertEqual( [i.getName() for i in providedBy(C3())], ['I3', 'I2', 'I5'], )
class C4(C3): implements(I4)
self.assertEqual( [i.getName() for i in providedBy(C4())], ['I4', 'I3', 'I2', 'I5'], )
self.assertEqual( [i.getName() for i in C4.__implemented__], ['I4', 'I3', 'I2', 'I5'], )
# Note that C3.__implemented__ should now be a sequence of interfaces self.assertEqual( [i.getName() for i in C3.__implemented__], ['I3', 'I2', 'I5'], ) self.failIf(C3.__implemented__.__class__ is tuple)
def test_module(self): import zope.interface.tests.m1 import zope.interface.tests.m2 directlyProvides(zope.interface.tests.m2, zope.interface.tests.m1.I1, zope.interface.tests.m1.I2, ) self.assertEqual(list(providedBy(zope.interface.tests.m1)), list(providedBy(zope.interface.tests.m2)), )
def test_builtins(self): # Setup
intspec = implementedBy(int) olddeclared = intspec.declared classImplements(int, I1) class myint(int): implements(I2)
x = 42 self.assertEqual([i.getName() for i in providedBy(x)], ['I1'])
x = myint(42) directlyProvides(x, I3) self.assertEqual([i.getName() for i in providedBy(x)], ['I3', 'I2', 'I1'])
# cleanup intspec.declared = olddeclared classImplements(int)
x = 42 self.assertEqual([i.getName() for i in providedBy(x)], [])
def test_signature_w_no_class_interfaces(): """ >>> from zope.interface import * >>> class C(object): ... pass >>> c = C() >>> list(providedBy(c)) [] >>> class I(Interface): ... pass >>> directlyProvides(c, I) >>> list(providedBy(c)) == list(directlyProvidedBy(c)) 1 """
def test_classImplement_on_deeply_nested_classes(): """This test is in response to a bug found, which is why it's a bit contrived
>>> from zope.interface import * >>> class B1(object): ... pass >>> class B2(B1): ... pass >>> class B3(B2): ... pass >>> class D(object): ... implements() >>> class S(B3, D): ... implements()
This failed due to a bug in the code for finding __providedBy__ descriptors for old-style classes.
"""
def test_pickle_provides_specs(): """ >>> from pickle import dumps, loads >>> a = A() >>> I2.providedBy(a) 0 >>> directlyProvides(a, I2) >>> I2.providedBy(a) 1 >>> a2 = loads(dumps(a)) >>> I2.providedBy(a2) 1 """
def test_that_we_dont_inherit_class_provides(): """ >>> class X(object): ... classProvides(I1) >>> class Y(X): ... pass >>> [i.__name__ for i in X.__provides__] ['I1'] >>> Y.__provides__ Traceback (most recent call last): ... AttributeError: __provides__ """
def test_that_we_dont_inherit_provides_optimizations(): """
When we make a declaration for a class, we install a __provides__ descriptors that provides a default for instances that don't have instance-specific declarations: >>> class A(object): ... implements(I1)
>>> class B(object): ... implements(I2)
>>> [i.__name__ for i in A().__provides__] ['I1'] >>> [i.__name__ for i in B().__provides__] ['I2']
But it's important that we don't use this for subclasses without declarations. This would cause incorrect results:
>>> class X(A, B): ... pass
>>> X().__provides__ Traceback (most recent call last): ... AttributeError: __provides__
However, if we "induce" a declaration, by calling implementedBy (even indirectly through providedBy):
>>> [i.__name__ for i in providedBy(X())] ['I1', 'I2']
then the optimization will work: >>> [i.__name__ for i in X().__provides__] ['I1', 'I2'] """
def test_classProvides_before_implements(): """Special descriptor for class __provides__
The descriptor caches the implementedBy info, so that we can get declarations for objects without instance-specific interfaces a bit quicker.
For example::
>>> from zope.interface import Interface >>> class IFooFactory(Interface): ... pass >>> class IFoo(Interface): ... pass >>> class C(object): ... classProvides(IFooFactory) ... implements(IFoo) >>> [i.getName() for i in C.__provides__] ['IFooFactory']
>>> [i.getName() for i in C().__provides__] ['IFoo'] """
def test_getting_spec_for_proxied_builtin_class(): """
In general, we should be able to get a spec for a proxied class if someone has declared or asked for a spec before.
We don't want to depend on proxies in this (zope.interface) package, but we do want to work with proxies. Proxies have the effect that a class's __dict__ cannot be gotten. Further, for built-in classes, we can't save, and thus, cannot get, any class attributes. We'll emulate this by treating a plain object as a class:
>>> cls = object()
We'll create an implements specification:
>>> import zope.interface.declarations >>> impl = zope.interface.declarations.Implements(I1, I2)
Now, we'll emulate a declaration for a built-in type by putting it in BuiltinImplementationSpecifications:
>>> zope.interface.declarations.BuiltinImplementationSpecifications[ ... cls] = impl
Now, we should be able to get it back:
>>> implementedBy(cls) is impl True
Of course, we don't want to leave it there. :)
>>> del zope.interface.declarations.BuiltinImplementationSpecifications[ ... cls]
"""
def test_declaration_get(): """ We can get definitions from a declaration:
>>> import zope.interface >>> class I1(zope.interface.Interface): ... a11 = zope.interface.Attribute('a11') ... a12 = zope.interface.Attribute('a12') >>> class I2(zope.interface.Interface): ... a21 = zope.interface.Attribute('a21') ... a22 = zope.interface.Attribute('a22') ... a12 = zope.interface.Attribute('a212') >>> class I11(I1): ... a11 = zope.interface.Attribute('a111')
>>> decl = Declaration(I11, I2) >>> decl.get('a11') is I11.get('a11') True >>> decl.get('a12') is I1.get('a12') True >>> decl.get('a21') is I2.get('a21') True >>> decl.get('a22') is I2.get('a22') True >>> decl.get('a') >>> decl.get('a', 42) 42
We get None even with no interfaces:
>>> decl = Declaration() >>> decl.get('a11') >>> decl.get('a11', 42) 42
We get new data if e change interface bases:
>>> decl.__bases__ = I11, I2 >>> decl.get('a11') is I11.get('a11') True """
def test_classImplements_after_classImplementsOnly_issue_402(): """http://www.zope.org/Collectors/Zope3-dev/402
>>> from zope.interface import * >>> class I1(Interface): ... pass >>> class I2(Interface): ... pass >>> class C: ... implements(I1) >>> class C2: ... implementsOnly(I2) >>> class I3(Interface): ... pass
>>> [i.__name__ for i in providedBy(C2()).__iro__] ['I2', 'Interface']
>>> classImplements(C2, I3) >>> [i.__name__ for i in providedBy(C2()).__iro__] ['I2', 'I3', 'Interface']
>>> class I4(Interface): ... pass >>> classImplements(C2, I4) >>> [i.__name__ for i in providedBy(C2()).__iro__] ['I2', 'I3', 'I4', 'Interface']
"""
def test_picklability_of_implements_specifications(): """
Sometimes, we need to pickle implements specs. We should be able to do so as long as the class is picklable.
>>> import pickle >>> pickle.loads(pickle.dumps(implementedBy(C))) is implementedBy(C) True """
def test_provided_by_with_slots(): """
This is an edge case: if the __slots__ of a class contain '__provides__', using providedBy() on that class should still work (this occurs, for example, when providing an adapter for a concrete class.)
>>> import zope.interface >>> class Slotted(object): ... __slots__ = ('__provides__') >>> class IFoo(zope.interface.Interface): ... pass >>> IFoo.providedBy(Slotted) False
"""
def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(Test)) suite.addTest(DocTestSuite("zope.interface.declarations")) suite.addTest(DocTestSuite()) return suite
if __name__ == '__main__': unittest.main()
|