Re: [sqlalchemy] Inheriting custom collection to create another custom collection. Issues with the appenders/parents

2010-11-15 Thread Hector Blanco
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

2010-11-13 Thread jason kirtland
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 

[sqlalchemy] Inheriting custom collection to create another custom collection. Issues with the appenders/parents

2010-11-12 Thread Hector Blanco
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 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