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
...
@@ -10,6 +10,8 @@ with support
We can now use the with statement to define transaction boundaries.
We can now use the with statement to define transaction boundaries.
.. doctest::
>>> import transaction.tests.savepointsample
>>> import transaction.tests.savepointsample
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
>>> list(dm.keys())
>>> list(dm.keys())
...
@@ -17,6 +19,8 @@ We can now use the with statement to define transaction boundaries.
...
@@ -17,6 +19,8 @@ We can now use the with statement to define transaction boundaries.
We can use it with a manager:
We can use it with a manager:
.. doctest::
>>> with transaction.manager as t:
>>> with transaction.manager as t:
... dm['z'] = 3
... dm['z'] = 3
... t.note('test 3')
... t.note('test 3')
...
@@ -46,7 +50,9 @@ Retries
...
@@ -46,7 +50,9 @@ Retries
Commits can fail for transient reasons, especially conflicts.
Commits can fail for transient reasons, especially conflicts.
Applications will often retry transactions some number of times to
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):
for i in range(3):
try:
try:
...
@@ -62,6 +68,7 @@ This is rather ugly.
...
@@ -62,6 +68,7 @@ This is rather ugly.
Transaction managers provide a helper for this case. To show this,
Transaction managers provide a helper for this case. To show this,
we'll use a contrived example:
we'll use a contrived example:
.. doctest::
>>> ntry = 0
>>> ntry = 0
>>> with transaction.manager:
>>> with transaction.manager:
...
@@ -96,6 +103,8 @@ a transaction object will be assigned to the variable named.
...
@@ -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:
By default, it tries 3 times. We can tell it how many times to try:
.. doctest::
>>> for attempt in transaction.manager.attempts(2):
>>> for attempt in transaction.manager.attempts(2):
... with attempt:
... with attempt:
... ntry += 1
... ntry += 1
...
@@ -110,6 +119,8 @@ propagated.
...
@@ -110,6 +119,8 @@ propagated.
Of course, other errors are propagated directly:
Of course, other errors are propagated directly:
.. doctest::
>>> ntry = 0
>>> ntry = 0
>>> for attempt in transaction.manager.attempts():
>>> for attempt in transaction.manager.attempts():
... with attempt:
... with attempt:
...
@@ -122,6 +133,8 @@ Of course, other errors are propagated directly:
...
@@ -122,6 +133,8 @@ Of course, other errors are propagated directly:
We can use the default transaction manager:
We can use the default transaction manager:
.. doctest::
>>> for attempt in transaction.attempts():
>>> for attempt in transaction.attempts():
... with attempt as t:
... with attempt as t:
... t.note('test')
... t.note('test')
...
@@ -140,6 +153,8 @@ control. Data managers can provide a should_retry method that takes
...
@@ -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
an exception instance and returns True if the transaction should be
attempted again.
attempted again.
.. doctest::
>>> class DM(transaction.tests.savepointsample.SampleSavepointDataManager):
>>> class DM(transaction.tests.savepointsample.SampleSavepointDataManager):
... def should_retry(self, e):
... def should_retry(self, e):
... if 'should retry' in str(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.
...
@@ -25,6 +25,8 @@ use savepoints and doom() safely.
To see how it works we first need to create a stub data manager:
To see how it works we first need to create a stub data manager:
.. doctest::
>>> from transaction.interfaces import IDataManager
>>> from transaction.interfaces import IDataManager
>>> from zope.interface import implementer
>>> from zope.interface import implementer
>>> @implementer(IDataManager)
>>> @implementer(IDataManager)
...
@@ -45,6 +47,8 @@ To see how it works we first need to create a stub data manager:
...
@@ -45,6 +47,8 @@ To see how it works we first need to create a stub data manager:
Start a new transaction:
Start a new transaction:
.. doctest::
>>> import transaction
>>> import transaction
>>> txn = transaction.begin()
>>> txn = transaction.begin()
>>> dm = DataManager()
>>> dm = DataManager()
...
@@ -56,27 +60,37 @@ sends all outstanding SQL to a relational database for objects changed during
...
@@ -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
the transaction. This expensive operation is not necessary if the transaction
has been doomed. A non-doomed transaction should return False:
has been doomed. A non-doomed transaction should return False:
.. doctest::
>>> txn.isDoomed()
>>> txn.isDoomed()
False
False
We can doom a transaction by calling .doom() on it:
We can doom a transaction by calling .doom() on it:
.. doctest::
>>> txn.doom()
>>> txn.doom()
>>> txn.isDoomed()
>>> txn.isDoomed()
True
True
We can doom it again if we like:
We can doom it again if we like:
.. doctest::
>>> txn.doom()
>>> txn.doom()
The data manager is unchanged at this point:
The data manager is unchanged at this point:
.. doctest::
>>> dm.total()
>>> dm.total()
0
0
Attempting to commit a doomed transaction any number of times raises a
Attempting to commit a doomed transaction any number of times raises a
DoomedTransaction:
DoomedTransaction:
.. doctest::
>>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
>>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
Traceback (most recent call last):
DoomedTransaction: transaction doomed, cannot commit
DoomedTransaction: transaction doomed, cannot commit
...
@@ -86,15 +100,21 @@ DoomedTransaction:
...
@@ -86,15 +100,21 @@ DoomedTransaction:
But still leaves the data manager unchanged:
But still leaves the data manager unchanged:
.. doctest::
>>> dm.total()
>>> dm.total()
0
0
But the doomed transaction can be aborted:
But the doomed transaction can be aborted:
.. doctest::
>>> txn.abort()
>>> txn.abort()
Which aborts the data manager:
Which aborts the data manager:
.. doctest::
>>> dm.total()
>>> dm.total()
1
1
>>> dm.attr_counter['abort']
>>> dm.attr_counter['abort']
...
@@ -103,6 +123,8 @@ Which aborts the data manager:
...
@@ -103,6 +123,8 @@ Which aborts the data manager:
Dooming the current transaction can also be done directly from the transaction
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:
module. We can also begin a new transaction directly after dooming the old one:
.. doctest::
>>> txn = transaction.begin()
>>> txn = transaction.begin()
>>> transaction.isDoomed()
>>> transaction.isDoomed()
False
False
...
@@ -115,6 +137,8 @@ After committing a transaction we get an assertion error if we try to doom the
...
@@ -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
transaction. This could be made more specific, but trying to doom a transaction
after it's been committed is probably a programming error:
after it's been committed is probably a programming error:
.. doctest::
>>> txn = transaction.begin()
>>> txn = transaction.begin()
>>> txn.commit()
>>> txn.commit()
>>> txn.doom()
>>> txn.doom()
...
@@ -125,6 +149,8 @@ after it's been committed is probably a programming error:
...
@@ -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
A doomed transaction should act the same as an active transaction, so we should
be able to join it:
be able to join it:
.. doctest::
>>> txn = transaction.begin()
>>> txn = transaction.begin()
>>> txn.doom()
>>> txn.doom()
>>> dm2 = DataManager()
>>> dm2 = DataManager()
...
@@ -132,5 +158,7 @@ be able to join it:
...
@@ -132,5 +158,7 @@ be able to join it:
Clean up:
Clean up:
.. doctest::
>>> txn = transaction.begin()
>>> txn = transaction.begin()
>>> txn.abort()
>>> txn.abort()
docs/index.rst
View file @
2df3cf17
...
@@ -6,6 +6,9 @@ Contents:
...
@@ -6,6 +6,9 @@ Contents:
.. toctree::
.. toctree::
:maxdepth: 2
:maxdepth: 2
convenience
doom
savepoint
api
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
...
@@ -24,6 +24,8 @@ demonstrating the correct operation of savepoint support within the
transaction system. This data manager is very simple. It provides flat
transaction system. This data manager is very simple. It provides flat
storage of named immutable values, like strings and numbers.
storage of named immutable values, like strings and numbers.
.. doctest::
>>> import transaction
>>> import transaction
>>> from transaction.tests import savepointsample
>>> from transaction.tests import savepointsample
>>> dm = savepointsample.SampleSavepointDataManager()
>>> dm = savepointsample.SampleSavepointDataManager()
...
@@ -31,12 +33,16 @@ storage of named immutable values, like strings and numbers.
...
@@ -31,12 +33,16 @@ storage of named immutable values, like strings and numbers.
As with other data managers, we can commit changes:
As with other data managers, we can commit changes:
.. doctest::
>>> transaction.commit()
>>> transaction.commit()
>>> dm['name']
>>> dm['name']
'bob'
'bob'
and abort changes:
and abort changes:
.. doctest::
>>> dm['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> dm['name']
>>> dm['name']
'sally'
'sally'
...
@@ -52,6 +58,8 @@ account is invalid, we roll back the change for that entry. The success or
...
@@ -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
failure of an entry is indicated in the output status. First we'll initialize
some accounts:
some accounts:
.. doctest::
>>> dm['bob-balance'] = 0.0
>>> dm['bob-balance'] = 0.0
>>> dm['bob-credit'] = 0.0
>>> dm['bob-credit'] = 0.0
>>> dm['sally-balance'] = 0.0
>>> dm['sally-balance'] = 0.0
...
@@ -60,6 +68,8 @@ some accounts:
...
@@ -60,6 +68,8 @@ some accounts:
Now, we'll define a validation function to validate an account:
Now, we'll define a validation function to validate an account:
.. doctest::
>>> def validate_account(name):
>>> def validate_account(name):
... if dm[name+'-balance'] + dm[name+'-credit'] < 0:
... if dm[name+'-balance'] + dm[name+'-credit'] < 0:
... raise ValueError('Overdrawn', name)
... raise ValueError('Overdrawn', name)
...
@@ -67,6 +77,8 @@ Now, we'll define a validation function to validate an account:
...
@@ -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
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:
way, it rolls back all of its changes and prints the error:
.. doctest::
>>> def apply_entries(entries):
>>> def apply_entries(entries):
... savepoint = transaction.savepoint()
... savepoint = transaction.savepoint()
... try:
... try:
...
@@ -86,6 +98,8 @@ way, it rolls back all of its changes and prints the error:
...
@@ -86,6 +98,8 @@ way, it rolls back all of its changes and prints the error:
Now let's try applying some entries:
Now let's try applying some entries:
.. doctest::
>>> apply_entries([
>>> apply_entries([
... ('bob', 10.0),
... ('bob', 10.0),
... ('sally', 10.0),
... ('sally', 10.0),
...
@@ -109,6 +123,8 @@ Now let's try applying some entries:
...
@@ -109,6 +123,8 @@ Now let's try applying some entries:
If we provide entries that cause an unexpected error:
If we provide entries that cause an unexpected error:
.. doctest::
>>> apply_entries([
>>> apply_entries([
... ('bob', 10.0),
... ('bob', 10.0),
... ('sally', 10.0),
... ('sally', 10.0),
...
@@ -123,6 +139,8 @@ Because the apply_entries used a savepoint for the entire function, it was
...
@@ -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
able to rollback the partial changes without rolling back changes made in the
previous call to ``apply_entries``:
previous call to ``apply_entries``:
.. doctest::
>>> dm['bob-balance']
>>> dm['bob-balance']
30.0
30.0
...
@@ -132,6 +150,8 @@ previous call to ``apply_entries``:
...
@@ -132,6 +150,8 @@ previous call to ``apply_entries``:
If we now abort the outer transactions, the earlier changes will go
If we now abort the outer transactions, the earlier changes will go
away:
away:
.. doctest::
>>> transaction.abort()
>>> transaction.abort()
>>> dm['bob-balance']
>>> dm['bob-balance']
...
@@ -145,6 +165,8 @@ Savepoint invalidation
...
@@ -145,6 +165,8 @@ Savepoint invalidation
A savepoint can be used any number of times:
A savepoint can be used any number of times:
.. doctest::
>>> dm['bob-balance'] = 100.0
>>> dm['bob-balance'] = 100.0
>>> dm['bob-balance']
>>> dm['bob-balance']
100.0
100.0
...
@@ -170,6 +192,8 @@ A savepoint can be used any number of times:
...
@@ -170,6 +192,8 @@ A savepoint can be used any number of times:
However, using a savepoint invalidates any savepoints that come after it:
However, using a savepoint invalidates any savepoints that come after it:
.. doctest::
>>> dm['bob-balance'] = 200.0
>>> dm['bob-balance'] = 200.0
>>> dm['bob-balance']
>>> dm['bob-balance']
200.0
200.0
...
@@ -203,6 +227,8 @@ Databases without savepoint support
...
@@ -203,6 +227,8 @@ Databases without savepoint support
Normally it's an error to use savepoints with databases that don't support
Normally it's an error to use savepoints with databases that don't support
savepoints:
savepoints:
.. doctest::
>>> dm_no_sp = savepointsample.SampleDataManager()
>>> dm_no_sp = savepointsample.SampleDataManager()
>>> dm_no_sp['name'] = 'bob'
>>> dm_no_sp['name'] = 'bob'
>>> transaction.commit()
>>> transaction.commit()
...
@@ -219,6 +245,8 @@ that databases without savepoint support should be tolerated until a savepoint
...
@@ -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
is rolled back. This allows transactions to proceed if there are no reasons
to roll back:
to roll back:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> dm_no_sp['name'] = 'sally'
>>> savepoint = transaction.savepoint(1)
>>> savepoint = transaction.savepoint(1)
>>> dm_no_sp['name'] = 'sue'
>>> dm_no_sp['name'] = 'sue'
...
@@ -245,6 +273,8 @@ the transaction is aborted.
...
@@ -245,6 +273,8 @@ the transaction is aborted.
In the previous example, we got an error when we tried to rollback the
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:
savepoint. If we try to commit the transaction, the commit will fail:
.. doctest::
>>> transaction.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
>>> transaction.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
Traceback (most recent call last):
...
...
...
@@ -255,11 +285,15 @@ savepoint. If we try to commit the transaction, the commit will fail:
...
@@ -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:
We have to abort it to make any progress:
.. doctest::
>>> transaction.abort()
>>> transaction.abort()
Similarly, in our earlier example, where we tried to take a savepoint with a
Similarly, in our earlier example, where we tried to take a savepoint with a
data manager that didn't support savepoints:
data manager that didn't support savepoints:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> dm_no_sp['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> savepoint = transaction.savepoint() # doctest: +IGNORE_EXCEPTION_DETAIL
>>> savepoint = transaction.savepoint() # doctest: +IGNORE_EXCEPTION_DETAIL
...
@@ -280,6 +314,8 @@ data manager that didn't support savepoints:
...
@@ -280,6 +314,8 @@ data manager that didn't support savepoints:
After clearing the transaction with an abort, we can get on with new
After clearing the transaction with an abort, we can get on with new
transactions:
transactions:
.. doctest::
>>> dm_no_sp['name'] = 'sally'
>>> dm_no_sp['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> dm['name'] = 'sally'
>>> transaction.commit()
>>> transaction.commit()
...
...
transaction/tests/savepointsample.py
View file @
2df3cf17
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
Sample data manager implementation that illustrates how to implement
Sample data manager implementation that illustrates how to implement
savepoints.
savepoints.
See savepoint.txt in the transaction package
.
Used by savepoint.rst in the Sphinx docs
.
"""
"""
from
zope.interface
import
implementer
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.
...
@@ -80,7 +80,6 @@ the dm would end up being joined twice, leading to extra tpc calls and pain.
def
test_suite
():
def
test_suite
():
return
unittest
.
TestSuite
((
return
unittest
.
TestSuite
((
doctest
.
DocFileSuite
(
'savepoint.txt'
),
doctest
.
DocTestSuite
(),
doctest
.
DocTestSuite
(),
))
))
...
...
transaction/tests/test_transaction.py
View file @
2df3cf17
...
@@ -36,10 +36,8 @@ TODO
...
@@ -36,10 +36,8 @@ TODO
add in tests for objects which are modified multiple times,
add in tests for objects which are modified multiple times,
for example an object that gets modified in multiple sub txns.
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
struct
import
sys
import
unittest
import
unittest
import
transaction
import
transaction
...
@@ -763,14 +761,10 @@ def bug239086():
...
@@ -763,14 +761,10 @@ def bug239086():
def
test_suite
():
def
test_suite
():
suite
=
unittest
.
TestSuite
((
suite
=
unittest
.
TestSuite
((
DocFileSuite
(
'doom.txt'
),
DocTestSuite
(),
DocTestSuite
(),
unittest
.
makeSuite
(
TransactionTests
),
unittest
.
makeSuite
(
TransactionTests
),
unittest
.
makeSuite
(
Test_oid_repr
),
unittest
.
makeSuite
(
Test_oid_repr
),
))
))
if
sys
.
version_info
>=
(
2
,
6
):
suite
.
addTest
(
DocFileSuite
(
'convenience.txt'
,
optionflags
=
IGNORE_EXCEPTION_DETAIL
))
return
suite
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