Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
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
Zope
Commits
db30982b
Commit
db30982b
authored
May 11, 2004
by
root
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Use tagged version of src/transaction
parent
643a9757
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
2462 additions
and
0 deletions
+2462
-0
lib/python/transaction/DEPENDENCIES.cfg
lib/python/transaction/DEPENDENCIES.cfg
+2
-0
lib/python/transaction/README.txt
lib/python/transaction/README.txt
+14
-0
lib/python/transaction/__init__.py
lib/python/transaction/__init__.py
+33
-0
lib/python/transaction/_manager.py
lib/python/transaction/_manager.py
+93
-0
lib/python/transaction/_transaction.py
lib/python/transaction/_transaction.py
+582
-0
lib/python/transaction/interfaces.py
lib/python/transaction/interfaces.py
+120
-0
lib/python/transaction/notes.txt
lib/python/transaction/notes.txt
+269
-0
lib/python/transaction/tests/__init__.py
lib/python/transaction/tests/__init__.py
+1
-0
lib/python/transaction/tests/abstestIDataManager.py
lib/python/transaction/tests/abstestIDataManager.py
+63
-0
lib/python/transaction/tests/test_SampleDataManager.py
lib/python/transaction/tests/test_SampleDataManager.py
+412
-0
lib/python/transaction/tests/test_register_compat.py
lib/python/transaction/tests/test_register_compat.py
+150
-0
lib/python/transaction/tests/test_transaction.py
lib/python/transaction/tests/test_transaction.py
+647
-0
lib/python/transaction/tests/test_util.py
lib/python/transaction/tests/test_util.py
+25
-0
lib/python/transaction/util.py
lib/python/transaction/util.py
+51
-0
No files found.
lib/python/transaction/DEPENDENCIES.cfg
0 → 100644
View file @
db30982b
ZODB
zope.interface
lib/python/transaction/README.txt
0 → 100644
View file @
db30982b
This package is currently a facade of the ZODB.Transaction module.
It exists to support:
- Application code that uses the ZODB 4 transaction API
- ZODB4-style data managers (transaction.interfaces.IDataManager)
Note that the data manager API, transaction.interfaces.IDataManager,
is syntactically simple, but semantically complex. The semantics
were not easy to express in the interface. This could probably use
more work. The semantics are presented in detail through examples of
a sample data manager in transaction.tests.test_SampleDataManager.
lib/python/transaction/__init__.py
0 → 100644
View file @
db30982b
############################################################################
#
# Copyright (c) 2001, 2002, 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
############################################################################
from
transaction._transaction
import
Transaction
from
transaction._manager
import
TransactionManager
,
ThreadTransactionManager
manager
=
ThreadTransactionManager
()
def
get
():
return
manager
.
get
()
def
begin
():
return
manager
.
begin
()
def
commit
(
sub
=
False
):
manager
.
get
().
commit
(
sub
)
def
abort
(
sub
=
False
):
manager
.
get
().
abort
(
sub
)
# XXX Issue deprecation warning if this variant is used?
get_transaction
=
get
lib/python/transaction/_manager.py
0 → 100644
View file @
db30982b
############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
############################################################################
"""A TransactionManager controls transaction boundaries.
It coordinates application code and resource managers, so that they
are associated with the right transaction.
"""
import
thread
from
transaction._transaction
import
Transaction
class
TransactionManager
(
object
):
def
__init__
(
self
):
self
.
_txn
=
None
self
.
_synchs
=
[]
def
begin
(
self
):
if
self
.
_txn
is
not
None
:
self
.
_txn
.
abort
()
self
.
_txn
=
Transaction
(
self
.
_synchs
,
self
)
return
self
.
_txn
def
get
(
self
):
if
self
.
_txn
is
None
:
self
.
_txn
=
Transaction
(
self
.
_synchs
,
self
)
return
self
.
_txn
def
free
(
self
,
txn
):
assert
txn
is
self
.
_txn
self
.
_txn
=
None
def
registerSynch
(
self
,
synch
):
self
.
_synchs
.
append
(
synch
)
def
unregisterSynch
(
self
,
synch
):
self
.
_synchs
.
remove
(
synch
)
class
ThreadTransactionManager
(
object
):
"""Thread-aware transaction manager.
Each thread is associated with a unique transaction.
"""
def
__init__
(
self
):
# _threads maps thread ids to transactions
self
.
_txns
=
{}
# _synchs maps a thread id to a list of registered synchronizers.
# The list is passed to the Transaction constructor, because
# it needs to call the synchronizers when it commits.
self
.
_synchs
=
{}
def
begin
(
self
):
tid
=
thread
.
get_ident
()
txn
=
self
.
_txns
.
get
(
tid
)
if
txn
is
not
None
:
txn
.
abort
()
txn
=
self
.
_txns
[
tid
]
=
Transaction
(
self
.
_synchs
.
get
(
tid
),
self
)
return
txn
def
get
(
self
):
tid
=
thread
.
get_ident
()
txn
=
self
.
_txns
.
get
(
tid
)
if
txn
is
None
:
txn
=
self
.
_txns
[
tid
]
=
Transaction
(
self
.
_synchs
.
get
(
tid
),
self
)
return
txn
def
free
(
self
,
txn
):
tid
=
thread
.
get_ident
()
assert
txn
is
self
.
_txns
.
get
(
tid
)
del
self
.
_txns
[
tid
]
def
registerSynch
(
self
,
synch
):
tid
=
thread
.
get_ident
()
L
=
self
.
_synchs
.
setdefault
(
tid
,
[])
L
.
append
(
synch
)
def
unregisterSynch
(
self
,
synch
):
tid
=
thread
.
get_ident
()
L
=
self
.
_synchs
.
get
(
tid
)
L
.
remove
(
synch
)
lib/python/transaction/_transaction.py
0 → 100644
View file @
db30982b
This diff is collapsed.
Click to expand it.
lib/python/transaction/interfaces.py
0 → 100644
View file @
db30982b
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Transaction Interfaces
$Id: interfaces.py,v 1.8 2004/04/19 21:19:10 tim_one Exp $
"""
try
:
from
zope.interface
import
Interface
except
ImportError
:
class
Interface
:
pass
class
IDataManager
(
Interface
):
"""Data management interface for storing objects transactionally
This is currently implemented by ZODB database connections.
XXX This exists to document ZODB4 behavior, to help create some
backward-compatability support for Zope 3. New classes shouldn't
implement this. They should implement ZODB.interfaces.IDataManager
for now. Our hope is that there will eventually be an interface
like this or that this interface will evolve and become the
standard interface. There are some issues to be resolved first, like:
- Probably want separate abort methods for use in and out of
two-phase commit.
- The savepoint api may need some more thought.
"""
def
prepare
(
transaction
):
"""Perform the first phase of a 2-phase commit
The data manager prepares for commit any changes to be made
persistent. A normal return from this method indicated that
the data manager is ready to commit the changes.
The data manager must raise an exception if it is not prepared
to commit the transaction after executing prepare().
The transaction must match that used for preceeding
savepoints, if any.
"""
# This is equivalent to zodb3's tpc_begin, commit, and
# tpc_vote combined.
def
abort
(
transaction
):
"""Abort changes made by transaction
This may be called before two-phase commit or in the second
phase of two-phase commit.
The transaction must match that used for preceeding
savepoints, if any.
"""
# This is equivalent to *both* zodb3's abort and tpc_abort
# calls. This should probably be split into 2 methods.
def
commit
(
transaction
):
"""Finish two-phase commit
The prepare method must be called, with the same transaction,
before calling commit.
"""
# This is equivalent to zodb3's tpc_finish
def
savepoint
(
transaction
):
"""Do tentative commit of changes to this point.
Should return an object implementing IRollback that can be used
to rollback to the savepoint.
Note that (unlike zodb3) this doesn't use a 2-phase commit
protocol. If this call fails, or if a rollback call on the
result fails, the (containing) transaction should be
aborted. Aborting the containing transaction is *not* the
responsibility of the data manager, however.
An implementation that doesn't support savepoints should
implement this method by returning a rollback implementation
that always raises an error when it's rollback method is
called. The savepoing method shouldn't raise an error. This
way, transactions that create savepoints can proceed as long
as an attempt is never made to roll back a savepoint.
"""
class
IRollback
(
Interface
):
def
rollback
():
"""Rollback changes since savepoint.
IOW, rollback to the last savepoint.
It is an error to rollback to a savepoint if:
- An earlier savepoint within the same transaction has been
rolled back to, or
- The transaction has ended.
"""
lib/python/transaction/notes.txt
0 → 100644
View file @
db30982b
This diff is collapsed.
Click to expand it.
lib/python/transaction/tests/__init__.py
0 → 100644
View file @
db30982b
#
lib/python/transaction/tests/abstestIDataManager.py
0 → 100644
View file @
db30982b
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test cases for objects implementing IDataManager.
This is a combo test between Connection and DB, since the two are
rather incestuous and the DB Interface is not defined that I was
able to find.
To do a full test suite one would probably want to write a dummy
storage that will raise errors as needed for testing.
I started this test suite to reproduce a very simple error (tpc_abort
had an error and wouldn't even run if called). So it is *very*
incomplete, and even the tests that exist do not make sure that
the data actually gets written/not written to the storge.
Obviously this test suite should be expanded.
$Id: abstestIDataManager.py,v 1.5 2004/03/05 22:08:50 jim Exp $
"""
from
unittest
import
TestCase
from
transaction.interfaces
import
IRollback
class
IDataManagerTests
(
TestCase
,
object
):
def
setUp
(
self
):
self
.
datamgr
=
None
# subclass should override
self
.
obj
=
None
# subclass should define Persistent object
self
.
txn_factory
=
None
def
get_transaction
(
self
):
return
self
.
txn_factory
()
################################
# IDataManager interface tests #
################################
def
testCommitObj
(
self
):
tran
=
self
.
get_transaction
()
self
.
datamgr
.
prepare
(
tran
)
self
.
datamgr
.
commit
(
tran
)
def
testAbortTran
(
self
):
tran
=
self
.
get_transaction
()
self
.
datamgr
.
prepare
(
tran
)
self
.
datamgr
.
abort
(
tran
)
def
testRollback
(
self
):
tran
=
self
.
get_transaction
()
rb
=
self
.
datamgr
.
savepoint
(
tran
)
self
.
assert_
(
IRollback
.
providedBy
(
rb
))
lib/python/transaction/tests/test_SampleDataManager.py
0 → 100644
View file @
db30982b
This diff is collapsed.
Click to expand it.
lib/python/transaction/tests/test_register_compat.py
0 → 100644
View file @
db30982b
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test backwards compatibility for resource managers using register().
The transaction package supports several different APIs for resource
managers. The original ZODB3 API was implemented by ZODB.Connection.
The Connection passed persistent objects to a Transaction's register()
method. It's possible that third-party code also used this API, hence
these tests that the code that adapts the old interface to the current
API works.
These tests use a TestConnection object that implements the old API.
They check that the right methods are called and in roughly the right
order.
Common cases
------------
First, check that a basic transaction commit works.
>>> cn = TestConnection()
>>> cn.register(Object())
>>> cn.register(Object())
>>> cn.register(Object())
>>> transaction.commit()
>>> len(cn.committed)
3
>>> len(cn.aborted)
0
>>> cn.calls
['begin', 'vote', 'finish']
Second, check that a basic transaction abort works. If the
application calls abort(), then the transaction never gets into the
two-phase commit. It just aborts each object.
>>> cn = TestConnection()
>>> cn.register(Object())
>>> cn.register(Object())
>>> cn.register(Object())
>>> transaction.abort()
>>> len(cn.committed)
0
>>> len(cn.aborted)
3
>>> cn.calls
[]
Error handling
--------------
The tricky part of the implementation is recovering from an error that
occurs during the two-phase commit. We override the commit() and
abort() methods of Object to cause errors during commit.
Note that the implementation uses lists internally, so that objects
are committed in the order they are registered. (In the presence of
multiple resource managers, objects from a single resource manager are
committed in order. I'm not sure if this is an accident of the
implementation or a feature that should be supported by any
implementation.)
The order of resource managers depends on sortKey().
>>> cn = TestConnection()
>>> cn.register(Object())
>>> cn.register(CommitError())
>>> cn.register(Object())
>>> transaction.commit()
Traceback (most recent call last):
...
RuntimeError: commit
>>> len(cn.committed)
1
>>> len(cn.aborted)
3
"""
import
transaction
class
Object
(
object
):
def
commit
(
self
):
pass
def
abort
(
self
):
pass
class
CommitError
(
Object
):
def
commit
(
self
):
raise
RuntimeError
(
"commit"
)
class
AbortError
(
Object
):
def
abort
(
self
):
raise
RuntimeError
(
"abort"
)
class
BothError
(
CommitError
,
AbortError
):
pass
class
TestConnection
:
def
__init__
(
self
):
self
.
committed
=
[]
self
.
aborted
=
[]
self
.
calls
=
[]
def
register
(
self
,
obj
):
obj
.
_p_jar
=
self
transaction
.
get
().
register
(
obj
)
def
sortKey
(
self
):
return
str
(
id
(
self
))
def
tpc_begin
(
self
,
txn
,
sub
):
self
.
calls
.
append
(
"begin"
)
def
tpc_vote
(
self
,
txn
):
self
.
calls
.
append
(
"vote"
)
def
tpc_finish
(
self
,
txn
):
self
.
calls
.
append
(
"finish"
)
def
tpc_abort
(
self
,
txn
):
self
.
calls
.
append
(
"abort"
)
def
commit
(
self
,
obj
,
txn
):
obj
.
commit
()
self
.
committed
.
append
(
obj
)
def
abort
(
self
,
obj
,
txn
):
obj
.
abort
()
self
.
aborted
.
append
(
obj
)
import
doctest
def
test_suite
():
return
doctest
.
DocTestSuite
()
lib/python/transaction/tests/test_transaction.py
0 → 100644
View file @
db30982b
This diff is collapsed.
Click to expand it.
lib/python/transaction/tests/test_util.py
0 → 100644
View file @
db30982b
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test transaction utilities
$Id: test_util.py,v 1.2 2004/02/20 16:56:58 fdrake Exp $
"""
import
unittest
from
doctest
import
DocTestSuite
def
test_suite
():
return
DocTestSuite
(
'transaction.util'
)
if
__name__
==
'__main__'
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
lib/python/transaction/util.py
0 → 100644
View file @
db30982b
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Utility classes or functions
$Id: util.py,v 1.3 2004/04/19 21:19:10 tim_one Exp $
"""
from
transaction.interfaces
import
IRollback
try
:
from
zope.interface
import
implements
except
ImportError
:
def
implements
(
*
args
):
pass
class
NoSavepointSupportRollback
:
"""Rollback for data managers that don't support savepoints
>>> class DataManager:
... def savepoint(self, txn):
... return NoSavepointSupportRollback(self)
>>> rb = DataManager().savepoint('some transaction')
>>> rb.rollback()
Traceback (most recent call last):
...
NotImplementedError: """
\
"""DataManager data managers do not support """
\
"""savepoints (aka subtransactions
"""
implements
(
IRollback
)
def
__init__
(
self
,
dm
):
self
.
dm
=
dm
.
__class__
.
__name__
def
rollback
(
self
):
raise
NotImplementedError
(
"%s data managers do not support savepoints (aka subtransactions"
%
self
.
dm
)
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