[Zodb-checkins] SVN: ZODB/trunk/src/ - Databases have a new method, transaction, that can be used with the
Jim Fulton
jim at zope.com
Mon Apr 27 18:07:57 EDT 2009
Log message for revision 99543:
- Databases have a new method, transaction, that can be used with the
Python (2.5 and later) with statement::
db = ZODB.DB(...)
with db.transaction() as conn:
# ... do stuff with conn
This uses a private transaction manager for the connection.
If control exists the block without an error, the transaction is
committed, otherwise, it is aborted.
- Connections now have a public ``opened`` attribute that is true when
the connection is open, and false otherwise. When true, it is the
seconds since the epoch (time.time()) when the connection was
opened. This is a renaming of the previous ``_opened`` private
variable.
Changed:
U ZODB/trunk/src/CHANGES.txt
U ZODB/trunk/src/ZODB/Connection.py
U ZODB/trunk/src/ZODB/DB.py
U ZODB/trunk/src/ZODB/tests/testDB.py
-=-
Modified: ZODB/trunk/src/CHANGES.txt
===================================================================
--- ZODB/trunk/src/CHANGES.txt 2009-04-27 21:35:05 UTC (rev 99542)
+++ ZODB/trunk/src/CHANGES.txt 2009-04-27 22:07:57 UTC (rev 99543)
@@ -14,6 +14,17 @@
New Features
------------
+- Databases have a new method, transaction, that can be used with the
+ Python (2.5 and later) with statement::
+
+ db = ZODB.DB(...)
+ with db.transaction() as conn:
+ # ... do stuff with conn
+
+ This uses a private transaction manager for the connection.
+ If control exists the block without an error, the transaction is
+ committed, otherwise, it is aborted.
+
- Convenience methods ZODB.DB.open and ZEO.DB.open provide a
convenient way to open a connection to a database. They open a
database and return a connection to it. When the connection is
@@ -48,6 +59,13 @@
There are corresponding methods to read and set the new configuration
parameters.
+- Connections now have a public ``opened`` attribute that is true when
+ the connection is open, and false otherwise. When true, it is the
+ seconds since the epoch (time.time()) when the connection was
+ opened. This is a renaming of the previous ``_opened`` private
+ variable.
+
+
Bugs Fixed
----------
Modified: ZODB/trunk/src/ZODB/Connection.py
===================================================================
--- ZODB/trunk/src/ZODB/Connection.py 2009-04-27 21:35:05 UTC (rev 99542)
+++ ZODB/trunk/src/ZODB/Connection.py 2009-04-27 22:07:57 UTC (rev 99543)
@@ -101,7 +101,7 @@
# Do we need to join a txn manager?
self._needs_to_join = True
self.transaction_manager = None
- self._opened = None # time.time() when DB.open() opened us
+ self.opened = None # time.time() when DB.open() opened us
self._reset_counter = global_reset_counter
self._load_count = 0 # Number of objects unghosted
@@ -196,7 +196,7 @@
def add(self, obj):
"""Add a new object 'obj' to the database and assign it an oid."""
- if self._opened is None:
+ if self.opened is None:
raise ConnectionStateError("The database connection is closed")
marker = object()
@@ -220,7 +220,7 @@
def get(self, oid):
"""Return the persistent object with oid 'oid'."""
- if self._opened is None:
+ if self.opened is None:
raise ConnectionStateError("The database connection is closed")
obj = self._cache.get(oid, None)
@@ -292,7 +292,7 @@
self._debug_info = ()
- if self._opened:
+ if self.opened:
self.transaction_manager.unregisterSynch(self)
if primary:
@@ -301,15 +301,15 @@
connection.close(False)
# Return the connection to the pool.
- if self._opened is not None:
+ if self.opened is not None:
self._db._returnToPool(self)
- # _returnToPool() set self._opened to None.
+ # _returnToPool() set self.opened to None.
# However, we can't assert that here, because self may
# have been reused (by another thread) by the time we
# get back here.
else:
- self._opened = None
+ self.opened = None
def db(self):
"""Returns a handle to the database this connection belongs to."""
@@ -317,7 +317,7 @@
def isReadOnly(self):
"""Returns True if this connection is read only."""
- if self._opened is None:
+ if self.opened is None:
raise ConnectionStateError("The database connection is closed")
return self.before is not None or self._storage.isReadOnly()
@@ -798,7 +798,7 @@
the database."""
oid = obj._p_oid
- if self._opened is None:
+ if self.opened is None:
msg = ("Shouldn't load state for %s "
"when the connection is closed" % oid_repr(oid))
self._log.error(msg)
@@ -1010,7 +1010,7 @@
register for afterCompletion() calls.
"""
- self._opened = time.time()
+ self.opened = time.time()
if transaction_manager is None:
transaction_manager = transaction.manager
Modified: ZODB/trunk/src/ZODB/DB.py
===================================================================
--- ZODB/trunk/src/ZODB/DB.py 2009-04-27 21:35:05 UTC (rev 99542)
+++ ZODB/trunk/src/ZODB/DB.py 2009-04-27 22:07:57 UTC (rev 99543)
@@ -515,7 +515,7 @@
self._a()
try:
assert connection._db is self
- connection._opened = None
+ connection.opened = None
am = self._activity_monitor
if am is not None:
@@ -783,7 +783,7 @@
def get_info(c):
# `result`, `time` and `before` are lexically inherited.
- o = c._opened
+ o = c.opened
d = c.getDebugInfo()
if d:
if len(d) == 1:
@@ -920,7 +920,29 @@
txn = transaction.get()
txn.register(TransactionalUndo(self, id))
+ def transaction(self):
+ return ContextManager(self)
+
+class ContextManager:
+ """PEP 343 context manager
+ """
+
+ def __init__(self, db):
+ self.db = db
+
+ def __enter__(self):
+ self.tm = transaction.TransactionManager()
+ self.conn = self.db.open(self.tm)
+ return self.conn
+
+ def __exit__(self, t, v, tb):
+ if t is None:
+ self.tm.commit()
+ else:
+ self.tm.abort()
+ self.conn.close()
+
resource_counter_lock = threading.Lock()
resource_counter = 0
Modified: ZODB/trunk/src/ZODB/tests/testDB.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testDB.py 2009-04-27 21:35:05 UTC (rev 99542)
+++ ZODB/trunk/src/ZODB/tests/testDB.py 2009-04-27 22:07:57 UTC (rev 99543)
@@ -16,6 +16,7 @@
from zope.testing import doctest
import datetime
import os
+import sys
import time
import transaction
import unittest
@@ -181,6 +182,62 @@
>>> db.close()
"""
+if sys.version_info >= (2, 6):
+ def db_with_transaction():
+ """Using databases with with
+
+ The transaction method returns a context manager that when entered
+ starts a transaction with a private transaction manager. To
+ illustrate this, we start a trasnaction using a regular connection
+ and see that it isn't automatically committed or aborted as we use
+ the transaction context manager.
+
+ >>> db = ZODB.DB('data.fs')
+ >>> conn = db.open()
+ >>> conn.root()['x'] = conn.root().__class__()
+ >>> transaction.commit()
+ >>> conn.root()['x']['x'] = 1
+
+ >>> with db.transaction() as conn2:
+ ... conn2.root()['y'] = 1
+
+ >>> conn2.opened
+
+ Now, we'll open a 3rd connection a verify that
+
+ >>> conn3 = db.open()
+ >>> conn3.root()['x']
+ {}
+ >>> conn3.root()['y']
+ 1
+ >>> conn3.close()
+
+ Let's try again, but this time, we'll have an exception:
+
+ >>> with db.transaction() as conn2:
+ ... conn2.root()['y'] = 2
+ ... XXX
+ Traceback (most recent call last):
+ ...
+ NameError: name 'XXX' is not defined
+
+ >>> conn2.opened
+
+ >>> conn3 = db.open()
+ >>> conn3.root()['x']
+ {}
+ >>> conn3.root()['y']
+ 1
+ >>> conn3.close()
+
+ >>> transaction.commit()
+
+ >>> conn3 = db.open()
+ >>> conn3.root()['x']
+ {'x': 1}
+
+ """
+
def test_suite():
s = unittest.makeSuite(DBTests)
s.addTest(doctest.DocTestSuite(
More information about the Zodb-checkins
mailing list