The general forms of "table inheritance" that SQLAlchemy supports
directly are described here: http://www.sqlalchemy.org/docs/05/mappers.html#advdatamapping_mapper_inheritance
.
i am not sure i understand what u want, but here's my
baseDBclass.copy() method.
[ sidenote:
if u talk about real value inheritance/shading, that is different
quite complex beast, i have that too. e.g. A.x, B.x are values, B.a
points to some A, and Bs are before As in the value-inheritance
chain, so if A1.x=2, B1.a=A1 and B1.x=5, then inherited( B1.x) = 5
(e.g. shading); while if B1.x has no value, then inherited( B1.x)= 2
(e.g. inheritance or see-through).
]
here, i have objects with bitemporal versions, with bitemporal
many2many associations for most relations, hence any new version is a
semi-deep copy of previous + the modifications on top of that.
u can use this below as pseudocode/starting point to write your own -
plz ignore anything that makes no sense to you, or substitute with
your stuff of same meaning if u have such.
basicaly, logic is to copy all plain attributes and references, then
walk all relations and copy those, with the special case of explicit
associations, where the backlink of the copy of each member should be
explicitly set to the new owner.
Each item (plain or relation-member) is checked if it has to be
depth-copied or not.
class _NOTFOUND: pass
class Struct( _Base, ....):
dont_copy = [] # set of attr-names to ignore when copying;
#when inheriting dont miss the base set
dont_copy_me = False #copy as reference, not in depth;
# the copy wil refer same object
def copy( me, dont_copy_now =()):
if dbg: print l, 'copying', me
new = me.__class__()
#singulars
done = set()
for walker in [ me._walkTypes(), me._DBCOOK_references ]:
for name in walker:
if name in done: continue
done.add( name)
if name in dont_copy_now or name in me.dont_copy:
if dbg: print l, ' ignore', name
continue
item = getattr( me, name, _NOTFOUND)
if item is _NOTFOUND: #nothing to copy
if dbg: print l, ' ignore/novalue', name
continue
i0 = item
if not getattr( item, 'dont_copy_me', None):
vcopy = getattr( item, 'copy', None)
if callable( vcopy):
if dbg: print l, ' copy-deep', name, item
item = vcopy()
if dbg:
if i0 is item: print l, ' copy-ref', name
print l, ' copied', name, '=', item
setattr( new, name, item)
#maybe rels = [ p in class_mapper(klas).props if p.uselist ]
rels = getattr( me, '_DBCOOK_relations', () )
for name in rels:
if name in dont_copy_now or name in me.dont_copy:
if dbg: print l, ' ignore', name
continue
#make deep-copy of the set = set of copies of each item
child_klas = rels[ name]
if dbg: print l, ' copy-relation', name, ':', child_klas
children = getattr( me, name) #XXX this can load all!!
new_children = getattr( new, name)
explicit_assoc=not getattr( child_klas, 'DBCOOK_hidden',
True)
ab = about_relation( me.__class__, name)
attr = ab.otherside.name
for a in children:
#3 cases: non-assoc (nocopy), assoc.hidden (nocopy),
# assoc.explicit:copy
if explicit_assoc:
if dbg: print ' copy-deep-assoc', a
assert getattr( a, attr) is me
a = a.copy( dont_copy_now= [attr] )
if ab.no_backref:
if dbg: print ' replace', attr, new
setattr( a, attr, new)
else:
if dbg: print ' copy-ref'
if dbg: print ' copied-over', a
new_children.append( a )
if dbg: print l, ' copied-relation', name, new_children
return new