123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- # Copyright (c) Twisted Matrix Laboratories.
- # See LICENSE for details.
- import sys, os
- import types
- from twisted.trial import unittest
- from twisted.python import rebuild
- import crash_test_dummy
- f = crash_test_dummy.foo
- class Foo: pass
- class Bar(Foo): pass
- class Baz(object): pass
- class Buz(Bar, Baz): pass
- class HashRaisesRuntimeError:
- """
- Things that don't hash (raise an Exception) should be ignored by the
- rebuilder.
- @ivar hashCalled: C{bool} set to True when __hash__ is called.
- """
- def __init__(self):
- self.hashCalled = False
- def __hash__(self):
- self.hashCalled = True
- raise RuntimeError('not a TypeError!')
- unhashableObject = None # set in test_hashException
- class RebuildTests(unittest.TestCase):
- """
- Simple testcase for rebuilding, to at least exercise the code.
- """
- def setUp(self):
- self.libPath = self.mktemp()
- os.mkdir(self.libPath)
- self.fakelibPath = os.path.join(self.libPath, 'twisted_rebuild_fakelib')
- os.mkdir(self.fakelibPath)
- open(os.path.join(self.fakelibPath, '__init__.py'), 'w').close()
- sys.path.insert(0, self.libPath)
- def tearDown(self):
- sys.path.remove(self.libPath)
- def testFileRebuild(self):
- from twisted.python.util import sibpath
- import shutil, time
- shutil.copyfile(sibpath(__file__, "myrebuilder1.py"),
- os.path.join(self.fakelibPath, "myrebuilder.py"))
- from twisted_rebuild_fakelib import myrebuilder
- a = myrebuilder.A()
- try:
- object
- except NameError:
- pass
- else:
- from twisted.test import test_rebuild
- b = myrebuilder.B()
- class C(myrebuilder.B):
- pass
- test_rebuild.C = C
- C()
- i = myrebuilder.Inherit()
- self.assertEqual(a.a(), 'a')
- # necessary because the file has not "changed" if a second has not gone
- # by in unix. This sucks, but it's not often that you'll be doing more
- # than one reload per second.
- time.sleep(1.1)
- shutil.copyfile(sibpath(__file__, "myrebuilder2.py"),
- os.path.join(self.fakelibPath, "myrebuilder.py"))
- rebuild.rebuild(myrebuilder)
- try:
- object
- except NameError:
- pass
- else:
- b2 = myrebuilder.B()
- self.assertEqual(b2.b(), 'c')
- self.assertEqual(b.b(), 'c')
- self.assertEqual(i.a(), 'd')
- self.assertEqual(a.a(), 'b')
- # more work to be done on new-style classes
- # self.assertEqual(c.b(), 'c')
- def testRebuild(self):
- """
- Rebuilding an unchanged module.
- """
- # This test would actually pass if rebuild was a no-op, but it
- # ensures rebuild doesn't break stuff while being a less
- # complex test than testFileRebuild.
- x = crash_test_dummy.X('a')
- rebuild.rebuild(crash_test_dummy, doLog=False)
- # Instance rebuilding is triggered by attribute access.
- x.do()
- self.failUnlessIdentical(x.__class__, crash_test_dummy.X)
- self.failUnlessIdentical(f, crash_test_dummy.foo)
- def testComponentInteraction(self):
- x = crash_test_dummy.XComponent()
- x.setAdapter(crash_test_dummy.IX, crash_test_dummy.XA)
- x.getComponent(crash_test_dummy.IX)
- rebuild.rebuild(crash_test_dummy, 0)
- newComponent = x.getComponent(crash_test_dummy.IX)
- newComponent.method()
- self.assertEqual(newComponent.__class__, crash_test_dummy.XA)
- # Test that a duplicate registerAdapter is not allowed
- from twisted.python import components
- self.assertRaises(ValueError, components.registerAdapter,
- crash_test_dummy.XA, crash_test_dummy.X,
- crash_test_dummy.IX)
- def testUpdateInstance(self):
- global Foo, Buz
- b = Buz()
- class Foo:
- def foo(self):
- pass
- class Buz(Bar, Baz):
- x = 10
- rebuild.updateInstance(b)
- assert hasattr(b, 'foo'), "Missing method on rebuilt instance"
- assert hasattr(b, 'x'), "Missing class attribute on rebuilt instance"
- def testBananaInteraction(self):
- from twisted.python import rebuild
- from twisted.spread import banana
- rebuild.latestClass(banana.Banana)
- def test_hashException(self):
- """
- Rebuilding something that has a __hash__ that raises a non-TypeError
- shouldn't cause rebuild to die.
- """
- global unhashableObject
- unhashableObject = HashRaisesRuntimeError()
- def _cleanup():
- global unhashableObject
- unhashableObject = None
- self.addCleanup(_cleanup)
- rebuild.rebuild(rebuild)
- self.assertTrue(unhashableObject.hashCalled)
- class NewStyleTests(unittest.TestCase):
- """
- Tests for rebuilding new-style classes of various sorts.
- """
- def setUp(self):
- self.m = types.ModuleType('whipping')
- sys.modules['whipping'] = self.m
- def tearDown(self):
- del sys.modules['whipping']
- del self.m
- def test_slots(self):
- """
- Try to rebuild a new style class with slots defined.
- """
- classDefinition = (
- "class SlottedClass(object):\n"
- " __slots__ = ['a']\n")
- exec(classDefinition, self.m.__dict__)
- inst = self.m.SlottedClass()
- inst.a = 7
- exec(classDefinition, self.m.__dict__)
- rebuild.updateInstance(inst)
- self.assertEqual(inst.a, 7)
- self.assertIs(type(inst), self.m.SlottedClass)
- def test_typeSubclass(self):
- """
- Try to rebuild a base type subclass.
- """
- classDefinition = (
- "class ListSubclass(list):\n"
- " pass\n")
- exec(classDefinition, self.m.__dict__)
- inst = self.m.ListSubclass()
- inst.append(2)
- exec(classDefinition, self.m.__dict__)
- rebuild.updateInstance(inst)
- self.assertEqual(inst[0], 2)
- self.assertIs(type(inst), self.m.ListSubclass)
- def test_instanceSlots(self):
- """
- Test that when rebuilding an instance with a __slots__ attribute, it
- fails accurately instead of giving a L{rebuild.RebuildError}.
- """
- classDefinition = (
- "class NotSlottedClass(object):\n"
- " pass\n")
- exec(classDefinition, self.m.__dict__)
- inst = self.m.NotSlottedClass()
- inst.__slots__ = ['a']
- classDefinition = (
- "class NotSlottedClass:\n"
- " pass\n")
- exec(classDefinition, self.m.__dict__)
- # Moving from new-style class to old-style should fail.
- self.assertRaises(TypeError, rebuild.updateInstance, inst)
|