title: Using a custom collection extending from a dict() with SqlAlchemy
body: <p>I'm trying to use a custom collection to "connect" (or relate) two classes but I haven't been able to do it. Maybe I got the whole concept of the <a href="http://www.sqlalchemy.org/docs/orm/collections.html#custom-collection-implementations" rel="nofollow" title="SqlAlchemy custom collections">SqlAlchemy custom collections</a> wrong, but let me explain what I am doing (and see if someone can give me a hint, or something)</p>
  
  <p>I have a Parent class (which some of you will remember from other questions) with a couple of connectors fields (kind of lists) in it. One of the connectors will store instances of a Child() class whose type is "<em>VR</em>" and the other will store children with a "<em>CC</em>" type.</p>
  
  <p>I don't really need persistence for the collection used to store the children, but I need it to be of an special class so it will have some methods that I have implemented and that need to be there. That would be the "<em>ZepConnector</em>" class (and, for purposes of the example, it's method foo() is the one I need to use). As you can see in the following lines, I randomly test its availability in the addChild1() method of the Parent.</p>
  
  <p>--------------------- Parent.py -----------------</p>
  
  <pre><code>from megrok import rdb
  from sqlalchemy import Column
  from sqlalchemy import and_
  from sqlalchemy.orm import relationship
  from sqlalchemy.types import Integer
  from sqlalchemy.types import String
  from mylibraries.database.tests.Child import Child
  from mylibraries.database.tests.Tables import testMetadata
  from mylibraries.database.tests.ZepConnector import ZepConnector
  
  class Parent(rdb.Model):
      rdb.metadata(testMetadata)
      rdb.tablename("parents_table")
      rdb.tableargs(schema='test2', useexisting=False)
  
      id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
      _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
      _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
  
      child1 = relationship(
          "Child",
          uselist=True,
          primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "VR")),
          collection_class=ZepConnector("VR")
          )
  
      child2 = relationship(
          "Child",
          uselist=True,
          primaryjoin=lambda: and_((Parent.id == Child.parent_id), (Child.type == "CC")),
          collection_class=ZepConnector("CC")
          )
  
      def __init__(self):
          print "Parent __init__"
          self._whateverField1 = "Whatever1"
          self._whateverField2 = "Whatever2"
          self.child1 = ZepConnector("VR")
          self.child2 = ZepConnector("CC")
  
      def addChild1(self, child):
          if isinstance(child, Child):
              print("::addChild1 &gt; Testing .foo method: " + str(self.child1.foo()))
              # The line above doesn't really makes much 
              # but testing the accessibility of the .foo() method.
              # As I'll explain later, it doesn't work
              self.child1.append(child)
  
      def addChild2(self, child):
          if isinstance(child, Child):
              self.child2.append(child)
  </code></pre>
  
  <hr>
  
  <p>Please note that I'm using megrok. For those who are not familiar with it, allow me to explain that it is just a tool that maps the Python class to an SqlAlchemy mapper itself and makes it a little bit more "<em>programmer friendly</em>" when using the <a href="http://en.wikipedia.org/wiki/Grok_%28web_framework%29" rel="nofollow" title="Grok framework">Grok framework</a>.</p>
  
  <p>I guess The mapping of the Parent() class in regular SqlAlchemy would resemble something like:</p>
  
  <pre><code>mapper(Parent, parents_table, properties={
      id = Column("id", Integer, primary_key=True, nullable=False, unique=True)
      _whateverField1 = Column("whatever_field1", String(16)) #Irrelevant
      _whateverField2 = Column("whatever_field2", String(16)) #Irrelevant
      child1 = relationship( # etc, etc, etc
  })
  #
  </code></pre>
  
  <p>but I'm 100%... erm... 90%... erm... 70% certain that using that tool is not what lead me to ask what I'm going to ask here (I mean: I don't think is interfering with the SqlAlchemy Custom Collections thing)</p>
  
  <p>A child is a very simple class:</p>
  
  <p>--------------- Child.py --------------------------</p>
  
  <pre><code>import random
  
  from megrok import rdb
  from sqlalchemy import Column
  from sqlalchemy import ForeignKey
  from sqlalchemy.types import Integer
  from sqlalchemy.types import String
  from mylibraries.database.tests.Tables import testMetadata
  
  class Child(rdb.Model):
      rdb.metadata(testMetadata)
      rdb.tablename("children_table")
      rdb.tableargs(schema='test2', useexisting=False)
  
      parent_id = Column("parent_id", Integer, ForeignKey("test2.parents_table.id"), primary_key=True)
      type = Column("type", String(2), nullable=True, primary_key=True)
      hasher = Column("hasher", String(5))
  
      def __init__(self):
          self.type = None
          self.hasher = self.generateHasher()
  
      def setType(self, typeParameter):
          if typeParameter in set(["VR", "CC"]):
              self.type = typeParameter
  
      @staticmethod
      def generateHasher():
          retval = str()
          for i in random.sample('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 5):
              retval += i
          return retval
  </code></pre>
  
  <hr>
  
  <p>Let's say every Child instance will have a unique "hasher" field that can be used as a key in a dictionary (the example above is far away from the reality, but it illustrates a little bit how the Child will work and for being able to create a test)</p>
  
  <p>And now my custom connector. I want it to behave as a <em>list</em> or a <em>set</em> (more like a <em>set</em>, although I don't mind much) but it's a class that inherits from dict.</p>
  
  <p>-------------------- ZepConnector.py --------------------</p>
  
  <pre><code>from sqlalchemy.orm.collections import collection
  
  class ZepConnector(dict):
      __emulates__ = list
  
      def __init__(self, type):
          self.type = type 
          # The 'type' will be "VR" or "CC" and it will be stamped
          # on every Child() class added through this ZepConnector
  
      def foo(self):
          return True
  
      @collection.appender
      def append(self, item):
          #Appends a child to itself
          if self.foo():
              item.setType(self.type)
              self[item.hasher] = item
  
      @collection.remover
      def remove(self, item):
          try:
              del self[item.hasher]
          except ValueError, e:
              print("::remove &gt; Got exception when trying to remove entry=" + str(item.hasher) + ". The exception is: " + str(e))
  
      def extend(self, items):
          pass
  </code></pre>
  
  <hr>
  
  <p>But I don't know why, the "ZepConnector" instances in the Parent class don't seem to be of a "<em>ZepConnector</em>" type but of an "<em>InstrumentedList</em>":</p>
  
  <p>When in the addChild1 method of Parent() I try to test the .foo() method (which should just print "True") I get this error:</p>
  
  <pre><code>AttributeError: 'InstrumentedList' object has no attribute 'foo'
  </code></pre>
  
  <p>Showing whole traceback:</p>
  
  <pre><code>Traceback (most recent call last):
    File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 134, in publish
      result = publication.callObject(request, obj)
    File "/home/ae/mytests-cms/grokserver/eggs/grok-1.1rc1-py2.4.egg/grok/publication.py", line 89, in callObject
      return super(ZopePublicationSansProxy, self).callObject(request, ob)
    File "/home/ae/mytests-cms/grokserver/eggs/zope.app.publication-3.10.2-py2.4.egg/zope/app/publication/zopepublication.py", line 205, in callObject
      return mapply(ob, request.getPositionalArguments(), request)
    File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
      return debug_call(obj, args)
    File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
      return obj(*args)
    File "/home/ae/mytests-cms/grokserver/eggs/grokcore.view-1.13.2-py2.4.egg/grokcore/view/components.py", line 101, in __call__
      return mapply(self.render, (), self.request)
    File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 109, in mapply
      return debug_call(obj, args)
    File "/home/ae/mytests-cms/grokserver/eggs/zope.publisher-3.12.0-py2.4.egg/zope/publisher/publish.py", line 115, in debug_call
      return obj(*args)
    File "/home/ae/mytests-cms/grokserver/src/grokserver/app.py", line 1575, in render
      mylibraries.database.tests.Test.runWholeTest()
    File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 54, in runWholeTest
      __test()
    File "/home/ae/mytests-cms/mylibraries/database/tests/Test.py", line 35, in __test
      parent.addChild1(child)
    File "/home/ae/mytests-cms/mylibraries/database/tests/Parent.py", line 54, in addChild1
      print("::addChild1 &gt; Testing .foo method: " + str(self.child1.foo()))
  AttributeError: 'InstrumentedList' object has no attribute 'foo'
  Debug at: http://127.0.0.1:8080/_debug/view/1289342582
  </code></pre>
  
  <p>It's strange... The <strong>init</strong> method of the ZepConnector is properly executed... but when I try to use it, it doesn't seem to be ZepConnector...</p>
  
  <p>I did a couple of more tests, but all unsuccessful:</p>
  
  <p>In a second try I wrote:</p>
  
  <pre><code>class ZepConnector(dict):
      __emulates__ = set
  </code></pre>
  
  <p>but this even makes things worse, because I get:</p>
  
  <pre><code>TypeError: Incompatible collection type: ZepConnector is not list-like
  </code></pre>
  
  <p>In a third (or second point two) try, I though... "well... if it's saying that ZepConnector is not a list, maybe telling the Parent() not to use a list in the relationship may help... Maybe stating that the collection_class is a ZepConnector makes ynnecessary the uselist parameter in the relationship..."</p>
  
  <p>And so I wrote:</p>
  
  <pre><code>child1 = relationship(
      "Child",
      uselist = False,
      primaryjoin=lambda: and_((Parent.id == Child.parent_id),(Child.type == "VR")),
      collection_class=ZepConnector("VR")
      )
  </code></pre>
  
  <p>But that threw a creepy exception talking about a field which I shouldn't see and that I don't want to see... ever... <strong>:-D</strong></p>
  
  <pre><code>AttributeError: 'ZepConnector' object has no attribute '_sa_instance_state'
  </code></pre>
  
  <p>I am using Python2.4 and SqlAlchemy 0.6.6, just in case it's relevant.</p>
  
  <p>If someone has any ideas, guidance, counseling... whatever... I'd really appreciate you sharing it with me... erm... us...</p>
  
  <p>Thank you in advance!</p>
  
  <p>(if you have reached this line, you certainly deserve a "thank you" just for your patience reading this huge post)</p>