[DB-SIG] conn.close() idempotence

M.-A. Lemburg mal at egenix.com
Wed Oct 19 09:59:52 CEST 2011

Daniele Varrazzo wrote:
> Hello,
> in a discussion on the psycopg mailing list, an user has been
> surprised by the fact that .close() called on a closed connection
> raised error. I thought this was an implementation accident in the
> driver and a more robust semantics should allow for close to be called
> on a closed object without effect. But going to code a forgiving
> double close, I found a test failing in the Stuart Bishop DBAPI unit
> test,
>         # connection.close should raise an Error if called more than once
>         self.assertRaises(self.driver.Error,con.close)

This is a consequence of making the connection object unusable
after .close() was called for the first time.

> I see no reason to require this, and it actually creates some problem.
> For example, if the connection is dropped for a network problem, the
> driver may detect the invalid connection and put the connection in
> closed status. But at this point any guard such as:
>     conn = connection()
>     try:
>         # work
>     finally:
>         conn.close()
> risks to become a problem, with the close() that may raise an error
> because the connection has been implicitly closed by a communication
> error. Note that close() in itself often is a quite safe operation,
> not involving database communication, so it is not expected to fail
> and may not be well guarded.

That last sentence is not quite correct: .close() issues an implicit
.rollback() and usually also tells the database backend to free up
resources maintained for the connection, so it does require communication
with the backend.

There are a few situations which can result in an exception:

 * the network has gone down or is temporarily interrupted
 * an operation is still pending completion on the connection,
   e.g. a two-phase commit or an asynchronously running statement
 * there's not enough memory available to complete the operation

Note that in the above cases, .close() will not complete and thus
also not necessarily put the connection in an unusable state. The
exact semantics depend on the database backend.

Example: You may have a temporary network error, so .close() issues
an exception, but still allows to call .close() again after the
issue has been resolved.

> The DBAPI says about conn.close():
>     The connection will be unusable from this point
>     forward; an Error (or subclass) exception will be raised
>     if any operation is attempted with the connection.
> now, is conn.close() an "operation" on the connection? Even if it
> doesn't involve server communication? I don't think an idempotent
> close() violates this rule, so I'm really asking about an
> interpretation of the DBAPI, not a change.

See above. .close() does imply a few operations that can fail.
You are basically suggesting to silence and ignore those exceptions.
That's generally not a good idea, since the application may want
to report those errors to the user or take some other action.

> Another user in the ML pointed out that an idempotent close is also
> the behaviour of the Python file objects.
> My opinion is that the DBAPI test suite can be relaxed and
> conn.close() should have no effect on a closed connection. What do you
> think?

In summary, I'd rather not have .close() silence exceptions.

What we could do is expose an attribute connection.closed which
gets set to True by a successful run of connection.close().
That way you can test for the "unusable" state on a connection,

if not connection.closed:

Marc-Andre Lemburg

Professional Python Services directly from the Source  (#1, Oct 19 2011)
>>> Python/Zope Consulting and Support ...        http://www.egenix.com/
>>> mxODBC.Zope.Database.Adapter ...             http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/

::: Try our new mxODBC.Connect Python Database Interface for free ! ::::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611

More information about the DB-SIG mailing list