Eh... please excuse my haste, having ton of work this morning and my brain is already melting... :)

It fails after all, exactly the same way as in my app:


https://gist.github.com/1363906



Output:



Outer transaction...
First pass...
INSERTED
Second pass...
UPDATED
tm.name:
Traceback (most recent call last):
  File "__init__.py", line 108, in <module>
    main(None)
  File "__init__.py", line 98, in main
    my_view(None)
  File "__init__.py", line 75, in my_view
    print "tm.name:", tm.name
File "/home/vlad/dev/Test/virtualenv/lib/python2.7/site-packages/SQLAlchemy-0.7.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/attributes.py", line 168, in __get__
    return self.impl.get(instance_state(instance),dict_)
File "/home/vlad/dev/Test/virtualenv/lib/python2.7/site-packages/SQLAlchemy-0.7.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/attributes.py", line 422, in get
    value = callable_(passive)
File "/home/vlad/dev/Test/virtualenv/lib/python2.7/site-packages/SQLAlchemy-0.7.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/state.py", line 271, in __call__
    self.manager.deferred_scalar_loader(self, toload)
File "/home/vlad/dev/Test/virtualenv/lib/python2.7/site-packages/SQLAlchemy-0.7.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/mapper.py", line 1589, in _load_scalar_attributes
    (state_str(state)))
sqlalchemy.orm.exc.DetachedInstanceError: Instance <TestModel at 0x1bf58d0> is not bound to a Session; attribute refresh operation cannot proceed


.oO V Oo.


On 11/14/2011 01:41 PM, Vlad K. wrote:

Here:

https://gist.github.com/1363860

This simple test case works just fine, meaning the problem is somewhere in my application. As you can see from the code, I tried both a "standalone" test and through Pyramid WSGI chain checking if pyramid_tm middleware possibly borks something somewhere, but both cases worked fine.

However, I can't really replicate a test scenario fully because the problematic part of my application involves several models with relationships, multiple updates. If I use EXACTLY the same flow for the savepoint, ie:

sp = transaction.savepoint()
try:
    ... # Try insert
    transaction.commit()
except IntegrityError:
    transaction.abort()
    ... # Try Update

Then the result is:



2011-11-14 12:58:29,689 INFO [sqlalchemy.engine.base.Engine][worker 0] BEGIN (implicit)

... SELECTs and UPDATEs

2011-11-14 12:58:29,726 INFO [sqlalchemy.engine.base.Engine][worker 0] SAVEPOINT sa_savepoint_1 2011-11-14 12:58:29,726 INFO [sqlalchemy.engine.base.Engine][worker 0] {} 2011-11-14 12:58:29,727 INFO [sqlalchemy.engine.base.Engine][worker 0] INSERT INTO user_stats (user_id, tstamp, portal, ads_new, ads_modified, ads_deleted) VALUES (%(user_id)s, %(tstamp)s, %(portal)s, %(ads_new)s, %(ads_modified)s, %(ads_deleted)s) 2011-11-14 12:58:29,727 INFO [sqlalchemy.engine.base.Engine][worker 0] {'user_id': 1, 'ads_new': 0, 'ads_deleted': 0, 'tstamp': datetime.date(2011, 11, 14), 'ads_modified': 0, 'portal': 'test'} 2011-11-14 12:58:29,728 INFO [sqlalchemy.engine.base.Engine][worker 0] ROLLBACK TO SAVEPOINT sa_savepoint_1 2011-11-14 12:58:29,728 INFO [sqlalchemy.engine.base.Engine][worker 0] {} 2011-11-14 12:58:29,754 INFO [sqlalchemy.engine.base.Engine][worker 0] BEGIN (implicit) 2011-11-14 12:58:29,756 INFO [sqlalchemy.engine.base.Engine][worker 0] UPDATE user_stats SET ads_new=(user_stats.ads_new + %(ads_new_1)s), ads_modified=(user_stats.ads_modified + %(ads_modified_1)s), ads_deleted=(user_stats.ads_deleted + %(ads_deleted_1)s) WHERE user_stats.user_id = %(user_id_1)s AND user_stats.portal = %(portal_1)s AND user_stats.tstamp = %(tstamp_1)s 2011-11-14 12:58:29,756 INFO [sqlalchemy.engine.base.Engine][worker 0] {'ads_deleted_1': 0, 'portal_1': 'test', 'ads_new_1': 0, 'tstamp_1': datetime.date(2011, 11, 14), 'user_id_1': 1, 'ads_modified_1': 1} 2011-11-14 12:58:29,956 ERROR [pyramid_debugtoolbar][worker 0] Exception at http://localhost:6543/ads/view/28328?category=
...
DetachedInstanceError: Parent instance <AdLand at 0x7ffb900faa90> is not bound to a Session; lazy load operation of attribute 'ad_base' cannot proceed




The exception being thrown when I, after the savepoint fail, try to READ a value from a model read/updated within the outer transaction. The process:

0. enter view
1. session = DBSession()
2. load some models
3. change them with POSTed data (including adding/removing/updating models through relationship class members) 4. session.flush() changes (possibly redundant because savepoint unconditionally flushes) 5. make savepoint, try insert or update some statistical models (which are not used or in any way related with those from the outer transaction), commit or abort the savepoint 6. read some data from models loaded in step 2 (reading again here because flush() in step 4 returns new IDs etc... so another phase of update* is required)
7. session.flush() everything again
8. exit view

*update involving external resources like processing related uploaded files which names depend on IDs and other data obtained after flush in step 4


The DetachedInstanceError is thrown at step 6, more precisely:




if not ad.ad_base.main_image_id and len(ad.ad_base.images):
    ...




where ad is a "main" model, ad.ad_base is a relationship() with parent (of another class), main_image_id is integer and ad.ad_base.images is a relationship to yet another model. The DetachedInstance means the 'ad' being detached, so ad.ad_base is void.


So somehow the transaction of the savepoint messes up with the external session, even though there is no relationship between those and the models inserted/updated within the inner transaction. No foreignkey or relationship() connection.




.oO V Oo.


On 11/14/2011 12:04 PM, Vlad K. wrote:

Sure, I'll whip something up.


Thanks.


.oO V Oo.


On 11/14/2011 06:01 AM, Chris McDonough wrote:
I hate to ask, but would it be possible to concoct a short Python script
that creates a SQLA DBSession (with the ZopeTransactionExtension
enabled) that issues transaction.commit/savepoint/abort commands that
demonstrates the problem being encountered?  I'd be guessing if I tried
to help with this without that.

- C





--
You received this message because you are subscribed to the Google Groups 
"pylons-discuss" 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/pylons-discuss?hl=en.

Reply via email to