Skip to content

Commit

Permalink
Don't clear the slots/dict when adding a new_ghost to Python
Browse files Browse the repository at this point in the history
PickleCache.

Fixes #49.

Unfortunately, this doesn't fix the whole problem, because
_p_deactivate() still clears them, and so we lose what we set in __new__.
  • Loading branch information
jamadden committed Dec 19, 2016
1 parent d63fde7 commit de9f3f2
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
2 changes: 1 addition & 1 deletion persistent/picklecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from persistent.interfaces import IPickleCache
from persistent.interfaces import OID_TYPE
from persistent.interfaces import UPTODATE
from persistent import Persistent
from persistent.persistence import Persistent
from persistent.persistence import _estimated_size_in_24_bits

# Tests may modify this to add additional types
Expand Down
52 changes: 52 additions & 0 deletions persistent/tests/test_persistence.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def _makeCache(self, jar):
# concrete testcase classes must override
raise NotImplementedError()

def _makeRealCache(self, jar):
return self._makeCache(jar)

def _makeOne(self, *args, **kw):
return self._getTargetClass()(*args, **kw)

Expand Down Expand Up @@ -1599,6 +1602,51 @@ def _p_deactivate(self):
p._p_invalidate()
self.assertTrue(p.deactivated)


def test_new_ghost_success_not_already_ghost_dict(self):
# https://github.com/zopefoundation/persistent/issues/49
# calling new_ghost on an object that already has state just changes
# its flags, it doesn't destroy the state.
from persistent.interfaces import GHOST
from persistent.interfaces import UPTODATE
class TestPersistent(self._getTargetClass()):
pass
KEY = b'123'
jar = self._makeJar()
cache = self._makeRealCache(jar)
candidate = TestPersistent()

candidate.set_by_new = 1
self.assertEqual(candidate._p_state, UPTODATE)
cache.new_ghost(KEY, candidate)

self.assertTrue(cache.get(KEY) is candidate)
self.assertEqual(candidate._p_oid, KEY)
self.assertEqual(candidate._p_state, GHOST)
self.assertEqual(candidate.set_by_new, 1)

def test_new_ghost_success_not_already_ghost_slot(self):
# https://github.com/zopefoundation/persistent/issues/49
# calling new_ghost on an object that already has state just changes
# its flags, it doesn't destroy the state.
from persistent.interfaces import GHOST
from persistent.interfaces import UPTODATE
class TestPersistent(self._getTargetClass()):
__slots__ = ('set_by_new', '__weakref__')
KEY = b'123'
jar = self._makeJar()
cache = self._makeRealCache(jar)
candidate = TestPersistent()
candidate.set_by_new = 1
self.assertEqual(candidate._p_state, UPTODATE)
cache.new_ghost(KEY, candidate)

self.assertTrue(cache.get(KEY) is candidate)
self.assertEqual(candidate._p_oid, KEY)
self.assertEqual(candidate._p_state, GHOST)
self.assertEqual(candidate.set_by_new, 1)


class PyPersistentTests(unittest.TestCase, _Persistent_Base):

def _getTargetClass(self):
Expand Down Expand Up @@ -1627,6 +1675,10 @@ def update_object_size_estimation(self, oid, new_size):

return _Cache(jar)

def _makeRealCache(self, jar):
from persistent.picklecache import PickleCache
return PickleCache(jar, 10)

def _checkMRU(self, jar, value):
self.assertEqual(list(jar._cache._mru), value)

Expand Down
4 changes: 3 additions & 1 deletion persistent/tests/test_picklecache.py
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,9 @@ def _p_invalidate(self):
self._p_state = GHOST

_p_deactivate = _p_invalidate
_p_invalidate_deactivate_helper = _p_invalidate

def _p_invalidate_deactivate_helper(self, clear=True):
self._p_invalidate()

def _p_activate(self):
from persistent.interfaces import UPTODATE
Expand Down

0 comments on commit de9f3f2

Please sign in to comment.