Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
T
transaction
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
transaction
Commits
2df3cf17
Commit
2df3cf17
authored
Dec 17, 2012
by
Tres Seaver
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move whole-file doctests into docs/.
parent
af2c1b2b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
85 additions
and
10 deletions
+85
-10
docs/convenience.rst
docs/convenience.rst
+16
-1
docs/doom.rst
docs/doom.rst
+28
-0
docs/index.rst
docs/index.rst
+3
-0
docs/savepoint.rst
docs/savepoint.rst
+36
-0
transaction/tests/savepointsample.py
transaction/tests/savepointsample.py
+1
-1
transaction/tests/test_savepoint.py
transaction/tests/test_savepoint.py
+0
-1
transaction/tests/test_transaction.py
transaction/tests/test_transaction.py
+1
-7
No files found.
transaction/tests/convenience.tx
t
→
docs/convenience.rs
t
View file @
2df3cf17
...
...
@@ -10,6 +10,8 @@ with support
We can now use the with statement to define transaction boundaries.
.. doctest::
>>> import transaction.tests.savepointsample
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
>>> list(dm.keys())
...
...
@@ -17,6 +19,8 @@ We can now use the with statement to define transaction boundaries.
We can use it with a manager:
.. doctest::
>>> with transaction.manager as t:
... dm['z'] = 3
... t.note('test 3')
...
...
@@ -46,7 +50,9 @@ Retries
Commits can fail for transient reasons, especially conflicts.
Applications will often retry transactions some number of times to
overcome transient failures. This typically looks something like::
overcome transient failures. This typically looks something like:
.. doctest::
for i in range(3):
try:
...
...
@@ -62,6 +68,7 @@ This is rather ugly.
Transaction managers provide a helper for this case. To show this,
we'll use a contrived example:
.. doctest::
>>> ntry = 0
>>> with transaction.manager:
...
...
@@ -96,6 +103,8 @@ a transaction object will be assigned to the variable named.
By default, it tries 3 times. We can tell it how many times to try:
.. doctest::
>>> for attempt in transaction.manager.attempts(2):
... with attempt:
... ntry += 1
...
...
@@ -110,6 +119,8 @@ propagated.
Of course, other errors are propagated directly:
.. doctest::
>>> ntry = 0
>>> for attempt in transaction.manager.attempts():
... with attempt:
...
...
@@ -122,6 +133,8 @@ Of course, other errors are propagated directly:
We can use the default transaction manager:
.. doctest::
>>> for attempt in transaction.attempts():
... with attempt as t:
... t.note('test')
...
...
@@ -140,6 +153,8 @@ control. Data managers can provide a should_retry method that takes
an exception instance and returns True if the transaction should be
attempted again.
.. doctest::
>>> class DM(transaction.tests.savepointsample.SampleSavepointDataManager):
... def should_retry(self, e):
... if 'should retry' in str(e):
...
...
transaction/tests/doom.tx
t
→
docs/doom.rs
t
View file @
2df3cf17
...
...
@@ -25,6 +25,8 @@ use savepoints and doom() safely.
To see how it works we first need to create a stub data manager:
.. doctest::
>>> from transaction.interfaces import IDataManager
>>> from zope.interface import implementer
>>> @implementer(IDataManager)
...
...
@@ -45,6 +47,8 @@ To see how it works we first need to create a stub data manager:
Start a new transaction:
.. doctest::
>>> import transaction
>>> txn = transaction.begin()
>>> dm = DataManager()
...
...
@@ -56,27 +60,37 @@ sends all outstanding SQL to a relational database for objects changed during
the transaction. This expensive operation is not necessary if the transaction
has been doomed. A non-doomed transaction should return False:
.. doctest::
>>> txn.isDoomed()
False
We can doom a transaction by calling .doom() on it:
.. doctest::
>>> txn.doom()
>>> txn.isDoomed()
True
We can doom it again if we like:
.. doctest::
>>> txn.doom()
The data manager is unchanged at this point:
.. doctest::
>>> dm.total()
0
Attempting to commit a doomed transaction any number of times raises a
DoomedTransaction:
.. doctest::
>>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
DoomedTransaction: transaction doomed, cannot commit
...
...
@@ -86,15 +100,21 @@ DoomedTransaction:
But still leaves the data manager unchanged:
.. doctest::
>>> dm.total()
0
But the doomed transaction can be aborted:
.. doctest::
>>> txn.abort()
Which aborts the data manager:
.. doctest::
>>> dm.total()
1
>>> dm.attr_counter['abort']
...
...
@@ -103,6 +123,8 @@ Which aborts the data manager:
Dooming the current transaction can also be done directly from the transaction
module. We can also begin a new transaction directly after dooming the old one:
.. doctest::
>>> txn = transaction.begin()
>>> transaction.isDoomed()
False
...
...
@@ -115,6 +137,8 @@ After committing a transaction we get an assertion error if we try to doom the
transaction. This could be made more specific, but trying to doom a transaction
after it's been committed is probably a programming error:
.. doctest::
>>> txn = transaction.begin()
>>> txn.commit()
>>> txn.doom()
...
...
@@ -125,6 +149,8 @@ after it's been committed is probably a programming error:
A doomed transaction should act the same as an active transaction, so we should
be able to join it:
.. doctest::
>>> txn = transaction.begin()
>>> txn.doom()
>>> dm2 = DataManager()
...
...
@@ -132,5 +158,7 @@ be able to join it:
Clean up:
.. doctest::
>>> txn = transaction.begin()
>>> txn.abort()
docs/index.rst
View file @
2df3cf17
...
...
@@ -6,6 +6,9 @@ Contents:
.. toctree::
:maxdepth: 2
convenience
doom
savepoint
api
...
...
transaction/tests/savepoint.tx
t
→
docs/savepoint.rs
t
View file @
2df3cf17
...
...
@@ -24,6 +24,8 @@ demonstrating the correct operation of savepoint support within the
transaction system. This data manager is very simple. It provides flat
storage of named immutable values, like strings and numbers.
.. doctest::
>>> import transaction
>>> from transaction.tests import savepointsample
>>> dm = savepointsample.SampleSavepointDataManager()
...
...
@@ -31,12 +33,16 @@ storage of named immutable values, like strings and numbers.
As with other data managers, we can commit changes:
.. doctest::
>>> transaction.commit()
>>> dm['name']
'bob'
and abort changes:
.. doctest::
>>> dm['name'] = 'sally'
>>> dm['name']
'sally'
...
...
@@ -52,6 +58,8 @@ account is invalid, we roll back the change for that entry. The success or
failure of an entry is indicated in the output status. First we'll initialize
some accounts:
.. doctest::
>>> dm['bob-balance'] = 0.0
>>> dm['bob-credit'] = 0.0
>>> dm['sally-balance'] = 0.0
...
...
@@ -60,6 +68,8 @@ some accounts:
Now, we'll define a validation function to validate an account:
.. doctest::
>>> def validate_account(name):
... if dm[name+'-balance'] + dm[name+'-credit'] < 0:
... raise ValueError('Overdrawn', name)
...
...
@@ -67,6 +77,8 @@ Now, we'll define a validation function to validate an account:
And a function to apply entries. If the function fails in some unexpected
way, it rolls back all of its changes and prints the error:
.. doctest::
>>> def apply_entries(entries):
... savepoint = transaction.savepoint()
... try:
...
...
@@ -86,6 +98,8 @@ way, it rolls back all of its changes and prints the error:
Now let's try applying some entries:
.. doctest::
>>> apply_entries([
... ('bob', 10.0),
... ('sally', 10.0),
...
...
@@ -109,6 +123,8 @@ Now let's try applying some entries:
If we provide entries that cause an unexpected error:
.. doctest::
>>> apply_entries([
... ('bob', 10.0),
... ('sally', 10.0),
...
...
@@ -123,6 +139,8 @@ Because the apply_entries used a savepoint for the entire function, it was
able to rollback the partial changes without rolling back changes made in the
previous call to ``apply_entries``:
.. doctest::
>>> dm['bob-balance']
30.0
...
...
@@ -132,6 +150,8 @@ previous call to ``apply_entries``:
If we now abort the outer transactions, the earlier changes will go
away:
.. doctest::
>>> transaction.abort()
>>> dm['bob-balance']
...
...
@@ -145,6 +165,8 @@ Savepoint invalidation
A savepoint can be used any number of times:
.. doctest::
>>> dm['bob-balance'] = 100.0
>>> dm['bob-balance']
100.0
...
...
@@ -170,6 +192,8 @@ A savepoint can be used any number of times:
However, using a savepoint invalidates any savepoints that come after it:
.. doctest::
>>> dm['bob-balance'] = 200.0
>>> dm['bob-balance']
200.0
...
...
@@ -203,6 +227,8 @@ Databases without savepoint support
Normally it's an error to use savepoints with databases that don't support
savepoints:
.. doctest::
>>> dm_no_sp = savepointsample.SampleDataManager()
>>> dm_no_sp['name'] = 'bob'
>>> transaction.commit()
...
...
@@ -219,6 +245,8 @@ that databases without savepoint support should be tolerated until a savepoint
is rolled back. This allows transactions to proceed if there are no reasons
to roll back:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> savepoint = transaction.savepoint(1)
>>> dm_no_sp['name'] = 'sue'
...
...
@@ -245,6 +273,8 @@ the transaction is aborted.
In the previous example, we got an error when we tried to rollback the
savepoint. If we try to commit the transaction, the commit will fail:
.. doctest::
>>> transaction.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
...
...
@@ -255,11 +285,15 @@ savepoint. If we try to commit the transaction, the commit will fail:
We have to abort it to make any progress:
.. doctest::
>>> transaction.abort()
Similarly, in our earlier example, where we tried to take a savepoint with a
data manager that didn't support savepoints:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> savepoint = transaction.savepoint() # doctest: +IGNORE_EXCEPTION_DETAIL
...
...
@@ -280,6 +314,8 @@ data manager that didn't support savepoints:
After clearing the transaction with an abort, we can get on with new
transactions:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> transaction.commit()
...
...
transaction/tests/savepointsample.py
View file @
2df3cf17
...
...
@@ -16,7 +16,7 @@
Sample data manager implementation that illustrates how to implement
savepoints.
See savepoint.txt in the transaction package
.
Used by savepoint.rst in the Sphinx docs
.
"""
from
zope.interface
import
implementer
...
...
transaction/tests/test_savepoint.py
View file @
2df3cf17
...
...
@@ -80,7 +80,6 @@ the dm would end up being joined twice, leading to extra tpc calls and pain.
def
test_suite
():
return
unittest
.
TestSuite
((
doctest
.
DocFileSuite
(
'savepoint.txt'
),
doctest
.
DocTestSuite
(),
))
...
...
transaction/tests/test_transaction.py
View file @
2df3cf17
...
...
@@ -36,10 +36,8 @@ TODO
add in tests for objects which are modified multiple times,
for example an object that gets modified in multiple sub txns.
"""
from
doctest
import
DocTestSuite
,
DocFileSuite
,
IGNORE_EXCEPTION_DETAIL
from
doctest
import
DocTestSuite
import
struct
import
sys
import
unittest
import
transaction
...
...
@@ -763,14 +761,10 @@ def bug239086():
def
test_suite
():
suite
=
unittest
.
TestSuite
((
DocFileSuite
(
'doom.txt'
),
DocTestSuite
(),
unittest
.
makeSuite
(
TransactionTests
),
unittest
.
makeSuite
(
Test_oid_repr
),
))
if
sys
.
version_info
>=
(
2
,
6
):
suite
.
addTest
(
DocFileSuite
(
'convenience.txt'
,
optionflags
=
IGNORE_EXCEPTION_DETAIL
))
return
suite
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment