]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
error message for Lookup
authorRamonWill <ramonwilliams@hotmail.co.uk>
Wed, 12 Aug 2020 18:50:20 +0000 (14:50 -0400)
committerRamonWill <ramonwilliams@hotmail.co.uk>
Mon, 17 Aug 2020 00:38:23 +0000 (01:38 +0100)
Th proposed change will provide the user with the target Enum Class name as well as up to four possible enum values when a LookupError is raised in the Enum Class.

A user requested that the enum name and possible values are included to the LookupError message to make debugging easier. The criteria included using ellipses for Enums containing more than four values and using ellipses for enum values that were greater than a certain number of characters (for this resolution the limit is 11 characters).

This pull request is:

- [ ] A documentation / typographical error fix
- Good to go, no issue or tests are needed
- [X ] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**
Fixes: #4733
Closes: #5490
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5490
Pull-request-sha: 55e76f2ae796b59b7de157cfaae5235dffa359cb

Change-Id: I4541f9efed1c05401587a413e9e748d46938bcd1
(cherry picked from commit a8bd2116764fb6039742a34409254175846bb700)

doc/build/changelog/unreleased_13/4733.rst [new file with mode: 0644]
lib/sqlalchemy/sql/sqltypes.py
lib/sqlalchemy/util/langhelpers.py
test/sql/test_types.py

diff --git a/doc/build/changelog/unreleased_13/4733.rst b/doc/build/changelog/unreleased_13/4733.rst
new file mode 100644 (file)
index 0000000..fb85800
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, datatypes, sql
+    :tickets: 4733
+
+    The ``LookupError`` message will now provide the user with up to four
+    possible values that a column is constrained to via the :class:`.Enum`.
+    Values longer than 11 characters will be truncated and replaced with
+    ellipses. Pull request courtesy Ramon Williams.
index 7d2ba2a58f9562271780e49ce5f16104f87ebc5f..7309774858e359cceaff749dd2d4003a66bb222c 100644 (file)
@@ -37,6 +37,7 @@ from .. import inspection
 from .. import processors
 from .. import util
 from ..util import compat
+from ..util import langhelpers
 from ..util import pickle
 
 
@@ -1512,7 +1513,13 @@ class Enum(Emulated, String, SchemaType):
             else:
                 util.raise_(
                     LookupError(
-                        '"%s" is not among the defined enum values' % elem
+                        "'%s' is not among the defined enum values. "
+                        "Enum name: %s. Possible values: %s"
+                        % (
+                            elem,
+                            self.name,
+                            langhelpers.repr_tuple_names(self.enums),
+                        )
                     ),
                     replace_context=err,
                 )
@@ -1536,7 +1543,13 @@ class Enum(Emulated, String, SchemaType):
         except KeyError as err:
             util.raise_(
                 LookupError(
-                    '"%s" is not among the defined enum values' % elem
+                    "'%s' is not among the defined enum values. "
+                    "Enum name: %s. Possible values: %s"
+                    % (
+                        elem,
+                        self.name,
+                        langhelpers.repr_tuple_names(self.enums),
+                    )
                 ),
                 replace_context=err,
             )
index 876a4bd7136c0a471a69c9961888c803eeaa1deb..1fedda256447ed62adffa11e10bc80aced47354b 100644 (file)
@@ -1736,3 +1736,17 @@ def inject_param_text(doctext, inject_params):
         lines.append(line)
 
     return "\n".join(lines)
+
+
+def repr_tuple_names(names):
+    """ Trims a list of strings from the middle and return a string of up to
+        four elements. Strings greater than 11 characters will be truncated"""
+    if len(names) == 0:
+        return None
+    flag = len(names) <= 4
+    names = names[0:4] if flag else names[0:3] + names[-1:]
+    res = ["%s.." % name[:11] if len(name) > 11 else name for name in names]
+    if flag:
+        return ", ".join(res)
+    else:
+        return "%s, ..., %s" % (", ".join(res[0:3]), res[-1])
index 46d8f264c02680038cf3dff7e0a7f0782cb63907..be8389c9ce49e3a2ad12d8a02691515fc48a461b 100644 (file)
@@ -1351,14 +1351,16 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         eq_(bind_processor("foo"), "foo")
         assert_raises_message(
             LookupError,
-            '"5" is not among the defined enum values',
+            "'5' is not among the defined enum values. Enum name: someenum. "
+            "Possible values: one, two, three, ..., BMember",
             bind_processor,
             5,
         )
 
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: someenum. "
+            "Possible values: one, two, three, ..., BMember",
             bind_processor_validates,
             "foo",
         )
@@ -1368,7 +1370,8 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         eq_(result_processor("one"), self.one)
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: someenum. "
+            "Possible values: one, two, three, ..., BMember",
             result_processor,
             "foo",
         )
@@ -1383,14 +1386,16 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
 
         assert_raises_message(
             LookupError,
-            '"5" is not among the defined enum values',
+            "'5' is not among the defined enum values. Enum name: someenum. "
+            "Possible values: one, two, three, ..., BMember",
             literal_processor,
             5,
         )
 
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: someenum. "
+            "Possible values: one, two, three, ..., BMember",
             validate_literal_processor,
             "foo",
         )
@@ -1407,14 +1412,16 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         eq_(bind_processor("foo"), "foo")
         assert_raises_message(
             LookupError,
-            '"5" is not among the defined enum values',
+            "'5' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, two",
             bind_processor,
             5,
         )
 
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, two",
             bind_processor_validates,
             "foo",
         )
@@ -1424,7 +1431,8 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         eq_(result_processor("one"), "one")
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, two",
             result_processor,
             "foo",
         )
@@ -1437,19 +1445,46 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
         eq_(literal_processor("foo"), "'foo'")
         assert_raises_message(
             LookupError,
-            '"5" is not among the defined enum values',
+            "'5' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, two",
             literal_processor,
             5,
         )
 
         assert_raises_message(
             LookupError,
-            '"foo" is not among the defined enum values',
+            "'foo' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, two",
             validate_literal_processor,
             "foo",
         )
 
-    def test_validators_not_in_like_roundtrip(self):
+    def test_enum_raise_lookup_ellipses(self):
+        type_ = Enum("one", "twothreefourfivesix", "seven", "eight")
+        bind_processor = type_.bind_processor(testing.db.dialect)
+
+        eq_(bind_processor("one"), "one")
+        assert_raises_message(
+            LookupError,
+            "'5' is not among the defined enum values. Enum name: None. "
+            "Possible values: one, twothreefou.., seven, eight",
+            bind_processor,
+            5,
+        )
+
+    def test_enum_raise_lookup_none(self):
+        type_ = Enum()
+        bind_processor = type_.bind_processor(testing.db.dialect)
+
+        assert_raises_message(
+            LookupError,
+            "'5' is not among the defined enum values. Enum name: None. "
+            "Possible values: None",
+            bind_processor,
+            5,
+        )
+
+    def test_validators_not_in_like_roundtrip(self, connection):
         enum_table = self.tables["non_native_enum_table"]
 
         enum_table.insert().execute(
@@ -1612,7 +1647,8 @@ class EnumTest(AssertsCompiledSQL, fixtures.TablesTest):
             )
             assert_raises_message(
                 LookupError,
-                '"four" is not among the defined enum values',
+                "'four' is not among the defined enum values. "
+                "Enum name: None. Possible values: one, two, three",
                 conn.scalar,
                 select([self.tables.non_native_enum_table.c.someotherenum]),
             )