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 [email protected]
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