[Checkins] SVN: zc.demostorage2/branches/dev/ Consolidated modules and got tests to pass.

Jim Fulton jim at zope.com
Mon Jan 21 15:47:56 EST 2008


Log message for revision 83076:
  Consolidated modules and got tests to pass.
  
  Need tests of loadBefore and configuration.
  

Changed:
  U   zc.demostorage2/branches/dev/buildout.cfg
  U   zc.demostorage2/branches/dev/setup.py
  U   zc.demostorage2/branches/dev/src/zc/demostorage2/README.txt
  U   zc.demostorage2/branches/dev/src/zc/demostorage2/__init__.py
  U   zc.demostorage2/branches/dev/src/zc/demostorage2/component.xml
  D   zc.demostorage2/branches/dev/src/zc/demostorage2/config.py
  D   zc.demostorage2/branches/dev/src/zc/demostorage2/storage.py
  U   zc.demostorage2/branches/dev/src/zc/demostorage2/synchronized.txt
  U   zc.demostorage2/branches/dev/src/zc/demostorage2/tests.py

-=-
Modified: zc.demostorage2/branches/dev/buildout.cfg
===================================================================
--- zc.demostorage2/branches/dev/buildout.cfg	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/buildout.cfg	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1,7 +1,12 @@
 [buildout]
 develop = .
-parts = test
+parts = test py
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = 
+eggs = zc.demostorage2
+
+[py]
+recipe = zc.recipe.egg
+eggs = ${test:eggs}
+interpreter = py

Modified: zc.demostorage2/branches/dev/setup.py
===================================================================
--- zc.demostorage2/branches/dev/setup.py	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/setup.py	2008-01-21 20:47:56 UTC (rev 83076)
@@ -4,7 +4,7 @@
 """
 
 setup(
-    name = '',
+    name = 'zc.demostorage2',
     version = '0.1',
     author = 'Jim Fulton',
     author_email = 'jim at zope.com',
@@ -14,7 +14,7 @@
     packages = find_packages('src'),
     namespace_packages = ['zc'],
     package_dir = {'': 'src'},
-    install_requires = 'setuptools',
+    install_requires = ['ZODB3', 'setuptools'],
     zip_safe = False,
     entry_points=entry_points,
     )

Modified: zc.demostorage2/branches/dev/src/zc/demostorage2/README.txt
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/README.txt	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/README.txt	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1,7 +1,7 @@
 Second-generation demo storage
 ==============================
 
-The demostorage2 module provides a storage implementation that
+The zc.demostorage2 module provides a storage implementation that
 wraps two storages, a base storage and a storage to hold changes.
 The base storage is never written to.  All new records are written to
 the changes storage.  Both storages are expected to:
@@ -21,33 +21,30 @@
 To see how this works, we'll start by creating a base storage and
 puting an object (in addition to the root object) in it:
 
-    >>> import os, tempfile
-    >>> tempdir = tempfile.mkdtemp()
-    >>> base_path = os.path.join(tempdir, 'base.fs')
-
     >>> from ZODB.FileStorage import FileStorage
-    >>> base = FileStorage(base_path)
+    >>> base = FileStorage('base.fs')
     >>> from ZODB.DB import DB
     >>> db = DB(base)
-    >>> from ZODB.PersistentMapping import PersistentMapping
+    >>> from persistent.mapping import PersistentMapping
     >>> conn = db.open()
     >>> conn.root()['1'] = PersistentMapping({'a': 1, 'b':2})
-    >>> get_transaction().commit()
+    >>> import transaction
+    >>> transaction.commit()
     >>> db.close()
-    >>> original_size = os.path.getsize(base_path)
+    >>> import os
+    >>> original_size = os.path.getsize('base.fs')
 
 Now, lets reopen the base storage in read-only mode:
 
-    >>> base = FileStorage(base_path, read_only=True)
+    >>> base = FileStorage('base.fs', read_only=True)
 
 And open a new storage to store changes:
 
-    >>> changes_path = os.path.join(tempdir, 'changes.fs')
-    >>> changes = FileStorage(changes_path)
+    >>> changes = FileStorage('changes.fs')
 
 and combine the 2 in a demofilestorage:
 
-    >>> from demostorage2 import DemoStorage2
+    >>> from zc.demostorage2 import DemoStorage2
     >>> storage = DemoStorage2(base, changes)
 
 If there are no transactions, the storage reports the lastTransaction
@@ -66,14 +63,14 @@
     [('a', 1), ('b', 2)]
 
     >>> conn.root()['2'] = PersistentMapping({'a': 3, 'b':4})
-    >>> get_transaction().commit()
+    >>> transaction.commit()
 
     >>> conn.root()['2']['c'] = 5
-    >>> get_transaction().commit()
+    >>> transaction.commit()
 
 Here we can see that we haven't modified the base storage:
 
-    >>> original_size == os.path.getsize(base_path)
+    >>> original_size == os.path.getsize('base.fs')
     True
 
 But we have modified the changes database:
@@ -89,7 +86,6 @@
     >>> storage.lastTransaction() == changes.lastTransaction()
     True
 
-
 Let's walk over some of the methods so ewe can see how we delegate to
 the new oderlying storages:
 
@@ -101,11 +97,11 @@
     >>> storage.load(p64(1), '') == base.load(p64(1), '')
     True
 
-    >>> serial = base.getSerial(p64(0)) 
+    >>> serial = base.load(p64(0), '')[1] 
     >>> storage.loadSerial(p64(0), serial) == base.loadSerial(p64(0), serial)
     True
 
-    >>> serial = changes.getSerial(p64(0)) 
+    >>> serial = changes.load(p64(0), '')[1] 
     >>> storage.loadSerial(p64(0), serial) == changes.loadSerial(p64(0),
     ...                                                          serial)
     True
@@ -115,27 +111,25 @@
     >>> u64(conn.root()['2']._p_oid)
     9223372036854775809L
 
-Versions aren't supported:
+Let's look at some other methods:
 
-    >>> storage.supportsVersions()
-    False
-    >>> storage.versions()
-    ()
-    >>> storage.versionEmpty(p64(0))
+    >>> storage.getName()
+    'DemoStorage2(base.fs, changes.fs)'
+
+    >>> storage.sortKey() == changes.sortKey()
     True
-    >>> storage.versionEmpty(p64(60))
+
+    >>> storage.getSize() == changes.getSize()
     True
-    >>> storage.modifiedInVersion(p64(0))
-    ''
-    >>> storage.modifiedInVersion(p64(60))
-    ''
     
-Many methods are simply copied from the base storage:
+    >>> len(storage) == len(changes)
+    True
 
+    
+Undo methods are simply copied from the changes storage:
+
     >>> [getattr(storage, name) == getattr(changes, name)
-    ...  for name in ('getName', 'sortKey', 'getSize', '__len__', 
-    ...               'supportsUndo', 'undo', 'undoLog', 'undoInfo',
-    ...               'supportsTransactionalUndo')
+    ...  for name in ('supportsUndo', 'undo', 'undoLog', 'undoInfo')
     ...  ]
-    [True, True, True, True, True, True, True, True, True]
+    [True, True, True, True]
 

Modified: zc.demostorage2/branches/dev/src/zc/demostorage2/__init__.py
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/__init__.py	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/__init__.py	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1 +1,175 @@
-from storage import DemoStorage2
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Demo storage that stores changes in a non-memory storage
+"""
+
+import threading
+
+import ZODB.POSException
+from ZODB.utils import p64, u64, z64
+
+from zc.demostorage2.synchronized import synchronized
+
+class DemoStorage2:
+
+    def __init__(self, base, changes):
+        self.changes = changes
+        self.base = base
+
+        supportsUndo = getattr(changes, 'supportsUndo', None)
+        if supportsUndo is not None and supportsUndo():
+            self.supportsUndo = changes.supportsUndo
+            self.undo = changes.undo
+            self.undoLog = changes.undoLog
+            self.undoInfo = changes.undoInfo
+    
+        self._oid = max(u64(changes.new_oid()), 1l << 63)
+        self._lock = threading.RLock()
+        self._commit_lock = threading.Lock()
+
+        self._transaction = None
+
+    def close(self):
+        self.base.close()
+        self.changes.close()
+
+    def getName(self):
+        return "DemoStorage2(%s, %s)" % (
+            self.base.getName(), self.changes.getName())
+
+    def __repr__(self):
+        return "<%s: %s>" % (self.__class__.__name__, self.getName())
+
+    def getSize(self):
+        return self.changes.getSize()
+
+    def history(self, *args, **kw):
+        return self.changes.history(*args, **kw)
+
+    def isReadOnly(self):
+        return self.changes.isReadOnly()
+
+    @synchronized
+    def lastTransaction(self):
+        t = self.changes.lastTransaction()
+        if t == z64:
+            t = self.base.lastTransaction()
+        return t
+
+    def __len__(self):
+        return len(self.changes)
+
+    @synchronized
+    def load(self, oid, version=''):
+        try:
+            return self.changes.load(oid, version)
+        except ZODB.POSException.POSKeyError:
+            return self.base.load(oid, version)
+
+    @synchronized
+    def loadBefore(self, oid, tid):
+        try:
+            result = self.changes.loadBefore(oid, tid)
+        except ZODB.POSException.POSKeyError:
+            return self.base.loadBefore(oid, tid)
+
+    @synchronized
+    def loadSerial(self, oid, serial):
+        try:
+            return self.changes.loadSerial(oid, serial)
+        except ZODB.POSException.POSKeyError:
+            return self.base.loadSerial(oid, serial)
+
+    @synchronized
+    def new_oid(self):
+        self._oid += 1
+        return p64(self._oid)
+
+    def pack(self, pack_time, referencesf):
+        pass
+
+    def registerDB(self, db):
+        self.base.registerDB(db)
+        self.changes.registerDB(db)
+
+    def sortKey(self):
+        return self.changes.sortKey()
+
+    @synchronized
+    def store(self, oid, serial, data, version, transaction):
+        assert version==''
+        if transaction is not self._transaction:
+            raise ZODB.POSException.StorageTransactionError(self, transaction)
+
+        # See if we already have changes for this oid
+        try:
+            old = self.changes.load(oid, '')[1]
+        except ZODB.POSException.POSKeyError:
+            try:
+                old = self.base.load(oid, '')[1]
+            except ZODB.POSException.POSKeyError:
+                old = serial
+                
+        if old != serial:
+            raise ZODB.POSException.ConflictError(
+                oid=oid, serials=(oserial, serial))
+
+        return self.changes.store(oid, serial, data, '', transaction)
+
+
+    @synchronized
+    def tpc_abort(self, transaction):
+        if self._transaction is not transaction:
+            return
+        self._transaction = None
+        try:
+            self.changes.tpc_abort(transaction)
+        finally:
+            self._commit_lock.release()
+
+    def tpc_begin(self, transaction, tid=None, status=' '):
+        if self._transaction is transaction:
+            return
+        self._commit_lock.acquire()
+        self._begin(transaction, tid, status)
+
+    @synchronized
+    def _begin(self, transaction, tid, status):
+        self._transaction = transaction
+        self.changes.tpc_begin(transaction, tid, status)
+
+    @synchronized
+    def tpc_finish(self, transaction, func = lambda: None):
+        if self._transaction is not transaction:
+            return
+        self._transaction = None
+        self.changes.tpc_finish(transaction)
+        self._commit_lock.release()
+
+    @synchronized
+    def tpc_vote(self, transaction):
+        if self._transaction is not transaction:
+            return
+        return self.changes.tpc_vote(transaction)
+
+class ZConfig:
+
+    def __init__(self, config):
+        self.config = config
+        self.name = config.getSectionName()
+
+    def open(self):
+        base = self.config.base.open()
+        changes = self.config.changes.open()
+        return DemoStorage2(base, changes)

Modified: zc.demostorage2/branches/dev/src/zc/demostorage2/component.xml
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/component.xml	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/component.xml	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1,9 +1,13 @@
-<component prefix="demostorage2.config">
-  <sectiontype name="demostorage2" datatype=".DemoStorage2"
-               implements="ZODB.storage">
-    <section type="ZODB.storage" name="base" attribute="base"/>
-    <section type="ZODB.storage" name="changes" attribute="changes"/>
-  </sectiontype>
+<component>
+  <sectiontype
+     name="demostorage2"
+     datatype="zc.demostorage2.ZConfig"
+     implements="ZODB.storage"
+     >
 
+    <section type="ZODB.storage" name="base" attribute="base" required="yes" />
+    <section type="ZODB.storage" name="changes" attribute="changes"
+             required="yes" />
 
+  </sectiontype>
 </component>

Deleted: zc.demostorage2/branches/dev/src/zc/demostorage2/config.py
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/config.py	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/config.py	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1,10 +0,0 @@
-
-import demostorage2
-from ZODB.config import BaseConfig
-
-class DemoStorage2(BaseConfig):
-
-    def open(self):
-        base = self.config.base.open()
-        changes = self.config.changes.open()
-        return demostorage2.DemoStorage2(base, changes)

Deleted: zc.demostorage2/branches/dev/src/zc/demostorage2/storage.py
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/storage.py	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/storage.py	2008-01-21 20:47:56 UTC (rev 83076)
@@ -1,159 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Demo storage that stores changes in a file storage
-
-$Id$
-"""
-
-import threading
-
-import ZODB.POSException
-from ZODB.utils import p64, u64, z64
-
-from demostorage2.synchronized import synchronized
-
-class DemoStorage2:
-
-    def __init__(self, base, changes):
-        self.changes = changes
-        self.base = base
-
-        self.getName = changes.getName
-        self.sortKey = changes.sortKey
-        self.getSize = changes.getSize
-        self.__len__ = changes.__len__
-        self.supportsUndo = changes.supportsUndo
-        self.supportsTransactionalUndo = changes.supportsTransactionalUndo
-        self.undo = changes.undo
-        self.undoLog = changes.undoLog
-        self.undoInfo = changes.undoInfo
-    
-        self._oid = max(u64(changes.new_oid()), 1l << 63)
-        self._lock = threading.RLock()
-        self._commit_lock = threading.Lock()
-
-        self._transaction = None
-
-    def registerDB(self, db, limit):
-        self.base.registerDB(db, limit)
-        self.changes.registerDB(db, limit)
-
-    def close(self):
-        self.base.close()
-        self.changes.close()
-
-    def load(self, oid, version):
-        try:
-            return self.changes.load(oid, version)
-        except ZODB.POSException.POSKeyError:
-            return self.base.load(oid, version)
-    load = synchronized(load)
-
-    def getSerial(self, oid):
-        return self.load(oid, '')[1]
-
-    def loadSerial(self, oid, serial):
-        try:
-            return self.changes.loadSerial(oid, serial)
-        except ZODB.POSException.POSKeyError:
-            return self.base.loadSerial(oid, serial)
-    loadSerial = synchronized(loadSerial)
-
-    def new_oid(self):
-        self._oid += 1
-        return p64(self._oid)
-    new_oid = synchronized(new_oid)
-
-    def tpc_begin(self, transaction, tid=None, status=' '):
-        if self._transaction is transaction:
-            return
-        self._commit_lock.acquire()
-        self._begin(transaction, tid, status)
-
-    def _begin(self, transaction, tid, status):
-        self._transaction = transaction
-        self.changes.tpc_begin(transaction, tid, status)
-    _begin = synchronized(_begin)
-
-    def tpc_abort(self, transaction):
-        if self._transaction is not transaction:
-            return
-        self._transaction = None
-        try:
-            self.changes.tpc_abort(transaction)
-        finally:
-            self._commit_lock.release()
-    tpc_abort = synchronized(tpc_abort)
-
-    def store(self, oid, serial, data, version, transaction):
-        if transaction is not self._transaction:
-            raise ZODB.POSException.StorageTransactionError(self, transaction)
-
-        if version:
-            raise ValueError("Invalid version", version)
-
-        # See if we already have changes for this oid
-        try:
-            old = self.changes.getSerial(oid)
-        except ZODB.POSException.POSKeyError:
-            try:
-                old = self.base.getSerial(oid)
-            except ZODB.POSException.POSKeyError:
-                old = serial
-                
-        if old != serial:
-            raise ZODB.POSException.ConflictError(
-                oid=oid, serials=(oserial, serial))
-
-        return self.changes.store(oid, serial, data, '', transaction)
-    store = synchronized(store)
-
-    def supportsVersions(self):
-        return False
-
-    def tpc_vote(self, transaction):
-        if self._transaction is not transaction:
-            return
-        return self.changes.tpc_vote(transaction)
-    tpc_vote = synchronized(tpc_vote)
-
-    def tpc_finish(self, transaction, func = lambda: None):
-        if self._transaction is not transaction:
-            return
-        self._transaction = None
-        self.changes.tpc_finish(transaction)
-        self._commit_lock.release()
-    tpc_finish = synchronized(tpc_finish)
-
-    def history(self, *args, **kw):
-        return self.changes.history(*args, **kw)
-
-    def lastTransaction(self):
-        t = self.changes.lastTransaction()
-        if t == z64:
-            t = self.base.lastTransaction()
-        return t
-    lastTransaction = synchronized(lastTransaction)
-
-    def isReadOnly(self):
-        return False
-
-    def versionEmpty(*args, **kw):
-        return True
-
-    def modifiedInVersion(*args, **kw):
-        return ''
-
-    def versions(*args, **kw):
-        return ()

Modified: zc.demostorage2/branches/dev/src/zc/demostorage2/synchronized.txt
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/synchronized.txt	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/synchronized.txt	2008-01-21 20:47:56 UTC (rev 83076)
@@ -31,33 +31,32 @@
 fairly burdonsome.  The synchonized module provides a simple
 decorator/descriptor that automates this:
 
-
-    >>> from demostorage2.synchronized import synchronized
+    >>> from zc.demostorage2.synchronized import synchronized
     >>> class Counter:
     ...     def __init__(self):
     ...         self._lock = threading.RLock()
     ...         self.value = 0
     ...
+    ...     @synchronized
     ...     def inc(self):
     ...         # looking for trouble
     ...         old = self.value
     ...         time.sleep(0.0001)
     ...         self.value = old + 1
-    ...     inc = synchronized(inc)
     ...
+    ...     @synchronized
     ...     def dec(self):
     ...         # looking for trouble
     ...         old = self.value
     ...         time.sleep(0.0001)
     ...         self.value = old - 1
-    ...     dec = synchronized('_lock')(dec)
     ...
+    ...     @synchronized
     ...     def getvalue(self):
     ...         return self.value
-    ...     getvalue = synchronized(getvalue)
 
-The decorator can be passed a lock name. If no name is passed, then
-'_lock' is assumed.
+The class using te decorator must have a _lock attribute, which is
+typically a threading.RLock.
 
 With something like this in place, we can safely update instances of
 our class from multiple threads:

Modified: zc.demostorage2/branches/dev/src/zc/demostorage2/tests.py
===================================================================
--- zc.demostorage2/branches/dev/src/zc/demostorage2/tests.py	2008-01-21 19:56:31 UTC (rev 83075)
+++ zc.demostorage2/branches/dev/src/zc/demostorage2/tests.py	2008-01-21 20:47:56 UTC (rev 83076)
@@ -11,23 +11,24 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-import unittest
-import shutil
-from ZODB.Transaction import get_transaction
+import time, unittest
+
 from zope.testing import doctest
+import zope.testing.setupstack
 
-def cleanupReadme(test):
-    get_transaction().abort()
-    test.globs['db'].close()
-    shutil.rmtree(test.globs['tempdir'])
+import transaction
 
-def testSomeDlegation():
+def setUp(test):
+    zope.testing.setupstack.setUpDirectory(test)
+    zope.testing.setupstack.register(test, transaction.abort)
+
+def testSomeDelegation():
     r"""
     >>> class S:
     ...     def __init__(self, name):
     ...         self.name = name
-    ...     def registerDB(self, db, limit):
-    ...         print self.name, db, limit
+    ...     def registerDB(self, db):
+    ...         print self.name, db
     ...     def close(self):
     ...         print self.name, 'closed'
     ...     getName = sortKey = getSize = __len__ = None
@@ -40,12 +41,12 @@
     ...     def tpc_abort(self, t):
     ...         pass
 
-    >>> from demostorage2 import DemoStorage2
+    >>> from zc.demostorage2 import DemoStorage2
     >>> storage = DemoStorage2(S(1), S(2))
 
-    >>> storage.registerDB(1, 2)
-    1 1 2
-    2 1 2
+    >>> storage.registerDB(1)
+    1 1
+    2 1
 
     >>> storage.close()
     1 closed
@@ -60,8 +61,13 @@
 def test_suite():
     return unittest.TestSuite((
         doctest.DocFileSuite('synchronized.txt'),
-        doctest.DocTestSuite(),
-        doctest.DocFileSuite('README.txt', tearDown=cleanupReadme),
+        doctest.DocTestSuite(
+            setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
+            ),
+        doctest.DocFileSuite(
+            'README.txt',
+            setUp=setUp, tearDown=zope.testing.setupstack.tearDown,
+            ),
         ))
 
 if __name__ == '__main__':



More information about the Checkins mailing list