From 29eb88eefbe859ccd13cf44a8b6b310ae8b27507 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 26 Jun 2010 17:20:17 -0400 Subject: [PATCH] - Fixed bug that would prevent overridden clause compilation from working for "annotated" expression elements, which are often generated by the ORM. --- CHANGES | 4 ++++ lib/sqlalchemy/sql/util.py | 8 +++++--- test/ext/test_compiler.py | 31 ++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 9c983e1c88..aba313a7ce 100644 --- a/CHANGES +++ b/CHANGES @@ -60,6 +60,10 @@ CHANGES and large string values don't pollute the output. [ticket:1822] + - Fixed bug that would prevent overridden clause + compilation from working for "annotated" expression + elements, which are often generated by the ORM. + - The argument to "ESCAPE" of a LIKE operator or similar is passed through render_literal_value(), which may implement escaping of backslashes. [ticket:1400] diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index d0af0a9d6e..c999ab7862 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -259,7 +259,7 @@ class Annotated(object): self.__dict__ = element.__dict__.copy() self.__element = element self._annotations = values - + def _annotate(self, values): _values = self._annotations.copy() _values.update(values) @@ -270,7 +270,10 @@ class Annotated(object): def _deannotate(self): return self.__element - + + def _compiler_dispatch(self, visitor, **kw): + return self.__element.__class__._compiler_dispatch(self, visitor, **kw) + @property def _constructor(self): return self.__element._constructor @@ -300,7 +303,6 @@ annotated_classes = {} for cls in expression.__dict__.values() + [schema.Column, schema.Table]: if isinstance(cls, type) and issubclass(cls, expression.ClauseElement): exec "class Annotated%s(Annotated, cls):\n" \ - " __visit_name__ = cls.__visit_name__\n"\ " pass" % (cls.__name__, ) in locals() exec "annotated_classes[cls] = Annotated%s" % (cls.__name__) diff --git a/test/ext/test_compiler.py b/test/ext/test_compiler.py index 2d33b382af..fa1e3c1623 100644 --- a/test/ext/test_compiler.py +++ b/test/ext/test_compiler.py @@ -1,7 +1,7 @@ from sqlalchemy import * from sqlalchemy.types import TypeEngine from sqlalchemy.sql.expression import ClauseElement, ColumnClause,\ - FunctionElement + FunctionElement, Select from sqlalchemy.schema import DDLElement from sqlalchemy.ext.compiler import compiles from sqlalchemy.sql import table, column @@ -98,9 +98,34 @@ class UserDefinedTest(TestBase, AssertsCompiledSQL): t1, select([t1]).where(t1.c.x>5) ), - "INSERT INTO mytable (SELECT mytable.x, mytable.y, mytable.z FROM mytable WHERE mytable.x > :x_1)" + "INSERT INTO mytable (SELECT mytable.x, mytable.y, mytable.z " + "FROM mytable WHERE mytable.x > :x_1)" ) - + + def test_annotations(self): + """test that annotated clause constructs use the + decorated class' compiler. + + """ + t1 = table('t1', column('c1'), column('c2')) + + dispatch = Select._compiler_dispatch + try: + @compiles(Select) + def compile(element, compiler, **kw): + return "OVERRIDE" + + s1 = select([t1]) + self.assert_compile( + s1, "OVERRIDE" + ) + self.assert_compile( + s1._annotate({}), + "OVERRIDE" + ) + finally: + Select._compiler_dispatch = dispatch + def test_dialect_specific(self): class AddThingy(DDLElement): __visit_name__ = 'add_thingy' -- 2.47.2