diff options
Diffstat (limited to 'python/helpers/pydev/test_pydevd_reload/test_pydevd_reload.py')
-rw-r--r-- | python/helpers/pydev/test_pydevd_reload/test_pydevd_reload.py | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/python/helpers/pydev/test_pydevd_reload/test_pydevd_reload.py b/python/helpers/pydev/test_pydevd_reload/test_pydevd_reload.py new file mode 100644 index 000000000000..062ead2b5ff8 --- /dev/null +++ b/python/helpers/pydev/test_pydevd_reload/test_pydevd_reload.py @@ -0,0 +1,516 @@ +import os # @NoMove +import sys # @NoMove +sys.path.insert(0, os.path.realpath(os.path.abspath('..'))) + +import pydevd_reload +import tempfile +import unittest + + +SAMPLE_CODE = """ +class C: + def foo(self): + return 0 + + @classmethod + def bar(cls): + return (0, 0) + + @staticmethod + def stomp(): + return (0, 0, 0) + + def unchanged(self): + return 'unchanged' +""" + + + +class Test(unittest.TestCase): + + + def setUp(self): + unittest.TestCase.setUp(self) + self.tempdir = None + self.save_path = None + self.tempdir = tempfile.mkdtemp() + self.save_path = list(sys.path) + sys.path.append(self.tempdir) + try: + del sys.modules['x'] + except: + pass + + + def tearDown(self): + unittest.TestCase.tearDown(self) + sys.path = self.save_path + try: + del sys.modules['x'] + except: + pass + + def make_mod(self, name="x", repl=None, subst=None, sample=SAMPLE_CODE): + fn = os.path.join(self.tempdir, name + ".py") + f = open(fn, "w") + if repl is not None and subst is not None: + sample = sample.replace(repl, subst) + try: + f.write(sample) + finally: + f.close() + + + def test_pydevd_reload(self): + + self.make_mod() + import x + + C = x.C + COut = C + Cfoo = C.foo + Cbar = C.bar + Cstomp = C.stomp + + def check2(expected): + C = x.C + Cfoo = C.foo + Cbar = C.bar + Cstomp = C.stomp + b = C() + bfoo = b.foo + self.assertEqual(expected, b.foo()) + self.assertEqual(expected, bfoo()) + self.assertEqual(expected, Cfoo(b)) + + def check(expected): + b = COut() + bfoo = b.foo + self.assertEqual(expected, b.foo()) + self.assertEqual(expected, bfoo()) + self.assertEqual(expected, Cfoo(b)) + self.assertEqual((expected, expected), Cbar()) + self.assertEqual((expected, expected, expected), Cstomp()) + check2(expected) + + check(0) + + # modify mod and reload + count = 0 + while count < 1: + count += 1 + self.make_mod(repl="0", subst=str(count)) + pydevd_reload.xreload(x) + check(count) + + + def test_pydevd_reload2(self): + + self.make_mod() + import x + + c = x.C() + cfoo = c.foo + self.assertEqual(0, c.foo()) + self.assertEqual(0, cfoo()) + + self.make_mod(repl="0", subst='1') + pydevd_reload.xreload(x) + self.assertEqual(1, c.foo()) + self.assertEqual(1, cfoo()) + + def test_pydevd_reload3(self): + class F: + def m1(self): + return 1 + class G: + def m1(self): + return 2 + + self.assertEqual(F().m1(), 1) + pydevd_reload.Reload(None)._update(None, None, F, G) + self.assertEqual(F().m1(), 2) + + + def test_pydevd_reload4(self): + class F: + pass + F.m1 = lambda a:None + class G: + pass + G.m1 = lambda a:10 + + self.assertEqual(F().m1(), None) + pydevd_reload.Reload(None)._update(None, None, F, G) + self.assertEqual(F().m1(), 10) + + + + def test_if_code_obj_equals(self): + class F: + def m1(self): + return 1 + class G: + def m1(self): + return 1 + class H: + def m1(self): + return 2 + + if hasattr(F.m1, 'func_code'): + self.assertTrue(pydevd_reload.code_objects_equal(F.m1.func_code, G.m1.func_code)) + self.assertFalse(pydevd_reload.code_objects_equal(F.m1.func_code, H.m1.func_code)) + else: + self.assertTrue(pydevd_reload.code_objects_equal(F.m1.__code__, G.m1.__code__)) + self.assertFalse(pydevd_reload.code_objects_equal(F.m1.__code__, H.m1.__code__)) + + + + def test_metaclass(self): + + class Meta(type): + def __init__(cls, name, bases, attrs): + super(Meta, cls).__init__(name, bases, attrs) + + class F: + __metaclass__ = Meta + + def m1(self): + return 1 + + + class G: + __metaclass__ = Meta + + def m1(self): + return 2 + + self.assertEqual(F().m1(), 1) + pydevd_reload.Reload(None)._update(None, None, F, G) + self.assertEqual(F().m1(), 2) + + + + def test_change_hierarchy(self): + + class F(object): + + def m1(self): + return 1 + + + class B(object): + def super_call(self): + return 2 + + class G(B): + + def m1(self): + return self.super_call() + + self.assertEqual(F().m1(), 1) + old = pydevd_reload.notify_error + self._called = False + def on_error(*args): + self._called = True + try: + pydevd_reload.notify_error = on_error + pydevd_reload.Reload(None)._update(None, None, F, G) + self.assertTrue(self._called) + finally: + pydevd_reload.notify_error = old + + + def test_change_hierarchy_old_style(self): + + class F: + + def m1(self): + return 1 + + + class B: + def super_call(self): + return 2 + + class G(B): + + def m1(self): + return self.super_call() + + + self.assertEqual(F().m1(), 1) + old = pydevd_reload.notify_error + self._called = False + def on_error(*args): + self._called = True + try: + pydevd_reload.notify_error = on_error + pydevd_reload.Reload(None)._update(None, None, F, G) + self.assertTrue(self._called) + finally: + pydevd_reload.notify_error = old + + + def test_create_class(self): + SAMPLE_CODE1 = """ +class C: + def foo(self): + return 0 +""" + # Creating a new class and using it from old class + SAMPLE_CODE2 = """ +class B: + pass + +class C: + def foo(self): + return B +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.C().foo + self.assertEqual(foo(), 0) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo().__name__, 'B') + + def test_create_class2(self): + SAMPLE_CODE1 = """ +class C(object): + def foo(self): + return 0 +""" + # Creating a new class and using it from old class + SAMPLE_CODE2 = """ +class B(object): + pass + +class C(object): + def foo(self): + return B +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.C().foo + self.assertEqual(foo(), 0) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo().__name__, 'B') + + def test_parent_function(self): + SAMPLE_CODE1 = """ +class B(object): + def foo(self): + return 0 + +class C(B): + def call(self): + return self.foo() +""" + # Creating a new class and using it from old class + SAMPLE_CODE2 = """ +class B(object): + def foo(self): + return 0 + def bar(self): + return 'bar' + +class C(B): + def call(self): + return self.bar() +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + call = x.C().call + self.assertEqual(call(), 0) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(call(), 'bar') + + + def test_update_constant(self): + SAMPLE_CODE1 = """ +CONSTANT = 1 + +class B(object): + def foo(self): + return CONSTANT +""" + SAMPLE_CODE2 = """ +CONSTANT = 2 + +class B(object): + def foo(self): + return CONSTANT +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.B().foo + self.assertEqual(foo(), 1) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo(), 1) #Just making it explicit we don't reload constants. + + + def test_update_constant_with_custom_code(self): + SAMPLE_CODE1 = """ +CONSTANT = 1 + +class B(object): + def foo(self): + return CONSTANT +""" + SAMPLE_CODE2 = """ +CONSTANT = 2 + +def __xreload_old_new__(namespace, name, old, new): + if name == 'CONSTANT': + namespace[name] = new + +class B(object): + def foo(self): + return CONSTANT +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.B().foo + self.assertEqual(foo(), 1) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo(), 2) #Actually updated it now! + + + def test_reload_custom_code_after_changes(self): + SAMPLE_CODE1 = """ +CONSTANT = 1 + +class B(object): + def foo(self): + return CONSTANT +""" + SAMPLE_CODE2 = """ +CONSTANT = 1 + +def __xreload_after_reload_update__(namespace): + namespace['CONSTANT'] = 2 + +class B(object): + def foo(self): + return CONSTANT +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.B().foo + self.assertEqual(foo(), 1) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo(), 2) #Actually updated it now! + + + def test_reload_custom_code_after_changes_in_class(self): + SAMPLE_CODE1 = """ + +class B(object): + CONSTANT = 1 + + def foo(self): + return self.CONSTANT +""" + SAMPLE_CODE2 = """ + + +class B(object): + CONSTANT = 1 + + @classmethod + def __xreload_after_reload_update__(cls): + cls.CONSTANT = 2 + + def foo(self): + return self.CONSTANT +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.B().foo + self.assertEqual(foo(), 1) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo(), 2) #Actually updated it now! + + + def test_update_constant_with_custom_code(self): + SAMPLE_CODE1 = """ + +class B(object): + CONSTANT = 1 + + def foo(self): + return self.CONSTANT +""" + SAMPLE_CODE2 = """ + + +class B(object): + + CONSTANT = 2 + + def __xreload_old_new__(cls, name, old, new): + if name == 'CONSTANT': + cls.CONSTANT = new + __xreload_old_new__ = classmethod(__xreload_old_new__) + + def foo(self): + return self.CONSTANT +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + foo = x.B().foo + self.assertEqual(foo(), 1) + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + self.assertEqual(foo(), 2) #Actually updated it now! + + + def test_update_with_slots(self): + SAMPLE_CODE1 = """ +class B(object): + + __slots__ = ['bar'] + +""" + SAMPLE_CODE2 = """ +class B(object): + + __slots__ = ['bar', 'foo'] + + def m1(self): + self.bar = 10 + return 1 + +""" + + self.make_mod(sample=SAMPLE_CODE1) + import x + B = x.B + self.make_mod(sample=SAMPLE_CODE2) + pydevd_reload.xreload(x) + b = B() + self.assertEqual(1, b.m1()) + self.assertEqual(10, b.bar) + self.assertRaises(Exception, setattr, b, 'foo', 20) #__slots__ can't be updated + + + + +if __name__ == "__main__": +# import sys;sys.argv = ['', 'Test.test_reload_custom_code_after_changes_in_class'] + unittest.main() |