summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-01-14 18:55:59 +0000
committerGerrit Code Review <gerrit@bbpush.zzzcomputing.com>2021-01-14 18:55:59 +0000
commit41ca37734aa4f293ac5fb63c239d78185c8ec983 (patch)
tree372f172e38ba565df1a6b3acb9c70c843eed3735
parent4d20df14846e644b88fbe8a288116422bf5e343e (diff)
parentb4c6cfc2fde6c652e79ca157f8023a3f8941bc3c (diff)
downloadsqlalchemy-41ca37734aa4f293ac5fb63c239d78185c8ec983.tar.gz
Merge "Use UnsupportedCompilationError for no default compiler"
-rw-r--r--doc/build/changelog/unreleased_13/5836.rst13
-rw-r--r--lib/sqlalchemy/exc.py6
-rw-r--r--lib/sqlalchemy/ext/compiler.py16
-rw-r--r--test/ext/test_compiler.py25
4 files changed, 49 insertions, 11 deletions
diff --git a/doc/build/changelog/unreleased_13/5836.rst b/doc/build/changelog/unreleased_13/5836.rst
new file mode 100644
index 000000000..0ddfb9a8d
--- /dev/null
+++ b/doc/build/changelog/unreleased_13/5836.rst
@@ -0,0 +1,13 @@
+.. change::
+ :tags: bug, ext
+ :tickets: 5836
+
+ Fixed issue where the stringification that is sometimes called when
+ attempting to generate the "key" for the ``.c`` collection on a selectable
+ would fail if the column were an unlabeled custom SQL construct using the
+ ``sqlalchemy.ext.compiler`` extension, and did not provide a default
+ compilation form; while this seems like an unusual case, it can get invoked
+ for some ORM scenarios such as when the expression is used in an "order by"
+ in combination with joined eager loading. The issue is that the lack of a
+ default compiler function was raising :class:`.CompileError` and not
+ :class:`.UnsupportedCompilationError`.
diff --git a/lib/sqlalchemy/exc.py b/lib/sqlalchemy/exc.py
index b031c1610..08b1bb060 100644
--- a/lib/sqlalchemy/exc.py
+++ b/lib/sqlalchemy/exc.py
@@ -179,10 +179,10 @@ class UnsupportedCompilationError(CompileError):
code = "l7de"
- def __init__(self, compiler, element_type):
+ def __init__(self, compiler, element_type, message=None):
super(UnsupportedCompilationError, self).__init__(
- "Compiler %r can't render element of type %s"
- % (compiler, element_type)
+ "Compiler %r can't render element of type %s%s"
+ % (compiler, element_type, ": %s" % message if message else "")
)
diff --git a/lib/sqlalchemy/ext/compiler.py b/lib/sqlalchemy/ext/compiler.py
index 5a31173ec..47fb6720b 100644
--- a/lib/sqlalchemy/ext/compiler.py
+++ b/lib/sqlalchemy/ext/compiler.py
@@ -425,9 +425,11 @@ def compiles(class_, *specs):
return existing_dispatch(element, compiler, **kw)
except exc.UnsupportedCompilationError as uce:
util.raise_(
- exc.CompileError(
- "%s construct has no default "
- "compilation handler." % type(element)
+ exc.UnsupportedCompilationError(
+ compiler,
+ type(element),
+ message="%s construct has no default "
+ "compilation handler." % type(element),
),
from_=uce,
)
@@ -476,9 +478,11 @@ class _dispatcher(object):
fn = self.specs["default"]
except KeyError as ke:
util.raise_(
- exc.CompileError(
- "%s construct has no default "
- "compilation handler." % type(element)
+ exc.UnsupportedCompilationError(
+ compiler,
+ type(element),
+ message="%s construct has no default "
+ "compilation handler." % type(element),
),
replace_context=ke,
)
diff --git a/test/ext/test_compiler.py b/test/ext/test_compiler.py
index d011417d7..c10e27180 100644
--- a/test/ext/test_compiler.py
+++ b/test/ext/test_compiler.py
@@ -151,13 +151,33 @@ class UserDefinedTest(fixtures.TestBase, AssertsCompiledSQL):
return "mythingy"
assert_raises_message(
- exc.CompileError,
+ exc.UnsupportedCompilationError,
"<class 'test.ext.test_compiler..*MyThingy'> "
"construct has no default compilation handler.",
str,
MyThingy(),
)
+ def test_no_default_proxy_generation(self):
+ class my_function(FunctionElement):
+ name = "my_function"
+ type = Numeric()
+
+ @compiles(my_function, "sqlite")
+ def sqlite_my_function(element, compiler, **kw):
+ return "my_function(%s)" % compiler.process(element.clauses, **kw)
+
+ t1 = table("t1", column("q"))
+ stmt = select(my_function(t1.c.q))
+
+ self.assert_compile(
+ stmt,
+ "SELECT my_function(t1.q) AS my_function_1 FROM t1",
+ dialect="sqlite",
+ )
+
+ eq_(stmt.selected_columns.keys(), [stmt._raw_columns[0].anon_label])
+
def test_no_default_message(self):
class MyThingy(ClauseElement):
pass
@@ -167,7 +187,8 @@ class UserDefinedTest(fixtures.TestBase, AssertsCompiledSQL):
return "mythingy"
assert_raises_message(
- exc.CompileError,
+ exc.UnsupportedCompilationError,
+ "Compiler .*StrSQLCompiler.* can't .* "
"<class 'test.ext.test_compiler..*MyThingy'> "
"construct has no default compilation handler.",
str,