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.

Reply via email to