"""Tests for advice""" |
|
|
|
from unittest import TestCase, makeSuite, TestSuite |
from unittest import TestCase, makeSuite, TestSuite |
from protocols.advice import * |
from peak.util.decorators import * |
import dispatch |
from peak.util.decorators import with_metaclass |
import sys |
import sys |
from types import InstanceType |
|
|
|
|
|
def ping(log, value): |
def ping(log, value): |
|
|
|
"""Class decorator for testing""" |
|
|
def pong(klass): |
def pong(klass): |
log.append((value,klass)) |
log.append((value,klass)) |
return [klass] |
return [klass] |
|
|
addClassAdvisor(pong) |
decorate_class(pong) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SuperTest(TestCase): |
|
|
|
def checkMetaSuper(self): |
|
|
|
class Meta(type): |
|
def foo(self,arg): |
|
return arg |
|
foo = metamethod(foo) |
|
|
|
class Class(object): |
|
__metaclass__ = Meta |
|
|
|
def foo(self,arg): |
|
return arg*2 |
|
|
|
# Verify that ob.foo() and ob.__class__.foo() are different |
|
assert Class.foo(1)==1 |
|
assert Class().foo(1)==2 |
|
|
|
|
|
# Verify that supermeta() works for such methods |
def additional_tests(): |
|
import doctest |
class SubMeta(Meta): |
return doctest.DocFileSuite( |
def foo(self,arg): |
'README.txt', |
return -supermeta(SubMeta,self).foo(arg) |
optionflags=doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE, |
foo = metamethod(foo) |
) |
|
|
class ClassOfSubMeta(Class): |
|
__metaclass__ = SubMeta |
|
|
|
assert ClassOfSubMeta.foo(1)==-1 |
|
assert ClassOfSubMeta().foo(1)==2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def checkPropSuper(self): |
|
|
|
class Base(object): |
|
__slots__ = 'foo' |
|
|
|
class Sub(Base): |
|
|
|
def getFoo(self): |
|
return supermeta(Sub,self).foo * 2 |
|
|
|
def setFoo(self,val): |
|
Base.foo.__set__(self,val) |
|
|
|
foo = property(getFoo, setFoo) |
|
|
|
ob = Sub() |
|
ob.foo = 1 |
|
assert ob.foo == 2 |
|
|
|
|
|
def checkSuperNotFound(self): |
|
class Base(object): |
|
pass |
|
|
|
b = Base() |
|
try: |
|
supermeta(Base,b).foo |
|
except AttributeError: |
|
pass |
|
else: |
|
raise AssertionError("Shouldn't have returned a value") |
|
|
|
|
|
|
|
|
|
class DecoratorTests(TestCase): |
class DecoratorTests(TestCase): |
|
|
def checkAssignAdvice(self): |
def testAssignAdvice(self): |
|
|
log = [] |
log = [] |
def track(f,k,v,d): |
def track(f,k,v,d): |
if k in f.f_locals: |
if k in f.f_locals: |
del f.f_locals[k] # simulate old-style advisor |
del f.f_locals[k] # simulate old-style advisor |
|
|
add_assignment_advisor(track,1) |
decorate_assignment(track,frame=sys._getframe()) |
test_var = 1 |
test_var = 1 |
self.assertEqual(log, [(sys._getframe(),'test_var',1)]) |
self.assertEqual(log, [(sys._getframe(),'test_var',1)]) |
log = [] |
log = [] |
add_assignment_advisor(track,1) |
decorate_assignment(track,1) |
test2 = 42 |
test2 = 42 |
self.assertEqual(log, [(sys._getframe(),'test2',42)]) |
self.assertEqual(log, [(sys._getframe(),'test2',42)]) |
|
|
# Try doing double duty, redefining an existing variable... |
# Try doing double duty, redefining an existing variable... |
log = [] |
log = [] |
add_assignment_advisor(track,1) |
decorate_assignment(track,1) |
add_assignment_advisor(track,1) |
decorate_assignment(track,1) |
|
|
test2 = 42 |
test2 = 42 |
self.assertEqual(log, [(sys._getframe(),'test2',42)]*2) |
self.assertEqual(log, [(sys._getframe(),'test2',42)]*2) |
|
|
|
|
def checkAs(self): |
def testAs(self): |
|
|
def f(): pass |
def f(): pass |
|
|
[dispatch.as(lambda x: [x])] |
[decorate(lambda x: [x])] |
f1 = f |
f1 = f |
|
|
self.assertEqual(f1, [f]) |
self.assertEqual(f1, [f]) |
|
|
[dispatch.as(list, lambda x: (x,))] |
[decorate(list, lambda x: (x,))] |
f1 = f |
f1 = f |
self.assertEqual(f1, [f]) |
self.assertEqual(f1, [f]) |
|
|
|
|
def check24DecoratorMode(self): |
def test24DecoratorMode(self): |
|
|
log = [] |
log = [] |
def track(f,k,v,d): |
def track(f,k,v,d): |
log.append((f,k,v)) |
log.append((f,k,v)) |
|
|
def foo(x): pass |
def foo(x): pass |
|
|
add_assignment_advisor(track,1)(foo) |
decorate_assignment(track,1)(foo) |
x = 1 |
x = 1 |
|
|
self.assertEqual(log, [(sys._getframe(),'foo',foo)]) |
self.assertEqual(log, [(sys._getframe(),'foo',foo)]) |
|
|
|
def testAlreadyTracing(self): |
|
log = []; stk = [] |
|
fue = self.assertEqual.__name__ #['failUnlessEqual'] |
|
def my_global_tracer(frm,event,arg): |
|
if not stk: log.append(frm.f_code.co_name) |
|
if frm.f_code.co_name==fue: |
|
stk.append(frm) |
|
return my_local_tracer |
|
def my_local_tracer(frm, event, arg): |
|
if event=='return' and stk and stk[-1] is frm: |
|
stk.pop() |
|
return my_local_tracer |
|
|
|
sys.settrace(my_global_tracer) # This is going to break your debugger! |
|
self.testAssignAdvice() |
|
sys.settrace(None) |
|
# And this part is going to fail if testAssignAdvice() or |
|
# decorate_assignment change much... |
|
self.assertEqual(log, [ |
|
'testAssignAdvice', |
|
'decorate_assignment', 'enclosing_frame', '<lambda>', fue, |
|
'decorate_assignment', 'enclosing_frame', '<lambda>', fue, |
|
'decorate_assignment', 'enclosing_frame', '<lambda>', |
|
'decorate_assignment', 'enclosing_frame', '<lambda>', fue, |
|
]) |
|
|
|
|
|
|
|
moduleLevelFrameInfo = frameinfo(sys._getframe()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
moduleLevelFrameInfo = getFrameInfo(sys._getframe()) |
|
|
|
class FrameInfoTest(TestCase): |
class FrameInfoTest(TestCase): |
|
|
classLevelFrameInfo = getFrameInfo(sys._getframe()) |
classLevelFrameInfo = frameinfo(sys._getframe()) |
|
|
def checkModuleInfo(self): |
def testModuleInfo(self): |
kind,module,f_locals,f_globals = moduleLevelFrameInfo |
kind,module,f_locals,f_globals = moduleLevelFrameInfo |
assert kind=="module" |
assert kind=="module" |
for d in module.__dict__, f_locals, f_globals: |
for d in module.__dict__, f_locals, f_globals: |
assert d is globals() |
assert d is globals() |
|
|
def checkClassInfo(self): |
def testClassInfo(self): |
kind,module,f_locals,f_globals = self.classLevelFrameInfo |
kind,module,f_locals,f_globals = self.classLevelFrameInfo |
assert kind=="class" |
assert kind=="class" |
assert f_locals['classLevelFrameInfo'] is self.classLevelFrameInfo |
assert f_locals['classLevelFrameInfo'] is self.classLevelFrameInfo |
assert d is globals() |
assert d is globals() |
|
|
|
|
def checkCallInfo(self): |
def testCallInfo(self): |
kind,module,f_locals,f_globals = getFrameInfo(sys._getframe()) |
kind,module,f_locals,f_globals = frameinfo(sys._getframe()) |
assert kind=="function call" |
assert kind=="function call" |
assert f_locals is locals() # ??? |
assert f_locals is locals() # ??? |
for d in module.__dict__, f_globals: |
for d in module.__dict__, f_globals: |
assert d is globals() |
assert d is globals() |
|
|
|
|
|
def testClassExec(self): |
|
d = {'sys':sys, 'frameinfo':frameinfo} |
|
exec("class Foo: info=frameinfo(sys._getframe())", d) |
|
kind,module,f_locals,f_globals = d['Foo'].info |
|
assert kind=="class", kind |
|
|
|
|
|
|
|
|
|
|
|
|
|
class ClassDecoratorTests(TestCase): |
|
|
|
def testOrder(self): |
|
|
|
|
|
|
class MROTests(TestCase): |
|
|
|
def checkStdMRO(self): |
|
class foo(object): pass |
|
class bar(foo): pass |
|
class baz(foo): pass |
|
class spam(bar,baz): pass |
|
assert getMRO(spam) is spam.__mro__ |
|
|
|
def checkClassicMRO(self): |
|
class foo: pass |
|
class bar(foo): pass |
|
class baz(foo): pass |
|
class spam(bar,baz): pass |
|
basicMRO = [spam,bar,foo,baz,foo] |
|
assert list(getMRO(spam)) == basicMRO |
|
assert list(getMRO(spam,True)) == basicMRO+[InstanceType,object] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdviceTests(TestCase): |
|
|
|
def checkOrder(self): |
|
log = [] |
log = [] |
class Foo: |
class Foo: |
ping(log, 1) |
ping(log, 1) |
(3, [[Foo]]), |
(3, [[Foo]]), |
] |
] |
|
|
def checkOutside(self): |
def testOutside(self): |
try: |
try: |
ping([], 1) |
ping([], 1) |
except SyntaxError: |
except SyntaxError: |
"Should have detected advice outside class body" |
"Should have detected advice outside class body" |
) |
) |
|
|
def checkDoubleType(self): |
def testDoubleType(self): |
if sys.hexversion >= 0x02030000: |
if sys.hexversion >= 0x02030000: |
return # you can't duplicate bases in 2.3 |
return # you can't duplicate bases in 2.3 |
class aType(type,type): |
class aType(type,type): |
|
|
|
|
|
|
def checkSingleExplicitMeta(self): |
def testSingleExplicitMeta(self): |
|
|
class M(type): pass |
class M(type): pass |
|
|
class C(M): |
class C(with_metaclass(M, M)): |
__metaclass__ = M |
|
ping([],1) |
ping([],1) |
|
|
C, = C |
C, = C |
assert C.__class__ is M |
assert C.__class__ is M |
|
|
|
|
def checkMixedMetas(self): |
def testMixedMetas(self): |
|
|
class M1(type): pass |
class M1(type): pass |
class M2(type): pass |
class M2(type): pass |
|
|
class B1: __metaclass__ = M1 |
class B1(with_metaclass(M1)): pass |
class B2: __metaclass__ = M2 |
class B2(with_metaclass(M2)): pass |
|
|
try: |
try: |
class C(B1,B2): |
class C(B1,B2): |
|
|
class M3(M1,M2): pass |
class M3(M1,M2): pass |
|
|
class C(B1,B2): |
class C(with_metaclass(M3,B1,B2)): |
__metaclass__ = M3 |
|
ping([],1) |
ping([],1) |
|
|
assert isinstance(C,list) |
assert isinstance(C,list) |
|
|
|
|
|
|
def checkMetaOfClass(self): |
|
|
|
class metameta(type): |
|
pass |
|
|
|
class meta(type): |
|
__metaclass__ = metameta |
|
|
|
assert determineMetaclass((meta,type))==metameta |
|
|
|
|
|
|
|
|
|
|
|
TestClasses = ( |
|
SuperTest, DecoratorTests, AdviceTests, FrameInfoTest, MROTests, |
|
) |
|
|
|
def test_suite(): |
|
return TestSuite([makeSuite(t,'check') for t in TestClasses]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def testMetaOfClass(self): |
|
|
|
class metameta(type): |
|
pass |
|
|
|
class meta(with_metaclass(metameta, type)): |
|
pass |
|
|
|
assert metaclass_for_bases((meta,type))==metameta |
|
|
|
|
|
class ClassyMetaTests(TestCase): |
|
"""Test subclass/instance checking of classy for Python 2.6+ ABC mixin""" |
|
|
|
# avert 3.2 warnings, but still work on 2.3(!) |
|
failUnless = getattr(TestCase, 'assertTrue', TestCase.failUnless) |
|
failIf = getattr(TestCase, 'assertFalse', TestCase.failIf) |
|
|
|
def setUp(self): |
|
class x(classy): pass |
|
class y(x): pass |
|
class cc(type(classy)): pass |
|
self.__dict__.update(locals()) |
|
|
|
def test_subclassing(self): |
|
self.failUnless(issubclass(self.x, classy)) |
|
self.failUnless(issubclass(self.y, self.x)) |
|
self.failIf(issubclass(self.x, self.y)) |
|
self.failIf(issubclass(classy, self.x)) |
|
self.failIf(issubclass(self.x, type(classy))) |
|
|
|
def test_instancing(self): |
|
self.failIf(isinstance(self.x, classy)) |
|
self.failUnless(isinstance(self.x, type(classy))) |
|
self.failIf(isinstance(self.x(), type(classy))) |
|
self.failIf(isinstance(object, type(classy))) |
|
self.failIf(isinstance(self.x(),self.y)) |
|
self.failUnless(isinstance(self.y(),self.x)) |
|
|
|
|
|
|