Trap errors when translating into the db's encoding
authorKarl O. Pinc <kop@karlpinc.com>
Sun, 30 May 2021 06:18:10 +0000 (01:18 -0500)
committerKarl O. Pinc <kop@karlpinc.com>
Sun, 30 May 2021 06:18:10 +0000 (01:18 -0500)
src/pgwui_core/core.py
src/pgwui_core/exceptions.py

index 4b92571034cea27b739105bcab44d8427afc4fad..2b96da798b2cbf1cf80e7578bf65ca23adb48f5b 100644 (file)
@@ -62,6 +62,7 @@ from wtforms import (
     FileField)
 
 import psycopg2
+import psycopg2.extensions
 
 from pgwui_core.constants import (
     CHECKED,
@@ -988,6 +989,7 @@ class UploadData(DBData):
 @attr.s
 class ParameterExecutor():
     '''Execute a parameterized pscopg2 statement
+    Must be mixed in with a DataLineProcessor.
     '''
     def param_execute(self, insert_stmt, udl):
         try:
@@ -999,6 +1001,37 @@ class ParameterExecutor():
                 'Fewer columns than column headings',
                 f'The IndexError from psycopg2 is: ({exp})',
                 data=udl.raw)
+        except UnicodeEncodeError as exp:
+            self.raise_encoding_error(exp, udl)
+
+    def raise_encoding_error(self, exp, udl):
+        errors = []
+        cnt = 1
+        enc = psycopg2.extensions.encodings[self.cur.connection.encoding]
+        for col in udl.tuples:
+            try:
+                col.encode(encoding=enc)
+            except UnicodeEncodeError as detailed_exp:
+                errors.append(core_ex.EncodingError(
+                    udl.lineno,
+                    ("Data cannot be represented in the database's character"
+                     " encoding"),
+                    (f'The data ({col}) in column'
+                     f' {cnt} contains an un-representable bit sequence;'
+                     ' the reported error is:'),
+                    str(detailed_exp),
+                    data=udl.raw))
+            cnt += 1
+        if errors:
+            raise core_ex.MultiError(errors)
+        raise core_ex.EncodingError(
+            udl.lineno,
+            ("Data cannot be represented in the database's character"
+             " encoding"),
+            ('Cannot discover which column contains an un-representable'
+             ' bit sequence, the reported error is:'),
+            str(exp),
+            data=udl.raw)
 
 
 class DataLineProcessor(object):
@@ -1476,12 +1509,11 @@ class DBConnector(object):
             try:
                 self.upload_data(processor, self.data, errors)
                 # Let upload handler finish
-                try:
-                    self.uh.cleanup()
-                except core_ex.MultiError as ex:
-                    errors.extend(ex.errors)
-                except core_ex.UploadError as ex:
-                    errors.append(ex)
+                self.uh.cleanup()
+            except core_ex.MultiError as ex:
+                errors.extend(ex.errors)
+            except core_ex.UploadError as ex:
+                errors.append(ex)
             finally:
                 self.cur.close()
         return errors
index 3fe4e46d81a7c732531ae5986dfc0ca066b206d9..8fff49d2db0eb1d2da799cafb132167fa30370e2 100644 (file)
@@ -250,3 +250,8 @@ class TooManyColsError(DataLineError):
 class TooFewColsError(DataLineError):
     def __init__(self, lineno, e, descr='', detail='', data=''):
         super().__init__(lineno, e, descr, detail, data)
+
+
+class EncodingError(DataLineError):
+    def __init__(self, lineno, e, descr='', detail='', data=''):
+        super().__init__(lineno, e, descr, detail, data)