hi folks,
i seem to be running into a bug or misconfiguration with sqlalchemy's tree
handling.. the table and mapping themselves seem fairly innocuous

concepts_table = Table("concepts", metadata,
                       Column("id", types.Integer, primary_key=True),
                       Column("name", types.Unicode, nullable=True),
                       Column("parent", types.Integer, ForeignKey("
concepts.id") )
                       )

class Concept( object ): pass

mapper(Concept, concepts_table, properties={
    'children': relation(Concept, cascade="all",
                         backref=backref("parent_node",
remote_side=[concepts_table.c.id]),

collection_class=attribute_mapped_collection('name'),
                         lazy=False, join_depth=3)})

the odd part is if i specify any join_depth i got an error, if i leave it
off its fine. i'm still curious to find out what causes the error and if its
a bug or just misconfiguration on my part.

i'm attaching a script which demonstrates the issue, and a contextual
traceback (ipython) of the error.


thanks,

kapil

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

    110 
    111 s = session.Session()
--> 112 for i in s.query( Concept ).all():
    113     print i.name
    114 

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
all(self)
    606         This results in an execution of the underlying query.
    607         """
--> 608         return list(self)
    609 
    610 

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
__iter__(self)
    654         if self._autoflush and not self._populate_existing:
    655             self.session._autoflush()
--> 656         return self._execute_and_instances(context)
    657 
    658     def _execute_and_instances(self, querycontext):

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
_execute_and_instances(self, querycontext)
    659         result = self.session.execute(querycontext.statement, 
params=self._params, mapper=self.mapper, instance=self._refresh_instance)
    660         try:
--> 661             return iter(self.instances(result, 
querycontext=querycontext))
    662         finally:
    663             result.close()

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
instances(self, cursor, *mappers_or_columns, **kwargs)
    720                 self.select_mapper._instance(context, 
self._primary_adapter(row), result, **primary_mapper_args)
    721             else:
--> 722                 self.select_mapper._instance(context, row, result, 
**primary_mapper_args)
    723             for proc in process:
    724                 proc[0](context, row)

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
_instance(self, context, row, result, skip_polymorphic, extension, 
only_load_props, refresh_instance)
   1453         flags = {'instancekey':identitykey, 'isnew':isnew}
   1454         if 'populate_instance' not in extension.methods or 
extension.populate_instance(self, context, row, instance, 
only_load_props=only_load_props, **flags) is EXT_CONTINUE:
-> 1455             self.populate_instance(context, instance, row, 
only_load_props=only_load_props, **flags)
   1456         if 'append_result' not in extension.methods or 
extension.append_result(self, context, row, instance, result, **flags) is 
EXT_CONTINUE:
   1457             if result is not None:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
populate_instance(self, selectcontext, instance, row, ispostselect, isnew, 
only_load_props, **flags)
   1541 
   1542         for (key, populator) in populators:
-> 1543             selectcontext.exec_with_path(self, key, populator, 
instance, row, ispostselect=ispostselect, isnew=isnew, **flags)
   1544 
   1545         if self.non_primary:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
exec_with_path(self, mapper, propkey, func, *args, **kwargs)
   1235         self.path += (mapper.base_mapper, propkey)
   1236         try:
-> 1237             return func(*args, **kwargs)
   1238         finally:
   1239             self.path = oldpath

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/strategies.py in 
execute(instance, row, isnew, **flags)
    605                         self.logger.debug("eagerload list instance on 
%s" % mapperutil.attribute_str(instance, self.key))
    606 
--> 607                     self.select_mapper._instance(selectcontext, 
decorated_row, result_list)
    608 
    609 

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
_instance(self, context, row, result, skip_polymorphic, extension, 
only_load_props, refresh_instance)
   1453         flags = {'instancekey':identitykey, 'isnew':isnew}
   1454         if 'populate_instance' not in extension.methods or 
extension.populate_instance(self, context, row, instance, 
only_load_props=only_load_props, **flags) is EXT_CONTINUE:
-> 1455             self.populate_instance(context, instance, row, 
only_load_props=only_load_props, **flags)
   1456         if 'append_result' not in extension.methods or 
extension.append_result(self, context, row, instance, result, **flags) is 
EXT_CONTINUE:
   1457             if result is not None:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
populate_instance(self, selectcontext, instance, row, ispostselect, isnew, 
only_load_props, **flags)
   1541 
   1542         for (key, populator) in populators:
-> 1543             selectcontext.exec_with_path(self, key, populator, 
instance, row, ispostselect=ispostselect, isnew=isnew, **flags)
   1544 
   1545         if self.non_primary:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
exec_with_path(self, mapper, propkey, func, *args, **kwargs)
   1235         self.path += (mapper.base_mapper, propkey)
   1236         try:
-> 1237             return func(*args, **kwargs)
   1238         finally:
   1239             self.path = oldpath

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/strategies.py in 
execute(instance, row, isnew, **flags)
    605                         self.logger.debug("eagerload list instance on 
%s" % mapperutil.attribute_str(instance, self.key))
    606 
--> 607                     self.select_mapper._instance(selectcontext, 
decorated_row, result_list)
    608 
    609 

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
_instance(self, context, row, result, skip_polymorphic, extension, 
only_load_props, refresh_instance)
   1453         flags = {'instancekey':identitykey, 'isnew':isnew}
   1454         if 'populate_instance' not in extension.methods or 
extension.populate_instance(self, context, row, instance, 
only_load_props=only_load_props, **flags) is EXT_CONTINUE:
-> 1455             self.populate_instance(context, instance, row, 
only_load_props=only_load_props, **flags)
   1456         if 'append_result' not in extension.methods or 
extension.append_result(self, context, row, instance, result, **flags) is 
EXT_CONTINUE:
   1457             if result is not None:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/mapper.py in 
populate_instance(self, selectcontext, instance, row, ispostselect, isnew, 
only_load_props, **flags)
   1541 
   1542         for (key, populator) in populators:
-> 1543             selectcontext.exec_with_path(self, key, populator, 
instance, row, ispostselect=ispostselect, isnew=isnew, **flags)
   1544 
   1545         if self.non_primary:

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/query.py in 
exec_with_path(self, mapper, propkey, func, *args, **kwargs)
   1235         self.path += (mapper.base_mapper, propkey)
   1236         try:
-> 1237             return func(*args, **kwargs)
   1238         finally:
   1239             self.path = oldpath

/Users/kapil/projects/piston/src/sqlalchemy/lib/sqlalchemy/orm/strategies.py in 
execute(instance, row, isnew, **flags)
    601                         # store it in the "scratch" area, which is 
local to this load operation.
    602                         selectcontext.attributes[('appender', 
id(instance), self.key)] = appender
--> 603                     result_list = selectcontext.attributes[('appender', 
id(instance), self.key)]
    604                     if self._should_log_debug:
    605                         self.logger.debug("eagerload list instance on 
%s" % mapperutil.attribute_str(instance, self.key))

<type 'exceptions.KeyError'>: ('appender', 17064688, 'children')
from sqlalchemy import Column, MetaData, Table, types, ForeignKey, Index, create_engine
from sqlalchemy.orm import mapper, relation, backref, session
from sqlalchemy.orm.collections import attribute_mapped_collection


metadata = MetaData()

concepts_table = Table("concepts", metadata,
                       Column("id", types.Integer, primary_key=True),
                       Column("name", types.Unicode, nullable=True),
                       Column("parent", types.Integer, ForeignKey("concepts.id") )
                       )
                       
class Concept( object ): pass
                       
mapper(Concept, concepts_table, properties={
    'children': relation(Concept, cascade="all",
                         backref=backref("parent_node", remote_side=[concepts_table.c.id]),
                         collection_class=attribute_mapped_collection('name'),
                         lazy=False, join_depth=3)})

db = create_engine('sqlite://', echo=True)

metadata.bind = db
metadata.drop_all()
metadata.create_all()

data = [
[ 3, u'Audiences', None ],
[ 4, u'External', 3 ],
[ 5, u'Media', 4 ],
[ 6, u'Vendors', 4 ],
[ 7, u'Researchers', 4 ],
[ 8, u'Grantees', 4 ],
[ 9, u'Government', 4 ],
[ 10, u'Managers', 9 ],
[ 11, u'Officials', 9 ],
[ 12, u'Educational', 4 ],
[ 13, u'Education product developers', 12 ],
[ 14, u'Educational Purposes', 12 ],
[ 15, u'Accessibility', 14 ],
[ 16, u'Educational level', 14 ],
[ 17, u'Disciplines', 14 ],
[ 18, u'Competency', 14 ],
[ 19, u'Skill level', 14 ],
[ 20, u'Prerequisites', 14 ],
[ 21, u'Restrictions', 14 ],
[ 22, u'Educational objectives', 14 ],
[ 23, u'Security level', 14 ],
[ 24, u'Ideas', 14 ],
[ 25, u'Educational Contexts', 12 ],
[ 26, u'School', 25 ],
[ 27, u'Training', 25 ],
[ 28, u'Higher education', 25 ],
[ 29, u'Students', 12 ],
[ 30, u'Middle School', 29 ],
[ 31, u'Graduate', 29 ],
[ 32, u'High School', 29 ],
[ 33, u'Post-graduate', 29 ],
[ 34, u'Undergraduate', 29 ],
[ 35, u'Adult', 29 ],
[ 36, u'Elementary School', 29 ],
[ 37, u'Managers', 12 ],
[ 38, u'Educators', 12 ],
[ 39, u'Educational Roles', 12 ],
[ 40, u'Contributors', 39 ],
[ 41, u'Validators', 40 ],
[ 42, u'Technical implementers', 40 ],
[ 43, u'Script writers', 40 ],
[ 44, u'Publishers', 40 ],
[ 45, u'Instructional designers', 40 ],
[ 46, u'Subject matter experts', 45 ],
[ 47, u'Graphic designers', 40 ],
[ 48, u'Educational validators', 40 ],
[ 49, u'Terminators', 40 ],
[ 50, u'Editors', 40 ],
[ 51, u'Technical validators', 40 ],
[ 52, u'Initiators', 40 ],
[ 53, u'End user roles', 39 ],
[ 54, u'Managers', 53 ],
[ 55, u'Students', 53 ],
[ 56, u'Middle School', 55 ],
[ 57, u'Graduate', 55 ],
[ 58, u'High School', 55 ],
[ 59, u'Post-graduate', 55 ],
[ 60, u'Undergraduate', 55 ],
[ 61, u'Adult', 55 ],
[ 62, u'Elementary School', 55 ],
[ 63, u'Educators', 53 ],
[ 64, u'Authors', 53 ],
[ 65, u'Parents', 12 ],
[ 66, u'General public', 4 ],
[ 67, u'Engineers (External)', 4 ],
[ 68, u'Scientists (External)', 4 ],
[ 69, u'Contractors', 4 ],
[ 70, u'Internal', 3 ],
[ 71, u'Employees', 70 ],
[ 72, u'Business Staff (Internal)', 71 ],
[ 73, u'Administrative Staff (Internal)', 72 ],
[ 74, u'Finance Staff (Internal)', 72 ],
[ 75, u'Managers (Internal)', 72 ],
[ 76, u'HR Staff (Internal)', 72 ],
[ 77, u'Engineers (Internal)', 71 ],
[ 78, u'Scientists (Internal)', 71 ],
]

for d in data:
    concepts_table.insert( values=d ).execute()

s = session.Session()
for i in s.query( Concept ).all(): 
    print i.name
    

Reply via email to