Commit 8dbdceec authored by Jim Fulton's avatar Jim Fulton

Fixed the last fix and fixed the test that failed to show the need for

the fix fix.
parent 0cd1074f
......@@ -29,7 +29,7 @@ ResolvedSerial = 'rs'
class BadClassName(Exception):
pass
class BadClass:
class BadClass(object):
def __init__(self, *args):
self.args = args
......@@ -123,13 +123,13 @@ class PersistentReference(object):
self.data = data
# see serialize.py, ObjectReader._persistent_load
if isinstance(data, tuple):
self.oid, self.klass = data
if isinstance(self.klass, BadClass):
self.oid, klass = data
if isinstance(klass, BadClass):
# We can't use the BadClass directly because, if
# resolution succeeds, there's no good way to pickle
# it. Fortunately, a class reference in a persistent
# reference is allowed to be a module+name tuple.
self.klass = self.klass.args
self.data = self.oid, klass.args
elif isinstance(data, str):
self.oid = data
else: # a list
......@@ -140,7 +140,7 @@ class PersistentReference(object):
# or persistent weakref: (oid, database_name)
# else it is a weakref: reference_type
if reference_type == 'm':
self.database_name, self.oid, self.klass = data[1]
self.database_name, self.oid, _ = data[1]
elif reference_type == 'n':
self.database_name, self.oid = data[1]
elif reference_type == 'w':
......@@ -173,6 +173,16 @@ class PersistentReference(object):
def __getstate__(self):
raise PicklingError("Can't pickle PersistentReference")
@property
def klass(self):
# for tests
data = self.data
if isinstance(data, tuple):
return data[1]
elif isinstance(data, list) and data[0] == 'm':
return data[1][2]
class PersistentReferenceFactory:
data = None
......
......@@ -158,6 +158,9 @@ def resolve_even_when_referenced_classes_are_absent():
We often want to be able to resolve even when there are pesistent
references to classes that can't be imported.
>>> class P(persistent.Persistent):
... pass
>>> db = ZODB.DB('t.fs') # FileStorage!
>>> storage = db.storage
>>> conn = db.open()
......@@ -166,20 +169,19 @@ references to classes that can't be imported.
>>> oid = conn.root.x._p_oid
>>> serial = conn.root.x._p_serial
>>> class P(persistent.Persistent):
... pass
>>> conn.root.x.a = a = P()
>>> conn.root.x.a = P()
>>> transaction.commit()
>>> aid = conn.root.x.a._p_oid
>>> serial1 = conn.root.x._p_serial
>>> del conn.root.x.a
>>> conn.root.x.b = b = P()
>>> conn.root.x.b = P()
>>> transaction.commit()
>>> serial2 = conn.root.x._p_serial
Bwahaha:
>>> P_aside = P
>>> del P
Now, even though we can't import P, we can still resolve the conflict:
......@@ -187,10 +189,18 @@ Now, even though we can't import P, we can still resolve the conflict:
>>> p = storage.tryToResolveConflict(
... oid, serial1, serial, storage.loadSerial(oid, serial2))
>>> p = conn._reader.getState(p)
>>> sorted(p), p['a'] is a, p['b'] is b
And load the pickle:
>>> conn2 = db.open()
>>> P = P_aside
>>> p = conn2._reader.getState(p)
>>> sorted(p), p['a'] is conn2.get(aid), p['b'] is conn2.root.x.b
(['a', 'b'], True, True)
>>> isinstance(p['a'], P) and isinstance(p['b'], P)
True
Oooooof course, this won't work if the subobjects aren't persistent:
>>> class NP:
......
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