Commit a9c8bcfe authored by Jim Fulton's avatar Jim Fulton

New transaction API for storing data on behalf of objects

For objects such as data managers or their subobjects that
work with multiple transactions, it's convenient to store
transaction-specific data on the transaction itself.  The
transaction knows nothing about the data, but simply holds it
on behalf of the object.

Discussion:
https://groups.google.com/forum/#!topic/python-transaction/oUzj3uIHBgA
parent 86a18280
......@@ -4,6 +4,9 @@ Changes
1.6.0 (TBD)
-----------
- New transaction API for storing data on behalf of objects, such as
data managers.
- Drop references to data managers joined to a transaction when it is
committed or aborted.
......
......@@ -441,8 +441,29 @@ class Transaction(object):
if self._manager:
self._manager.free(self)
if hasattr(self, '_data'):
delattr(self, '_data')
del self._resources[:]
def data(self, ob):
try:
data = self._data
except AttributeError:
raise KeyError(ob)
try:
return data[id(ob)]
except KeyError:
raise KeyError(ob)
def set_data(self, ob, ob_data):
try:
data = self._data
except AttributeError:
data = self._data = {}
data[id(ob)] = ob_data
def abort(self):
""" See ITransaction.
......@@ -497,6 +518,7 @@ class Transaction(object):
"""
self._extension[name] = value
# TODO: We need a better name for the adapters.
......
......@@ -298,6 +298,22 @@ class ITransaction(Interface):
by a top-level transaction commit.
"""
def set_data(self, object, data):
"""Hold data on behalf of an object
For objects such as data managers or their subobjects that
work with multiple transactions, it's convenient to store
transaction-specific data on the transaction itself. The
transaction knows nothing about the data, but simply holds it
on behalf of the object.
"""
def data(self, object):
"""Retrieve data held on behalf of an object.
See set_data.
"""
class ITransactionDeprecated(Interface):
"""Deprecated parts of the transaction API."""
......
......@@ -1001,6 +1001,29 @@ class TransactionTests(unittest.TestCase):
txn.setExtendedInfo('frob', 'quxxxx')
self.assertEqual(txn._extension, {'frob': 'quxxxx', 'baz': 'spam'})
def test_data(self):
txn = self._makeOne()
# Can't get data that wasn't set:
with self.assertRaises(KeyError) as c:
txn.data(self)
self.assertEqual(c.exception.args, (self,))
data = dict(a=1)
txn.set_data(self, data)
self.assertEqual(txn.data(self), data)
# Can't get something we haven't stored.
with self.assertRaises(KeyError) as c:
txn.data(data)
self.assertEqual(c.exception.args, (data,))
# When the transaction ends, data are discarded:
txn.commit()
with self.assertRaises(KeyError) as c:
txn.data(self)
self.assertEqual(c.exception.args, (self,))
class MultiObjectResourceAdapterTests(unittest.TestCase):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment