Re: [sqlalchemy] Inheriting custom collection to create another custom collection. Issues with the appenders/parents
Thanks for your interest! And yeah... sorry for the typos... I was writing the code right in the email... I'm afraid I won't be able to test it until December 1 but make sure as soon as I get my hands on the computer where that problem was happening, I'll test it. I really appreciate your effort! :) I'll keep you posted! 2010/11/13 jason kirtland j...@discorporate.us: Hi Hector, On Fri, Nov 12, 2010 at 7:46 AM, Hector Blanco white.li...@gmail.com wrote: Hello everyone. I was wondering if it's possible to inherit a custom collection to create another custom collection. A few days ago I was trying to use my own class as a custom_collection (http://groups.google.com/group/sqlalchemy/msg/ba1c64c3d227f586). Thanks to Michael Bayer I was able to do it, but now I would like to go one step further, and inherit my custom collection to create another custom collection. To simplify a little what I asked in the other message, let's say I have a: def ClassA(declarativeBase): __tablename__ = aes id = Column(id, Integer, primary_key=True) _whatever = Column(type, String(64)) def __init__(self): self._whatever = whatever Then I have my custom collection for instances of ClassA: def ContainerOfA(dict): __emulates__ = set def __init__(self): self._field = I'm a great... awesom! container #I also defined the appender, remover and iterator �...@collection.iterator def __iter__(self): return self.itervalues() �...@collection.appender def append(self, item): self[item.getUniqueHash()] = item �...@collection.remover def remove(self, item): if item.getUniqueHash() in self.keys(): del self[item.getUniqueHash()] And then I was happily able to use it in any relationships: def YetAnotherClass(declarativeBase): id = Column(id, Integer, primary_key=True) classesA = relationship(ClassA, uselist=True, secondary=intermediate_table, collection_class=lambda: ContainerOfA(), cascade=all, delete, delete-orphan, single_parent=True ) Now I needed to extend ClassA in a Class B and ContainerOfA in ContainerOfB. I added the polymorphic stuff to ClassA and ClassB to create a joined table inheritance, as detailed in http://www.sqlalchemy.org/docs/orm/inheritance.html#joined-table-inheritance . (it seems to be working fine, that's why I am not completely detailing it here) def ClassB(ClassA): __tablename__ = bs #Sorry for that __mapper_args__ = {'polymorphic_identity': 'ClassB'} id = Column(id, Integer, ForeignKey('aes.id'), primary_key=True) def __init__(self): self._anotherWhatever = another whatever def ContainerOfB(ContainerOfA): def __init__(self): super(ContainerOfB, self).__init__() def anotherMethodOnlyForBInstances(self): # do interesting stuff for B classes Then I tried to use it in a relationship: def YetYetAnotherClass(declarativeBase): id = Column(id, Integer, primary_key=True) classesB = relationship(ClassB, uselist=True, secondary=another_intermediate_table, collection_class=lambda: ContainerOfB(), cascade=all, delete, delete-orphan, single_parent=True ) But when I tried to append a ClassB instance through the relationship detailed above, I got this exception: Type ContainerOfB must elect an appender method to be a collection class I haven't been able to replicate this behavior. When testing your code I did notice that you are using 'def' to declare your classes, which won't actually create the type. I make that same typo myself periodically and it can be quite tricky to track down the one def'd class that's causing seemingly unrelated errors. Anyhow, I've attached the working test case I put together. If you can modify this to replicate your behavior, we can track down any bugs that might be present in the collection API's appender metadata bookkeeping. You definitely should not have to re-declare an @appender on a subclass- the collection mechanics should be sweeping over your inherited class and transparently picking up the methods. This is definitely working for the cases in the SQLA unit tests, but it's definitely possible you've found some corner case with that dict that's declared to be emulating a set. Cheers, Jason I thought... ok, ok... let's just explicitly add the 'appender' to the ContainerOfB class... The only thing I need to do is calling the appender of the super class, anyway... no biggie and so I did: def ContainerOfB(ContainerOfA): # [ . . . ] # �...@collection.appender def append(self, classBInstance):
Re: [sqlalchemy] Inheriting custom collection to create another custom collection. Issues with the appenders/parents
Hi Hector, On Fri, Nov 12, 2010 at 7:46 AM, Hector Blanco white.li...@gmail.com wrote: Hello everyone. I was wondering if it's possible to inherit a custom collection to create another custom collection. A few days ago I was trying to use my own class as a custom_collection (http://groups.google.com/group/sqlalchemy/msg/ba1c64c3d227f586). Thanks to Michael Bayer I was able to do it, but now I would like to go one step further, and inherit my custom collection to create another custom collection. To simplify a little what I asked in the other message, let's say I have a: def ClassA(declarativeBase): __tablename__ = aes id = Column(id, Integer, primary_key=True) _whatever = Column(type, String(64)) def __init__(self): self._whatever = whatever Then I have my custom collection for instances of ClassA: def ContainerOfA(dict): __emulates__ = set def __init__(self): self._field = I'm a great... awesom! container #I also defined the appender, remover and iterator �...@collection.iterator def __iter__(self): return self.itervalues() �...@collection.appender def append(self, item): self[item.getUniqueHash()] = item �...@collection.remover def remove(self, item): if item.getUniqueHash() in self.keys(): del self[item.getUniqueHash()] And then I was happily able to use it in any relationships: def YetAnotherClass(declarativeBase): id = Column(id, Integer, primary_key=True) classesA = relationship(ClassA, uselist=True, secondary=intermediate_table, collection_class=lambda: ContainerOfA(), cascade=all, delete, delete-orphan, single_parent=True ) Now I needed to extend ClassA in a Class B and ContainerOfA in ContainerOfB. I added the polymorphic stuff to ClassA and ClassB to create a joined table inheritance, as detailed in http://www.sqlalchemy.org/docs/orm/inheritance.html#joined-table-inheritance . (it seems to be working fine, that's why I am not completely detailing it here) def ClassB(ClassA): __tablename__ = bs #Sorry for that __mapper_args__ = {'polymorphic_identity': 'ClassB'} id = Column(id, Integer, ForeignKey('aes.id'), primary_key=True) def __init__(self): self._anotherWhatever = another whatever def ContainerOfB(ContainerOfA): def __init__(self): super(ContainerOfB, self).__init__() def anotherMethodOnlyForBInstances(self): # do interesting stuff for B classes Then I tried to use it in a relationship: def YetYetAnotherClass(declarativeBase): id = Column(id, Integer, primary_key=True) classesB = relationship(ClassB, uselist=True, secondary=another_intermediate_table, collection_class=lambda: ContainerOfB(), cascade=all, delete, delete-orphan, single_parent=True ) But when I tried to append a ClassB instance through the relationship detailed above, I got this exception: Type ContainerOfB must elect an appender method to be a collection class I haven't been able to replicate this behavior. When testing your code I did notice that you are using 'def' to declare your classes, which won't actually create the type. I make that same typo myself periodically and it can be quite tricky to track down the one def'd class that's causing seemingly unrelated errors. Anyhow, I've attached the working test case I put together. If you can modify this to replicate your behavior, we can track down any bugs that might be present in the collection API's appender metadata bookkeeping. You definitely should not have to re-declare an @appender on a subclass- the collection mechanics should be sweeping over your inherited class and transparently picking up the methods. This is definitely working for the cases in the SQLA unit tests, but it's definitely possible you've found some corner case with that dict that's declared to be emulating a set. Cheers, Jason I thought... ok, ok... let's just explicitly add the 'appender' to the ContainerOfB class... The only thing I need to do is calling the appender of the super class, anyway... no biggie and so I did: def ContainerOfB(ContainerOfA): # [ . . . ] # �...@collection.appender def append(self, classBInstance): return super(ContainerOfB, self).append(classBInstance) But then... another exception when I tried to add an instance of ClassB(): InvalidRequestError: Instance ClassB at 0xba9726c is already associated with an instance of class 'mylibraries.classesTest.YetYetAnotherClass' via its YetYetAnotherClass.classesB attribute, and is only allowed a single parent. Well... I need