Skip to content

Commit

Permalink
New transaction API for storing data on behalf of objects
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Jim Fulton committed May 21, 2016
1 parent 86a1828 commit a9c8bcf
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -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.

Expand Down
22 changes: 22 additions & 0 deletions transaction/_transaction.py
Expand Up @@ -441,8 +441,29 @@ def _free(self):
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.
Expand Down Expand Up @@ -497,6 +518,7 @@ def setExtendedInfo(self, name, value):
"""
self._extension[name] = value


# TODO: We need a better name for the adapters.


Expand Down
16 changes: 16 additions & 0 deletions transaction/interfaces.py
Expand Up @@ -298,6 +298,22 @@ def getAfterCommitHooks():
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."""

Expand Down
23 changes: 23 additions & 0 deletions transaction/tests/test__transaction.py
Expand Up @@ -1001,6 +1001,29 @@ def test_setExtendedInfo_multiple(self):
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):

Expand Down

0 comments on commit a9c8bcf

Please sign in to comment.