From: RamonWill Date: Mon, 3 Aug 2020 16:57:26 +0000 (+0100) Subject: resolves #4733 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=693008267be868574ff7930d2d5498b1af127238;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git resolves #4733 --- diff --git a/doc/build/changelog/unreleased_14/4733.rst b/doc/build/changelog/unreleased_14/4733.rst new file mode 100644 index 0000000000..fb8580041c --- /dev/null +++ b/doc/build/changelog/unreleased_14/4733.rst @@ -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. diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py index 186f885d8a..52d80da669 100644 --- a/lib/sqlalchemy/sql/sqltypes.py +++ b/lib/sqlalchemy/sql/sqltypes.py @@ -38,6 +38,7 @@ from .. import inspection from .. import processors from .. import util from ..util import compat +from ..util import langhelpers from ..util import pickle @@ -1555,7 +1556,9 @@ 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. " + "Possible values: %s" + % (elem, langhelpers._repr_tuple_names(self.enums)) ), replace_context=err, ) @@ -1579,7 +1582,9 @@ 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. " + "Possible values: %s" + % (elem, langhelpers._repr_tuple_names(self.enums)) ), replace_context=err, ) diff --git a/lib/sqlalchemy/util/langhelpers.py b/lib/sqlalchemy/util/langhelpers.py index 28b7aa4ccc..2ac4b95757 100644 --- a/lib/sqlalchemy/util/langhelpers.py +++ b/lib/sqlalchemy/util/langhelpers.py @@ -1737,3 +1737,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 12 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) > 12 else name for name in names] + if flag: + return ", ".join(res) + else: + return "%s, ..., %s" % (", ".join(res[0:3]), res[-1]) diff --git a/test/sql/test_types.py b/test/sql/test_types.py index fac9fd1399..dfbb78245a 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -1452,14 +1452,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. " + "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. " + "Possible values: one, two, three, ..., BMember", bind_processor_validates, "foo", ) @@ -1469,7 +1471,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. " + "Possible values: one, two, three, ..., BMember", result_processor, "foo", ) @@ -1484,14 +1487,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. " + "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. " + "Possible values: one, two, three, ..., BMember", validate_literal_processor, "foo", ) @@ -1508,14 +1513,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. " + "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. " + "Possible values: one, two", bind_processor_validates, "foo", ) @@ -1525,7 +1532,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. " + "Possible values: one, two", result_processor, "foo", ) @@ -1538,18 +1546,45 @@ 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. " + "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. " + "Possible values: one, two", validate_literal_processor, "foo", ) + 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. " + "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. " + "Possible values: None", + bind_processor, + 5, + ) + def test_validators_not_in_like_roundtrip(self, connection): enum_table = self.tables["non_native_enum_table"] @@ -1745,7 +1780,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. " + "Possible values: one, two, three", conn.scalar, select([self.tables.non_native_enum_table.c.someotherenum]), )