Future releases
---------------
-Psycopg 3.1.10
-^^^^^^^^^^^^^^
+Psycopg 3.1.10 (unreleased)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Fix prepared statement cache validation when exiting pipeline mode (or
`~Cursor.executemany()`) in case an error occurred within the pipeline
`OperationalError` in case of connection failure. `Error.pgconn` is now a
shallow copy of the real libpq connection, and the latter is closed before
the exception propagates (:ticket:`#565`).
+- Don't clobber a Python exception raised during COPY FROM with the resulting
+ `!QueryCanceled` raised as a consequence (:ticket:`#593`).
+
Current release
---------------
else:
bmsg = None
- res = self.connection.wait(copy_end(self._pgconn, bmsg))
- self.cursor._results = [res]
+ try:
+ res = self.connection.wait(copy_end(self._pgconn, bmsg))
+ # The QueryCanceled is expected if we sent an exception message to
+ # pgconn.put_copy_end(). The Python exception that generated that
+ # cancelling is more important, so don't clobber it.
+ except e.QueryCanceled:
+ if not bmsg:
+ raise
+ else:
+ self.cursor._results = [res]
class QueuedLibpqDriver(LibpqWriter):
else:
bmsg = None
- res = await self.connection.wait(copy_end(self._pgconn, bmsg))
- self.cursor._results = [res]
+ try:
+ res = await self.connection.wait(copy_end(self._pgconn, bmsg))
+ # The QueryCanceled is expected if we sent an exception message to
+ # pgconn.put_copy_end(). The Python exception that generated that
+ # cancelling is more important, so don't clobber it.
+ except e.QueryCanceled:
+ if not bmsg:
+ raise
+ else:
+ self.cursor._results = [res]
class AsyncQueuedLibpqWriter(AsyncLibpqWriter):
def test_copy_in_error(conn):
cur = conn.cursor()
ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled):
+ with pytest.raises(TypeError):
with cur.copy("copy copy_in from stdin (format binary)") as copy:
copy.write(sample_text.decode())
def test_copy_in_error_empty(conn, format):
cur = conn.cursor()
ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled) as exc:
+ with pytest.raises(ZeroDivisionError, match="mannaggiamiseria"):
with cur.copy(f"copy copy_in from stdin (format {format.name})"):
- raise Exception("mannaggiamiseria")
+ raise ZeroDivisionError("mannaggiamiseria")
- assert "mannaggiamiseria" in str(exc.value)
assert conn.info.transaction_status == conn.TransactionStatus.INERROR
def test_copy_in_buffers_with_py_error(conn):
cur = conn.cursor()
ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled) as exc:
+ with pytest.raises(ZeroDivisionError, match="nuttengoggenio"):
with cur.copy("copy copy_in from stdin (format text)") as copy:
copy.write(sample_text)
- raise Exception("nuttengoggenio")
+ raise ZeroDivisionError("nuttengoggenio")
- assert "nuttengoggenio" in str(exc.value)
assert conn.info.transaction_status == conn.TransactionStatus.INERROR
async def test_copy_in_error(aconn):
cur = aconn.cursor()
await ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled):
+ with pytest.raises(TypeError):
async with cur.copy("copy copy_in from stdin (format binary)") as copy:
await copy.write(sample_text.decode())
async def test_copy_in_error_empty(aconn, format):
cur = aconn.cursor()
await ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled) as exc:
+ with pytest.raises(ZeroDivisionError, match="mannaggiamiseria"):
async with cur.copy(f"copy copy_in from stdin (format {format.name})"):
- raise Exception("mannaggiamiseria")
+ raise ZeroDivisionError("mannaggiamiseria")
- assert "mannaggiamiseria" in str(exc.value)
assert aconn.info.transaction_status == aconn.TransactionStatus.INERROR
async def test_copy_in_buffers_with_py_error(aconn):
cur = aconn.cursor()
await ensure_table(cur, sample_tabledef)
- with pytest.raises(e.QueryCanceled) as exc:
+ with pytest.raises(ZeroDivisionError, match="nuttengoggenio"):
async with cur.copy("copy copy_in from stdin (format text)") as copy:
await copy.write(sample_text)
- raise Exception("nuttengoggenio")
+ raise ZeroDivisionError("nuttengoggenio")
- assert "nuttengoggenio" in str(exc.value)
assert aconn.info.transaction_status == aconn.TransactionStatus.INERROR