On 07/15/2016 07:49 AM, Alex Grönholm wrote:
The documentation provides the following example snippet for using
sessions within a context manager:
so, back when I started putting "examples" in those docs, the idea was
like, "hey, here's an *example*. The Python programmer is free to do
whatever they wish with these examples, and adjust as necessary".
That is, the reason something is an example and not a feature is, "you
don't have to do it this way! do it however you want".
That there's been a trend recently of examples being used as is, but
then when the example lacks some feature they result in bug reports
against the library itself (not this case, but a different case recently
comes to mind), is sadly the opposite of what i had intended. Of course
examples can be modified to be reasonable, however.
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except:
session.rollback()
raise
finally:
session.close()
I've been wondering why there is an except: block there. Shouldn't
session.close() be enough? At least according to the documentation, the
active transaction is rolled back by default when the connection is
returned to the pool.
that is correct. However .close() does not reset the state of the
objects managed by the Session to be "expired", which arguably is
necessary because without the transaction, you now have no idea what the
state of the object's corresponding rows in the database are (this is
what the whole "SQLAlchemy Session: In Depth" talk is about).
In reality, the above context manager is probably not that useful
because it bundles the lifespan of the Session and the lifespan of a
transaction together, and IMO an application should be more thoughtful
than that.
This snippet has a second potential problem: what if the transaction is
in a bad state when exiting the block? Shouldn't session.commit() be
skipped then?
it's assumed that if anything is in "a bad state" then an exception
would have been raised, you'd not reach commit().
Otherwise, if the idea is, "I'm using this context manager, but I'm not
sure I want to commit at the end even though nothing was raised", well
then this is not the context manager for you :). The example of
contextmanagers for things like writing files and such sets up the
convention of, "open resource, flush out all changes at the end if no
exceptions". That's what people usually want.
Like, if not session.is_active: session.commit()? Let's
say the user code catches IntegrityError but doesn't roll back.
if it doesn't re-raise, then we'd hit the commit() and that would
probably fail also (depending on backend). I don't see how that's
different from:
with open("important_file.txt", "w") as handle:
handle.write("important thing #1")
handle.write("important thing #2")
try:
important_thing_number_three = calculate_special_thing()
handle.write(important_thing_number_three)
except TerribleException:
log.info("oh crap! someone should fix this someday.")
handle.write("important thing #4")
The
example code will then raise an exception when it tries to commit the
session transaction. Am I missing something?
On the better backends like Postgresql, it would.
If there's a use case you're looking for here, e.g. catch an
IntegrityError but not leave the transaction, that's what savepoints are
for. There should be examples there.
Now, if someone on IRC is using savepoints with IntegrityError and the
context manager above and they're on Python 2 and are using MySQL and
getting deadlock errors and can't see the original cause, there's a very
specific sad situation going on with that which is
https://bitbucket.org/zzzeek/sqlalchemy/issues/2696 and I can help them
with that. But that's using the built in context managers. Using your
own context manager is a great way to get around that bug :).
--
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 sqlalchemy+unsubscr...@googlegroups.com
<mailto:sqlalchemy+unsubscr...@googlegroups.com>.
To post to this group, send email to sqlalchemy@googlegroups.com
<mailto:sqlalchemy@googlegroups.com>.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
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 sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.