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