Commit 18601a1a authored by Jim Fulton's avatar Jim Fulton

Use doctest rather than zope.testing.doctest.

This required using manuel to get the footnote
feature. Unfortunately, manuel imports zope.testing.doctest. :)
Hpefully, this will be fixed soon.

Updated the testhistoricalconnections.py tearDown to clear conflict
resolution class cache. The cache was causing tests to fail when tests
were run multiple times.
parent 3ea253ad
......@@ -185,8 +185,8 @@ setup(name="ZODB3",
read_file("README.txt") + "\n\n" +
read_file("src", "CHANGES.txt")),
test_suite="__main__.alltests", # to support "setup.py test"
tests_require = ['zope.testing'],
extras_require = dict(test=['zope.testing']),
tests_require = ['zope.testing', 'manuel'],
extras_require = dict(test=['zope.testing', 'manuel']),
install_requires = [
'transaction',
'zc.lockfile',
......
......@@ -29,8 +29,6 @@ use:
on the object. If the method succeeds, then the object change can be
committed, otherwise a ConflictError is raised as usual.
::
def _p_resolveConflict(oldState, savedState, newState):
Return the state of the object after resolving different changes.
......@@ -41,6 +39,7 @@ use:
transaction were based on.
The method is permitted to modify this value.
savedState
The state of the object that is currently stored in the
database. This state was written after oldState and reflects
......@@ -48,6 +47,7 @@ use:
current transaction.
The method is permitted to modify this value.
newState
The state after changes made by the current transaction.
......@@ -62,22 +62,29 @@ use:
Consider an extremely simple example, a counter::
>>> from persistent import Persistent
>>> class PCounter(Persistent):
... '`value` is readonly; increment it with `inc`.'
... _val = 0
... def inc(self):
... self._val += 1
... @property
... def value(self):
... return self._val
... def _p_resolveConflict(self, oldState, savedState, newState):
... oldState['_val'] = (
... savedState.get('_val', 0) +
... newState.get('_val', 0) -
... oldState.get('_val', 0))
... return oldState
...
from persistent import Persistent
class PCounter(Persistent):
'`value` is readonly; increment it with `inc`.'
_val = 0
def inc(self):
self._val += 1
@property
def value(self):
return self._val
def _p_resolveConflict(self, oldState, savedState, newState):
oldState['_val'] = (
savedState.get('_val', 0) +
newState.get('_val', 0) -
oldState.get('_val', 0))
return oldState
.. -> src
>>> import ConflictResolution_txt
>>> exec src in ConflictResolution_txt.__dict__
>>> PCounter = ConflictResolution_txt.PCounter
>>> PCounter.__module__ = 'ConflictResolution_txt'
By "state", the excerpt above means the value used by __getstate__ and
__setstate__: a dictionary, in most cases. We'll look at more details below,
......@@ -174,16 +181,21 @@ DANGERS: The changes you make to the instance will be discarded. The
instance is not initialized, so other methods that depend on instance
attributes will not work.
Here's an example of a broken _p_resolveConflict method.
Here's an example of a broken _p_resolveConflict method::
>>> class PCounter2(PCounter):
... def __init__(self):
... self.data = []
... def _p_resolveConflict(self, oldState, savedState, newState):
... self.data.append('bad idea')
... return super(PCounter2, self)._p_resolveConflict(
... oldState, savedState, newState)
...
class PCounter2(PCounter):
def __init__(self):
self.data = []
def _p_resolveConflict(self, oldState, savedState, newState):
self.data.append('bad idea')
return super(PCounter2, self)._p_resolveConflict(
oldState, savedState, newState)
.. -> src
>>> exec src in ConflictResolution_txt.__dict__
>>> PCounter2 = ConflictResolution_txt.PCounter2
>>> PCounter2.__module__ = 'ConflictResolution_txt'
Now we'll prepare for the conflict again.
......@@ -387,6 +399,12 @@ BTree Buckets and Sets, each with conflict resolution, needs to think
through these kinds of problems or be faced with potential data
integrity issues.
.. cleanup
>>> db.close()
>>> db1.close()
>>> db2.close()
.. ......... ..
.. FOOTNOTES ..
.. ......... ..
......@@ -394,16 +412,24 @@ integrity issues.
.. [#get_persistent_reference] We'll catch persistent references with a class
mutable.
>>> class PCounter3(PCounter):
... data = []
... def _p_resolveConflict(self, oldState, savedState, newState):
... PCounter3.data.append(
... (oldState.get('other'),
... savedState.get('other'),
... newState.get('other')))
... return super(PCounter3, self)._p_resolveConflict(
... oldState, savedState, newState)
...
::
class PCounter3(PCounter):
data = []
def _p_resolveConflict(self, oldState, savedState, newState):
PCounter3.data.append(
(oldState.get('other'),
savedState.get('other'),
newState.get('other')))
return super(PCounter3, self)._p_resolveConflict(
oldState, savedState, newState)
.. -> src
>>> exec src in ConflictResolution_txt.__dict__
>>> PCounter3 = ConflictResolution_txt.PCounter3
>>> PCounter3.__module__ = 'ConflictResolution_txt'
>>> p3_A = conn_A.root()['p3'] = PCounter3()
>>> p3_A.other = conn_A.root()['p']
>>> tm_A.commit()
......
......@@ -287,6 +287,12 @@ possible. If historical connections are used for conflict resolution, these
connections will probably be temporary--not saved in a pool--so that the extra
memory usage would also be brief and unlikely to overlap.
.. cleanup
>>> db.close()
>>> db2.close()
.. ......... ..
.. Footnotes ..
.. ......... ..
......
......@@ -11,33 +11,30 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
import manuel.doctest
import manuel.footnote
import manuel.capture
import manuel.testing
import unittest
from zope.testing import doctest, module
import ZODB.ConflictResolution
import ZODB.tests.util
import zope.testing.module
def setUp(test):
ZODB.tests.util.setUp(test)
module.setUp(test, 'ConflictResolution_txt')
zope.testing.module.setUp(test, 'ConflictResolution_txt')
def tearDown(test):
test.globs['db'].close()
test.globs['db1'].close()
test.globs['db2'].close()
module.tearDown(test)
zope.testing.module.tearDown(test)
ZODB.tests.util.tearDown(test)
ZODB.ConflictResolution._class_cache.clear()
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('../ConflictResolution.txt',
setUp=setUp,
tearDown=tearDown,
optionflags=doctest.INTERPRET_FOOTNOTES,
),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
return manuel.testing.TestSuite(
manuel.doctest.Manuel()
+ manuel.footnote.Manuel()
+ manuel.capture.Manuel(),
'../ConflictResolution.txt',
setUp=setUp, tearDown=tearDown,
)
......@@ -11,33 +11,14 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
import unittest
from zope.testing import doctest, module
import manuel.doctest
import manuel.footnote
import manuel.testing
import ZODB.tests.util
def setUp(test):
ZODB.tests.util.setUp(test)
module.setUp(test, 'historical_connections_txt')
def tearDown(test):
test.globs['db'].close()
test.globs['db2'].close()
# the DB class masks the module because of __init__ shenanigans
module.tearDown(test)
ZODB.tests.util.tearDown(test)
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('../historical_connections.txt',
setUp=setUp,
tearDown=tearDown,
optionflags=doctest.INTERPRET_FOOTNOTES,
),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
return manuel.testing.TestSuite(
manuel.doctest.Manuel() + manuel.footnote.Manuel(),
'../historical_connections.txt',
setUp=ZODB.tests.util.setUp, tearDown=ZODB.tests.util.tearDown,
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment