Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed: ZODB.Connection.TransactionMetaData didn't custom data #132

Merged
merged 3 commits into from
Nov 18, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
Change History
================

- Fixed: ``ZODB.Connection.TransactionMetaData`` didn't custom data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing some words?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup

storage that some storages rely on.

5.1.0 (2016-11-17)
==================

Expand Down
18 changes: 3 additions & 15 deletions src/ZODB/BaseStorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,13 @@

import ZODB.interfaces
from . import POSException, utils
from .Connection import TransactionMetaData
from .utils import z64, oid_repr, byte_ord, byte_chr, load_current
from .UndoLogCompatible import UndoLogCompatible
from ._compat import dumps, _protocol, py2_hasattr

log = logging.getLogger("ZODB.BaseStorage")



class BaseStorage(UndoLogCompatible):
"""Base class that supports storage implementations.

Expand Down Expand Up @@ -359,25 +358,14 @@ def checkCurrentSerialInTransaction(self, oid, serial, transaction):
BaseStorage.checkCurrentSerialInTransaction = checkCurrentSerialInTransaction

@zope.interface.implementer(ZODB.interfaces.IStorageTransactionInformation)
class TransactionRecord(object):
class TransactionRecord(TransactionMetaData):
"""Abstract base class for iterator protocol"""


def __init__(self, tid, status, user, description, extension):
self.tid = tid
self.status = status
self.user = user
self.description = description
self.extension = extension

# XXX This is a workaround to make the TransactionRecord compatible with a
# transaction object because it is passed to tpc_begin().
def _ext_set(self, value):
self.extension = value
def _ext_get(self):
return self.extension
_extension = property(fset=_ext_set, fget=_ext_get)

TransactionMetaData.__init__(self, user, description, extension)

@zope.interface.implementer(ZODB.interfaces.IStorageRecordInformation)
class DataRecord(object):
Expand Down
19 changes: 19 additions & 0 deletions src/ZODB/Connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1321,3 +1321,22 @@ def _extension(self):
@_extension.setter
def _extension(self, v):
self.extension = v

def data(self, ob):
try:
data = self._data
except AttributeError:
raise KeyError(ob)

try:
return data[id(ob)]
except KeyError:
raise KeyError(ob)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this simpler and equivalent (fewer lines of code to cover)?

try:
   return self._data[id(ob)]
except (AttributeError, KeyError):
   raise KeyError(ob)

Not that it's a big deal. If you prefer the more explicit version that's fine by me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. This code was copied verbatim from transaction.


def set_data(self, ob, ob_data):
try:
data = self._data
except AttributeError:
data = self._data = {}

data[id(ob)] = ob_data
22 changes: 22 additions & 0 deletions src/ZODB/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,28 @@ class IStorageTransactionMetaData(Interface):
extension = Attribute(
"A dictionary carrying a transaction's extended_info data")


def set_data(ob, data):
"""Hold data on behalf of an object

For objects such as storages 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.

The object passed should be the object that needs the data, as
opposed to simple object like a string. (Internally, the id of
the object is used as the key.)
"""

def data(ob):
"""Retrieve data held on behalf of an object.

See set_data.
"""


class IStorage(Interface):
"""A storage is responsible for storing and retrieving data of objects.

Expand Down
17 changes: 17 additions & 0 deletions src/ZODB/tests/test_TransactionMetaData.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ def tpc_begin(self, transaction):
self.assertEqual(t.description, b'description\xc2\x80')
self.assertEqual(t.extension, dict(foo='FOO'))

def test_data(self):
t = TransactionMetaData()

# Can't get data that wasn't set:
with self.assertRaises(KeyError) as c:
t.data(self)
self.assertEqual(c.exception.args, (self,))

data = dict(a=1)
t.set_data(self, data)
self.assertEqual(t.data(self), data)

# Can't get something we haven't stored.
with self.assertRaises(KeyError) as c:
t.data(data)
self.assertEqual(c.exception.args, (data,))

def test_suite():
return unittest.makeSuite(TransactionMetaDataTests)

Expand Down