Hi Michael et al,
basic question: Can I call identity_key in after_commit? If not, are there any
alternatives?
Explanation:
For our GUI application I tried to extend SQLAlchemy to signal database
updates. The following constraints apply:
* Updates are done in background threads and should be visible in
the GUI main thread.
* Being a MVC architecture, the GUI shows only data as actually
found in the database.
All business objects implement the Observer pattern, so in-GUI changes
(not yet committed) are shown in the GUI panels. This can not be used
with background threads as the event is fired on attribute write -
before the change is committed.
The scheme I implemented is that a SessionExtension is keeping track of
dirty, new and deleted instances in after_flush and generates events in
after_commit. after_rollback clears the information of changed
instances.
To move the list of affected objects to another thread, I use the
identity_key function to retrieve the primary keys. On the target
thread, I use that information to reload ORM instances which are
affected.
However, while doing an unrelated change today, this broke down with the
following backtrace. I can not make sense out of this: after_commit
should only be called after a commit I would think (not after a rollback
as the error message seems to indicate).
I'd expect that identity_key should be available in after_commit as it
is called *after* a commit and therefore the session should be in a sane
state?! This error breaks the GUI, every later attribute access fails
with DetachedInstanceError.
Note: The mechanism is used also for same-thread updates and in this
case the after_commit actually runs in the GUI thread for the ORM
session used by the GUI thread.
Any hints much appreciated. Thanks!
Torsten
File "/home/torsten/workspace/loco2-git/loco2/storage/extensions.py", line
96, in after_commit
notifier.signal_updated(instance)
File "/home/torsten/workspace/loco2-git/loco2/storage/notification.py", line
72, in signal_updated
self._signal(_UPDATE, type(instance), identity_key(instance=instance))
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/util.py",
line 185, in identity_key
return mapper.identity_key_from_instance(instance)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/mapper.py",
line 1294, in identity_key_from_instance
self.primary_key_from_instance(instance))
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/mapper.py",
line 1306, in primary_key_from_instance
return self._primary_key_from_state(state)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/mapper.py",
line 1311, in _primary_key_from_state
column in self.primary_key]
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/mapper.py",
line 1315, in _get_state_attr_by_column
return self._columntoproperty[column]._getattr(state, dict_, column,
passive=passive)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/properties.py",
line 121, in _getattr
return state.get_impl(self.key).get(state, dict_, passive=passive)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/attributes.py",
line 388, in get
value = callable_(passive=passive)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/state.py",
line 287, in __call__
self.manager.deferred_scalar_loader(self, toload)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/mapper.py",
line 2499, in _load_scalar_attributes
only_load_props=attribute_names)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/query.py",
line 1968, in _get
return q.one()
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/query.py",
line 1656, in one
ret = list(self)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/query.py",
line 1699, in __iter__
return self._execute_and_instances(context)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/query.py",
line 1704, in _execute_and_instances
mapper=self._mapper_zero_or_none())
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/session.py",
line 723, in execute
return self._connection_for_bind(engine, close_with_result=True).execute(
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/session.py",
line 667, in _connection_for_bind
return self.transaction._connection_for_bind(engine)
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/session.py",
line 319, in _connection_for_bind
self._assert_is_active()
File
"/usr/local/lib/python2.6/dist-packages/SQLAlchemy-0.6.7dev-py2.6.egg/sqlalchemy/orm/session.py",
line 247, in _assert_is_active
"This Session's transaction has been rolled back "
InvalidRequestError: This Session's transaction has been rolled back by a
nested rollback() call. To begin a new transaction, issue Session.rollback()
first.
--
DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH
Torsten Landschoff
Office Dresden
Tel: +49-(0)351-4519587
Fax: +49-(0)351-4519561
mailto:[email protected]
http://www.dynamore.de
Registration court: Mannheim, HRB: 109659, based in Karlsruhe,
Managing director: Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz
--
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.