]> git.ipfire.org Git - thirdparty/psycopg.git/commitdiff
Added error_message function instead of message_str method
authorDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 19 Mar 2020 07:55:10 +0000 (20:55 +1300)
committerDaniele Varrazzo <daniele.varrazzo@gmail.com>
Thu, 19 Mar 2020 09:33:25 +0000 (22:33 +1300)
Keeping the pq interface simple and low level and moving the policy a
bit aside.

psycopg3/pq/__init__.py
psycopg3/pq/misc.py [new file with mode: 0644]
psycopg3/pq/pq_ctypes.py
tests/pq/test_misc.py [new file with mode: 0644]

index 3bbe1587efecc4c65a242a0be183d16d6f991251..05c7a9225e2860bb95ce2fd73d3ab5f345ba830e 100644 (file)
@@ -18,10 +18,12 @@ from .enums import (
     DiagnosticField,
 )
 from .encodings import py_codecs
+from .misc import error_message
 
 from . import pq_ctypes as pq_module
 
 PGconn = pq_module.PGconn
+PGresult = pq_module.PGresult
 PQerror = pq_module.PQerror
 Conninfo = pq_module.Conninfo
 
@@ -35,5 +37,6 @@ __all__ = (
     "PGconn",
     "Conninfo",
     "PQerror",
+    "error_message",
     "py_codecs",
 )
diff --git a/psycopg3/pq/misc.py b/psycopg3/pq/misc.py
new file mode 100644 (file)
index 0000000..9385cc7
--- /dev/null
@@ -0,0 +1,42 @@
+"""
+Various functionalities to make easier to work with the libpq.
+"""
+
+# Copyright (C) 2020 The Psycopg Team
+
+
+def error_message(obj):
+    """
+    Return an error message from a PGconn or PGresult.
+
+    The return value is a str (unlike pq data which is usually bytes).
+    """
+    from psycopg3 import pq
+
+    if isinstance(obj, pq.PGconn):
+        msg = obj.error_message
+
+        # strip severity and whitespaces
+        if msg:
+            msg = msg.splitlines()[0].split(b":", 1)[-1].strip()
+
+    elif isinstance(obj, pq.PGresult):
+        msg = obj.error_field(pq.DiagnosticField.PG_DIAG_MESSAGE_PRIMARY)
+        if not msg:
+            msg = obj.error_message
+
+            # strip severity and whitespaces
+            if msg:
+                msg = msg.splitlines()[0].split(b":", 1)[-1].strip()
+
+    else:
+        raise TypeError(
+            f"PGconn or PGresult expected, got {type(obj).__name__}"
+        )
+
+    if msg:
+        msg = msg.decode("utf8", "replace")  # TODO: or in connection encoding?
+    else:
+        msg = "no details available"
+
+    return msg
index 31f2b918976c4288d589d289346a6349649e2f64..7e4549abd1dca07dcf4c5b19a7e7d512277f9904 100644 (file)
@@ -19,6 +19,7 @@ from .enums import (
     TransactionStatus,
     Ping,
 )
+from .misc import error_message
 from . import _pq_ctypes as impl
 from ..exceptions import OperationalError
 
@@ -158,14 +159,6 @@ class PGconn:
     def error_message(self):
         return impl.PQerrorMessage(self.pgconn_ptr)
 
-    @property
-    def error_str(self):
-        rv = self.error_message
-        if rv:
-            return rv.encode('utf8', 'replace').rstrip()
-        else:
-            return "no details available"
-
     @property
     def socket(self):
         return impl.PQsocket(self.pgconn_ptr)
@@ -351,7 +344,7 @@ class PGconn:
 
     def consume_input(self):
         if 1 != impl.PQconsumeInput(self.pgconn_ptr):
-            raise PQerror(f"consuming input failed: {self.error_str}")
+            raise PQerror(f"consuming input failed: {error_message(self)}")
 
     def is_busy(self):
         return impl.PQisBusy(self.pgconn_ptr)
@@ -363,12 +356,12 @@ class PGconn:
     @nonblocking.setter
     def nonblocking(self, arg):
         if 0 > impl.PQsetnonblocking(self.pgconn_ptr, arg):
-            raise PQerror(f"setting nonblocking failed: {self.error_str}")
+            raise PQerror(f"setting nonblocking failed: {error_message(self)}")
 
     def flush(self):
         rv = impl.PQflush(self.pgconn_ptr)
         if rv < 0:
-            raise PQerror(f"flushing failed: {self.error_str}")
+            raise PQerror(f"flushing failed: {error_message(self)}")
         return rv
 
 
@@ -479,7 +472,7 @@ class Conninfo:
             if not errmsg:
                 raise MemoryError("couldn't allocate on conninfo parse")
             else:
-                exc = PQerror(errmsg.value)
+                exc = PQerror(errmsg.value.decode("utf8", "replace"))
                 impl.PQfreemem(errmsg)
                 raise exc
 
diff --git a/tests/pq/test_misc.py b/tests/pq/test_misc.py
new file mode 100644 (file)
index 0000000..c193c87
--- /dev/null
@@ -0,0 +1,15 @@
+import pytest
+
+
+def test_error_message(pq, pgconn):
+    res = pgconn.exec_(b"wat")
+    assert res.status == pq.ExecStatus.PGRES_FATAL_ERROR
+    msg = pq.error_message(pgconn)
+    assert msg == 'syntax error at or near "wat"'
+    assert msg == pq.error_message(res)
+    assert msg == res.error_field(
+        pq.DiagnosticField.PG_DIAG_MESSAGE_PRIMARY
+    ).decode("ascii")
+
+    with pytest.raises(TypeError):
+        pq.error_message(None)