On 10/27/2016 05:13 PM, Zach wrote:
Hi, I'd really appreciate some assistance with the below issue.
Rolling back sqlalchemy transactions cross-flush currently appears
impossible to me. It’s necessary if you want to issue queries that rely
on the presence of an assigned primary key identifier (|add|ing
something to the session isn’t sufficient to get a primary key assigned).
But if you issue such a query, you’ll either get a query-invoked
autoflush (if autoflush is on), or you’ll have to flush first. And this
apparently seems to changes the scope of what gets rolled back
on |session.rollback()|. It seems to be only the stuff after the flush.
Use case: rolling back on the teardown method of unit tests that require
flushes.
Solution I'm looking for: A way to roll back /all/ uncommitted changes
after a savepoint/virtual transaction/some other kind of transactional
wrapper is created in the |setUp| method of a |unittest.TestCase| subclass.
Example:
|session
=sessionmaker()classMyTest(unittest.TestCase):defsetUp(self):session.begin_nested()deftearDown(self):session.rollback()defmyTest(self):session.add(object)#
now a flush is required because `id` is used belowquery
=session.query('select id from my_table where id =
{}'.format(object.id))# Problem: Now `object` will exist even after
`tearDown`|
So I'm not really sure what you're actually doing; the example described
will not commit anything. The call "session.query("SQL") makes no sense
and doesn't do anything. In order to trigger the autoflush, we have to
actually run some query. I've modified your code fragment to be
something in context and no additional data is committed:
from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
__tablename__ = 'a'
id = Column(Integer, primary_key=True)
e = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
Base.metadata.drop_all(e)
Base.metadata.create_all(e)
session = sessionmaker(e)()
class MyTest(object):
def setUp(self):
session.begin_nested()
def tearDown(self):
session.rollback()
def myTest(self):
a1 = A()
session.add(a1) # now a flush is required because `id` is used
below
session.query(A).filter(A.id == a1.id).all()
session.query(A).filter(A.id == a1.id).all()
# Problem: Now `object` will exist even after `tearDown`
def myOtherTest(self):
a1 = A()
session.add(a1) # now a flush is required because `id` is used
below
session.query(A).filter(A.id == a1.id).all()
# Problem: Now `object` will exist even after `tearDown`
t1 = MyTest()
t1.setUp()
t1.myTest()
t1.tearDown()
t1.setUp()
t1.myOtherTest()
t1.tearDown()
# nothing committed
assert e.scalar("Select count(*) from a") == 0
It's important that I have a real test case illustrating what you are
actually seeing because I'm not familiar with what "rolling back
cross-flush" means nor with any of the other behaviors you are seeing
(I'm sure you are seeing them, but I have no idea what you're doing to
get that result).
That said, the issue with setting up test transaction scope using the
session itself is that if anything inside the test itself does a
rollback() or commit(), the session is out of the transaction you've set
up and subsequent operations will begin a new transaction. I would
imagine your actual test case is much more complicated and something
like that is going on (if you can distill the actual behavior into a
self-contained, succinct test case that is runnable as mine is above,
that would allow me to explain exactly what you are seeing).
Therefore the documentation for this pattern recommends setting up the
transaction on a Connection that's external to the whole thing:
http://docs.sqlalchemy.org/en/rel_1_1/orm/session_transaction.html#joining-a-session-into-an-external-transaction-such-as-for-test-suites
that way, as the Session proceeds to begin/commit/begin/rollback or
whatever, it never gets access to the outermost "commit". The second
example in that section illustrates a way to go that additionally
supports tests that themselves rollback.
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and
Verifiable Example. See http://stackoverflow.com/help/mcve for a full
description.
---
You received this message because you are subscribed to the Google
Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to [email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
http://www.sqlalchemy.org/
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable
Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.