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): >> 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 the cascade to properly delete the items >> (http://www.sqlalchemy.org/docs/orm/session.html#deleting) and in >> order to use that, I need the single_parent = True. >> >> Then funny thing is that if I totally rewrite the appender method in >> ContainerOfB: >> >> def ContainerOfB(ContainerOfA): >> # [ . . . ] # >> �...@collection.appender >> def append(self, classBInstance): >> # write here the exact same code than ContainerOfA changing >> # the reference to the "item" parameter by "classBInstance" >> # (that's the only difference) >> >> then everything is working fine. I have made some more tests, and the >> inheritance ClassA <- ClassB seems to be working fine. In said tests I >> removed the "cascade" and the "single_parent" parameters of the >> "classesB" relationship. By doing that, I was able to insert instances >> of ClassB in the classesB container and all the information was >> properly stored in the database (the polymorphic identity was added >> properly, the foreign key of the ClassB() instance was properly >> pointing to its "parent" class "ClassA"'s id, all the fields were >> there... perfect!). The problem seems to come when I try to use the >> "single_parent = True" with my inherited ContainerOfB class. >> >> As far as I can tell (and I may be totally wrong) it seems to me that >> somehow, calling the "super - appender" appends the instance twice. I >> thought that because rewriting the whole "append" method in my >> ContainerOfB fixed the problem. But that is not "perfect". In regular >> OOP I don't need to do that. Is there any way to fix that? Am I >> missing something? (sorry... let me rephrase it: "What am I missing?", >> because, newbie as I am, I'm sure I'm doing something wrong) >> >> Reading the custom collections chapter >> (http://www.sqlalchemy.org/docs/orm/collections.html#instrumentation-and-custom-types), >> I found: >> >> """ >> However, it is important to note that the instrumentation process >> _will_ modify the type, adding decorators around methods >> automatically. >> """ >> >> I don't know if this is what is affecting my code, but if so, I >> haven't been able to find a better workaround than rewriting the >> "append" method. >> >> Any hint will be appreciated! Thank you in advance! >> >> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To post to this group, send email to sqlalch...@googlegroups.com. >> To unsubscribe from this group, send email to >> sqlalchemy+unsubscr...@googlegroups.com. >> For more options, visit this group at >> http://groups.google.com/group/sqlalchemy?hl=en. >> >> > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to sqlalch...@googlegroups.com. > To unsubscribe from this group, send email to > sqlalchemy+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.