[Zodb-checkins] SVN: ZODB/trunk/src/ZODB/ Collapsed the serializer reader and writer class hierarchies.

Jim Fulton jim at zope.com
Wed Mar 30 15:19:19 EST 2005


Log message for revision 29733:
  Collapsed the serializer reader and writer class hierarchies.
  

Changed:
  U   ZODB/trunk/src/ZODB/Connection.py
  U   ZODB/trunk/src/ZODB/serialize.py
  U   ZODB/trunk/src/ZODB/tests/testSerialize.py
  U   ZODB/trunk/src/ZODB/tests/testUtils.py

-=-
Modified: ZODB/trunk/src/ZODB/Connection.py
===================================================================
--- ZODB/trunk/src/ZODB/Connection.py	2005-03-30 19:32:28 UTC (rev 29732)
+++ ZODB/trunk/src/ZODB/Connection.py	2005-03-30 20:19:18 UTC (rev 29733)
@@ -37,7 +37,7 @@
      import ConflictError, ReadConflictError, InvalidObjectReference, \
             ConnectionStateError
 from ZODB.TmpStore import TmpStore
-from ZODB.serialize import ObjectWriter, ConnectionObjectReader, myhasattr
+from ZODB.serialize import ObjectWriter, ObjectReader, myhasattr
 from ZODB.utils import u64, oid_repr, z64, positive_id, \
         DEPRECATED_ARGUMENT, deprecated36
 
@@ -791,8 +791,7 @@
             self._flush_invalidations()
         if self._synch:
             self._txn_mgr.registerSynch(self)
-        self._reader = ConnectionObjectReader(self, self._cache,
-                                              self._db.classFactory)
+        self._reader = ObjectReader(self, self._cache, self._db.classFactory)
 
         # Multi-database support
         self.connections = {self._db.database_name: self}

Modified: ZODB/trunk/src/ZODB/serialize.py
===================================================================
--- ZODB/trunk/src/ZODB/serialize.py	2005-03-30 19:32:28 UTC (rev 29732)
+++ ZODB/trunk/src/ZODB/serialize.py	2005-03-30 20:19:18 UTC (rev 29733)
@@ -49,7 +49,7 @@
 It's unclear what "usually" means in the last paragraph.  There are two
 useful places to concentrate confusion about exactly which formats exist:
 
-- BaseObjectReader.getClassName() below returns a dotted "module.class"
+- ObjectReader.getClassName() below returns a dotted "module.class"
   string, via actually loading a pickle.  This requires that the
   implementation of application objects be available.
 
@@ -114,7 +114,7 @@
     return getattr(obj, name, _marker) is not _marker
 
 
-class BaseObjectWriter:
+class ObjectWriter:
     """Serializes objects for storage in the database.
 
     The ObjectWriter creates object pickles in the ZODB format.  It
@@ -122,14 +122,18 @@
     object.
     """
 
-    def __init__(self, jar=None):
+    _jar = None
+
+    def __init__(self, obj=None):
         self._file = cStringIO.StringIO()
         self._p = cPickle.Pickler(self._file, 1)
-        self._stack = []
         self._p.persistent_id = self.persistent_id
-        if jar is not None:
+        self._stack = []
+        if obj is not None:
+            self._stack.append(obj)
+            jar = obj._p_jar
             assert myhasattr(jar, "new_oid")
-        self._jar = jar
+            self._jar = jar
 
     def persistent_id(self, obj):
         """Return the persistent id for obj.
@@ -139,7 +143,9 @@
         ...     def new_oid(self):
         ...         return 42
         >>> jar = DummyJar()
-        >>> writer = BaseObjectWriter(jar)
+        >>> class O:
+        ...     _p_jar = jar
+        >>> writer = ObjectWriter(O)
 
         Normally, object references include the oid and a cached
         reference to the class.  Having the class available allows
@@ -304,12 +310,6 @@
         self._file.truncate()
         return self._file.getvalue()
 
-class ObjectWriter(BaseObjectWriter):
-
-    def __init__(self, obj):
-        BaseObjectWriter.__init__(self, obj._p_jar)
-        self._stack.append(obj)
-
     def __iter__(self):
         return NewObjectIterator(self._stack)
 
@@ -331,22 +331,80 @@
         else:
             raise StopIteration
 
-class BaseObjectReader:
+class ObjectReader:
 
-    def _persistent_load(self, oid):
-        # subclasses must define _persistent_load().
-        raise NotImplementedError
+    def __init__(self, conn=None, cache=None, factory=None):
+        self._conn = conn
+        self._cache = cache
+        self._factory = factory
 
     def _get_class(self, module, name):
-        # subclasses must define _get_class()
-        raise NotImplementedError
+        return self._factory(self._conn, module, name)
 
     def _get_unpickler(self, pickle):
         file = cStringIO.StringIO(pickle)
         unpickler = cPickle.Unpickler(file)
         unpickler.persistent_load = self._persistent_load
+        factory = self._factory
+        conn = self._conn
+
+        def find_global(modulename, name):
+            return factory(conn, modulename, name)
+
+        unpickler.find_global = find_global
+
         return unpickler
 
+    def _persistent_load(self, oid):
+        if isinstance(oid, tuple):
+            # Quick instance reference.  We know all we need to know
+            # to create the instance w/o hitting the db, so go for it!
+            oid, klass = oid
+
+            obj = self._cache.get(oid, None)
+            if obj is not None:
+                return obj
+
+            if isinstance(klass, tuple):
+                klass = self._get_class(*klass)
+
+            if issubclass(klass, Broken):
+                # We got a broken class. We might need to make it
+                # PersistentBroken
+                if not issubclass(klass, broken.PersistentBroken):
+                    klass = broken.persistentBroken(klass)
+
+            try:
+                obj = klass.__new__(klass)
+            except TypeError:
+                # Couldn't create the instance.  Maybe there's more
+                # current data in the object's actual record!
+                return self._conn.get(oid)
+
+            # TODO: should be done by connection
+            obj._p_oid = oid
+            obj._p_jar = self._conn
+            # When an object is created, it is put in the UPTODATE
+            # state.  We must explicitly deactivate it to turn it into
+            # a ghost.
+            obj._p_changed = None
+
+            self._cache[oid] = obj
+            return obj
+
+        elif isinstance(oid, list):
+            # see weakref.py
+            [oid] = oid
+            obj = WeakRef.__new__(WeakRef)
+            obj.oid = oid
+            obj.dm = self._conn
+            return obj
+
+        obj = self._cache.get(oid, None)
+        if obj is not None:
+            return obj
+        return self._conn.get(oid)
+
     def _new_object(self, klass, args):
         if not args and not myhasattr(klass, "__getnewargs__"):
             obj = klass.__new__(klass)
@@ -407,97 +465,6 @@
         state = self.getState(pickle)
         obj.__setstate__(state)
 
-
-class ExternalReference(object):
-    pass
-
-class SimpleObjectReader(BaseObjectReader):
-    """Can be used to inspect a single object pickle.
-
-    It returns an ExternalReference() object for other persistent
-    objects.  It can't instantiate the object.
-    """
-
-    ext_ref = ExternalReference()
-
-    def _persistent_load(self, oid):
-        return self.ext_ref
-
-    def _get_class(self, module, name):
-        return None
-
-class ConnectionObjectReader(BaseObjectReader):
-
-    def __init__(self, conn, cache, factory):
-        self._conn = conn
-        self._cache = cache
-        self._factory = factory
-
-    def _get_class(self, module, name):
-        return self._factory(self._conn, module, name)
-
-    def _get_unpickler(self, pickle):
-        unpickler = BaseObjectReader._get_unpickler(self, pickle)
-        factory = self._factory
-        conn = self._conn
-
-        def find_global(modulename, name):
-            return factory(conn, modulename, name)
-
-        unpickler.find_global = find_global
-
-        return unpickler
-
-    def _persistent_load(self, oid):
-        if isinstance(oid, tuple):
-            # Quick instance reference.  We know all we need to know
-            # to create the instance w/o hitting the db, so go for it!
-            oid, klass = oid
-
-            obj = self._cache.get(oid, None)
-            if obj is not None:
-                return obj
-
-            if isinstance(klass, tuple):
-                klass = self._get_class(*klass)
-
-            if issubclass(klass, Broken):
-                # We got a broken class. We might need to make it
-                # PersistentBroken
-                if not issubclass(klass, broken.PersistentBroken):
-                    klass = broken.persistentBroken(klass)
-
-            try:
-                obj = klass.__new__(klass)
-            except TypeError:
-                # Couldn't create the instance.  Maybe there's more
-                # current data in the object's actual record!
-                return self._conn.get(oid)
-
-            # TODO: should be done by connection
-            obj._p_oid = oid
-            obj._p_jar = self._conn
-            # When an object is created, it is put in the UPTODATE
-            # state.  We must explicitly deactivate it to turn it into
-            # a ghost.
-            obj._p_changed = None
-
-            self._cache[oid] = obj
-            return obj
-
-        elif isinstance(oid, list):
-            # see weakref.py
-            [oid] = oid
-            obj = WeakRef.__new__(WeakRef)
-            obj.oid = oid
-            obj.dm = self._conn
-            return obj
-
-        obj = self._cache.get(oid, None)
-        if obj is not None:
-            return obj
-        return self._conn.get(oid)
-
 def referencesf(p, rootl=None):
 
     if rootl is None:

Modified: ZODB/trunk/src/ZODB/tests/testSerialize.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testSerialize.py	2005-03-30 19:32:28 UTC (rev 29732)
+++ ZODB/trunk/src/ZODB/tests/testSerialize.py	2005-03-30 20:19:18 UTC (rev 29733)
@@ -39,6 +39,9 @@
     return sio.getvalue()
 
 
+def test_factory(conn, module_name, name):
+    return globals()[name]
+
 class SerializerTestCase(unittest.TestCase):
 
     # old format:  (module, name), None
@@ -58,7 +61,7 @@
         (ClassWithNewargs, (1,)))
 
     def test_getClassName(self):
-        r = serialize.BaseObjectReader()
+        r = serialize.ObjectReader(factory=test_factory)
         eq = self.assertEqual
         eq(r.getClassName(self.old_style_with_newargs),
            __name__ + ".ClassWithNewargs")
@@ -73,14 +76,14 @@
         # Use a TestObjectReader since we need _get_class() to be
         # implemented; otherwise this is just a BaseObjectReader.
 
-        class TestObjectReader(serialize.BaseObjectReader):
+        class TestObjectReader(serialize.ObjectReader):
             # A production object reader would optimize this, but we
             # don't need to in a test
             def _get_class(self, module, name):
                 __import__(module)
                 return getattr(sys.modules[module], name)
 
-        r = TestObjectReader()
+        r = TestObjectReader(factory=test_factory)
         g = r.getGhost(self.old_style_with_newargs)
         self.assert_(isinstance(g, ClassWithNewargs))
         self.assertEqual(g, 1)

Modified: ZODB/trunk/src/ZODB/tests/testUtils.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testUtils.py	2005-03-30 19:32:28 UTC (rev 29732)
+++ ZODB/trunk/src/ZODB/tests/testUtils.py	2005-03-30 20:19:18 UTC (rev 29733)
@@ -46,11 +46,11 @@
         self.assertEquals(U64("\000\000\000\001\000\000\000\000"), 1L<<32)
 
     def checkPersistentIdHandlesDescriptor(self):
-        from ZODB.serialize import BaseObjectWriter
+        from ZODB.serialize import ObjectWriter
         class P(Persistent):
             pass
 
-        writer = BaseObjectWriter(None)
+        writer = ObjectWriter(None)
         self.assertEqual(writer.persistent_id(P), None)
 
     # It's hard to know where to put this test.  We're checking that the
@@ -59,13 +59,13 @@
     # the pickle (and so also trying to import application module and
     # class objects, which isn't a good idea on a ZEO server when avoidable).
     def checkConflictErrorDoesntImport(self):
-        from ZODB.serialize import BaseObjectWriter
+        from ZODB.serialize import ObjectWriter
         from ZODB.POSException import ConflictError
         from ZODB.tests.MinPO import MinPO
         import cPickle as pickle
 
         obj = MinPO()
-        data = BaseObjectWriter().serialize(obj)
+        data = ObjectWriter().serialize(obj)
 
         # The pickle contains a GLOBAL ('c') opcode resolving to MinPO's
         # module and class.



More information about the Zodb-checkins mailing list