For my application, I need to be able to export a set of objects from a Durus database. So far I've been converting objects into an S-expression-based shorthand form, writing it out, and creating new objects after reading the S-expressions. This is high-maintenance, though: add a new attribute, and you also have to update the S-expr output code and the input code. pickle doesn't seem to work on objects that subclass Persistent: should I expect it to work? Can I make it work? As an experiment I wrote the copying function below; it tries to find the closure of all objects referenced by a starting object. These objects then have their _p_oid and _p_connection zapped, and are stored in a new connection. It seems to work on a little example. * Is the approach taken pure evil, or only slightly naughty? * Is the code's usage of Durus functions correct in all particulars? * Should this function be added to Durus? --amk # Ignore this stuff... this is application-specific. import os from ACE_model import get_model, get_connection m = get_model('small') print m # Here's the actual function from durus import serialize, connection, file_storage def copy_obj (obj): """Copies the object 'obj' into a new FileStorage, including all required objects. """ conn = obj._p_connection ow = serialize.ObjectWriter(conn) root_oid = obj._p_oid queue = [root_oid] oid_coll = {} while len(queue): oid = queue.pop(0) if oid in oid_coll: continue # Get object for this OID obj = conn.get(oid) if obj is None: ##print 'no object with oid', repr(oid) continue oid_coll[oid] = obj # Ensure object is loaded if obj._p_is_ghost(): conn.load_state(obj) # Get OIDs referenced by this object and add them to the queue data, refs = ow.get_state(obj) refs = serialize.split_oids(refs) queue.extend(refs) # Need to put this in a try/finally w/ preceding block ow.close() print len(oid_coll), 'objects' # Copy those objects to new storage try: os.unlink('/tmp/new-fs') except os.error: pass fs = file_storage.FileStorage('/tmp/new-fs') conn2 = connection.Connection(fs) root = conn2.get_root() # Clear _p_ attributes # (should probably clear the original connection's cache after doing this) for obj in oid_coll.values(): obj._p_oid = obj._p_connection = None # Store object in new storage root['copy'] = oid_coll[root_oid] # Commit it and close the FileStorage conn2.commit() del conn2 fs.close() # Make initial copy s = copy_obj(m) # Rename file storage os.rename('/tmp/new-fs', '/tmp/original-fs') fs = file_storage.FileStorage('/tmp/original-fs') # Get copy, and try copying it again conn2 = connection.Connection(fs) root = conn2.get_root() m2 = root['copy'] print m2 m2.dump() copy_obj(m2)