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.

Reply via email to