[Zope3-checkins] CVS: Zope3/lib/python/Persistence/tests - TestModule.py:1.1 testpatch.py:1.1 testModule.py:1.29

Jeremy Hylton jeremy@zope.com
Fri, 22 Nov 2002 00:33:58 -0500


Update of /cvs-repository/Zope3/lib/python/Persistence/tests
In directory cvs.zope.org:/tmp/cvs-serv11127/Persistence/tests

Modified Files:
	testModule.py 
Added Files:
	TestModule.py testpatch.py 
Log Message:
Get rid of the persistent class dead chicken.

This change adds yet another layer of complexity to the persistent
module support.  The patch module uses a pickler to copy the entire
persistent module, updating classes and functions along the way.

To update persistent classes in place, we need to use a special
__newstate__() method instead of __setstate__(), because a class's
__getstate__() only returns the persistent object and update-in-place
needs to handle all attributes (including removal of attributes that
no longer exist).

The update-in-place machinery tries to do something sensible in the
presence of aliasing, but it is probably half baked.  Need to think
more about whether sensible semantics are possible, and implement them
if they are.

To handle updates to methods, we need to add PersistentDescriptor and
PersistentMethod objects that make PersistentFunctions behave like
functions when found in a class dict.


=== Added File Zope3/lib/python/Persistence/tests/TestModule.py ===
"""A module used to test persistent module patching."""

def aFunc():
    def nestedFunc():
        return aFunc
    return 1

class Foo(object):
    def meth(self):
        return 0

    class Nested(object):
        def bar(self):
            return 1

class Bar:
    def bar(self, x):
        return 2 * x

    static = staticmethod(aFunc)
    alias = aFunc

    classbar = classmethod(bar)

def anotherFunc():
    class NotFound:
        pass


=== Added File Zope3/lib/python/Persistence/tests/testpatch.py ===
from Persistence.patch import NameFinder, convert
from Persistence.tests import TestModule

import unittest

class TestNameFinder(unittest.TestCase):

    def testNameFinder(self):
        nf = NameFinder(TestModule)
        names = nf.names()
        for name in ("Foo", "Bar", "aFunc", "anotherFunc",
                     "Foo.meth", "Foo.Nested", "Bar.bar",
                     "Foo.Nested.bar"):
            self.assert_(name in names)
        for name in ("aFunc.nestedFunc", "anotherFunc.NotFound"):
            self.assert_(name not in names)

class TestPatch(unittest.TestCase):

    def testPatch(self):
        moddict = TestModule.__dict__
        convert(TestModule, {})
        newdict = TestModule.__dict__
        
        L1 = moddict.keys()
        L2 = newdict.keys()
        L1.sort()
        L2.sort()
        self.assertEqual(L1, L2)

        self.assertEqual(TestModule.__dict__, TestModule.aFunc.func_globals)

def test_suite():
    s = unittest.TestSuite()
    for c in TestNameFinder, TestPatch:
        s.addTest(unittest.makeSuite(c))
    return s


=== Zope3/lib/python/Persistence/tests/testModule.py 1.28 => 1.29 ===
--- Zope3/lib/python/Persistence/tests/testModule.py:1.28	Thu Oct 10 18:29:37 2002
+++ Zope3/lib/python/Persistence/tests/testModule.py	Fri Nov 22 00:33:58 2002
@@ -95,7 +95,7 @@
         self.assertEqual(pmtest.a, 1)
         pmtest.f(4)
 
-    def testUpdate(self):
+    def testUpdateFunction(self):
         mgr = PersistentModuleManager(self.registry)
         mgr.new("pmtest", "def f(x): return x")
         get_transaction().commit()
@@ -108,6 +108,21 @@
         self.assertEqual(pmtest.f(3), 4)
         self.assertEqual(copy(3), 4)
 
+    def testUpdateClass(self):
+        mgr = PersistentModuleManager(self.registry)
+        mgr.new("pmtest", src)
+        get_transaction().commit()
+        import pmtest
+        inst = pmtest.Foo()
+        v0 = inst.x
+        v1 = inst.m()
+        v2 = inst.n()
+        self.assertEqual(v1 - 1, v2)
+        self.assertEqual(v0 + 1, v1)
+        mgr.update(src2)
+        get_transaction().commit()
+        self.assertRaises(AttributeError, getattr, inst, "n")
+
     def testModules(self):
         foomgr = PersistentModuleManager(self.registry)
         foomgr.new("foo", foo_src)
@@ -375,12 +390,22 @@
     return s
 
 src = """\
-from Persistence.Class import PersistentBaseClass
-
-class Foo(PersistentBaseClass):
+class Foo(object):
     def __init__(self):
         self.x = id(self)
     def m(self):
         self.x += 1
+        return self.x
+    def n(self):
+        self.x -= 1
+        return self.x
+"""
+
+src2 = """\
+class Foo(object):
+    def __init__(self):
+        self.x = 0
+    def m(self):
+        self.x += 10
         return self.x
 """