From ca2e4f385802799c2584782a8528e19a9e5513bc Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 28 Feb 2020 14:56:25 -0500 Subject: [PATCH] Discontinue dynamic __visit_name__ Removed very antiquated logic that checks if __visit_name__ is a property. There's no need for this as the compiler can handle switching between implementations. Convert _compile_dispatch() to be fully inlined. Change-Id: Ic0c7247c2d7dfed93a27f09250a8ed6352370764 --- lib/sqlalchemy/sql/compiler.py | 6 +++++ lib/sqlalchemy/sql/schema.py | 20 ++++---------- lib/sqlalchemy/sql/visitors.py | 47 ++++++++++++++------------------- test/profiles.txt | 48 +++++++++++++++++----------------- test/sql/test_compiler.py | 17 ++++++------ 5 files changed, 64 insertions(+), 74 deletions(-) diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 04ae2532bf..9c1f50ce13 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -3542,6 +3542,12 @@ class DDLCompiler(Compiled): else: return None + def visit_table_or_column_check_constraint(self, constraint, **kw): + if constraint.is_column_level: + return self.visit_column_check_constraint(constraint) + else: + return self.visit_check_constraint(constraint) + def visit_check_constraint(self, constraint): text = "" if constraint.name is not None: diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 7cece42d06..e6d3a6b059 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -2238,14 +2238,6 @@ class ColumnDefault(DefaultGenerator): "positional arguments" ) - def _visit_name(self): - if self.for_update: - return "column_onupdate" - else: - return "column_default" - - __visit_name__ = property(_visit_name) - def __repr__(self): return "ColumnDefault(%r)" % (self.arg,) @@ -2861,6 +2853,8 @@ class CheckConstraint(ColumnCollectionConstraint): _allow_multiple_tables = True + __visit_name__ = "table_or_column_check_constraint" + @_document_text_coercion( "sqltext", ":class:`.CheckConstraint`", @@ -2925,13 +2919,9 @@ class CheckConstraint(ColumnCollectionConstraint): if table is not None: self._set_parent_with_dispatch(table) - def __visit_name__(self): - if isinstance(self.parent, Table): - return "check_constraint" - else: - return "column_check_constraint" - - __visit_name__ = property(__visit_name__) + @property + def is_column_level(self): + return not isinstance(self.parent, Table) def copy(self, target_table=None, **kw): if target_table is not None: diff --git a/lib/sqlalchemy/sql/visitors.py b/lib/sqlalchemy/sql/visitors.py index c946bb4ab2..77e6b53a8a 100644 --- a/lib/sqlalchemy/sql/visitors.py +++ b/lib/sqlalchemy/sql/visitors.py @@ -24,7 +24,6 @@ http://techspot.zzzeek.org/2008/01/23/expression-transformations/ . """ from collections import deque -import operator from .. import exc from .. import util @@ -53,32 +52,26 @@ def _generate_compiler_dispatch(cls): """ visit_name = cls.__visit_name__ - if isinstance(visit_name, util.compat.string_types): - # There is an optimization opportunity here because the - # the string name of the class's __visit_name__ is known at - # this early stage (import time) so it can be pre-constructed. - getter = operator.attrgetter("visit_%s" % visit_name) - - def _compiler_dispatch(self, visitor, **kw): - try: - meth = getter(visitor) - except AttributeError: - raise exc.UnsupportedCompilationError(visitor, cls) - else: - return meth(self, **kw) - - else: - # The optimization opportunity is lost for this case because the - # __visit_name__ is not yet a string. As a result, the visit - # string has to be recalculated with each compilation. - def _compiler_dispatch(self, visitor, **kw): - visit_attr = "visit_%s" % self.__visit_name__ - try: - meth = getattr(visitor, visit_attr) - except AttributeError: - raise exc.UnsupportedCompilationError(visitor, cls) - else: - return meth(self, **kw) + if not isinstance(visit_name, util.compat.string_types): + raise exc.InvalidRequestError( + "__visit_name__ on class %s must be a string at the class level" + % cls.__name__ + ) + + code = ( + "def _compiler_dispatch(self, visitor, **kw):\n" + " try:\n" + " meth = visitor.visit_%(name)s\n" + " except AttributeError:\n" + " util.raise_from_cause(\n" + " exc.UnsupportedCompilationError(visitor, cls))\n" + " else:\n" + " return meth(self, **kw)\n" + ) % {"name": visit_name} + + _compiler_dispatch = langhelpers._exec_code_in_env( + code, {"exc": exc, "cls": cls, "util": util}, "_compiler_dispatch" + ) _compiler_dispatch.__doc__ = """Look for an attribute named "visit_" + self.__visit_name__ on the visitor, and call it with the same diff --git a/test/profiles.txt b/test/profiles.txt index 4244e12663..a6e4b18450 100644 --- a/test/profiles.txt +++ b/test/profiles.txt @@ -121,30 +121,30 @@ test.aaa_profiling.test_compiler.CompileTest.test_update 3.7_sqlite_pysqlite_dba # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mssql_pyodbc_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mssql_pyodbc_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_pymysql_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_pymysql_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_cextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 159 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mssql_pyodbc_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mssql_pyodbc_dbapiunicode_nocextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_nocextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_nocextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 164 -test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 164 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mssql_pyodbc_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mssql_pyodbc_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_mysqldb_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_pymysql_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_mysql_pymysql_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_oracle_cx_oracle_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_postgresql_psycopg2_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_cextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 2.7_sqlite_pysqlite_dbapiunicode_nocextensions 151 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mssql_pyodbc_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mssql_pyodbc_dbapiunicode_nocextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_mysqldb_dbapiunicode_nocextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_mysql_pymysql_dbapiunicode_nocextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_oracle_cx_oracle_dbapiunicode_nocextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_postgresql_psycopg2_dbapiunicode_nocextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_cextensions 156 +test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.7_sqlite_pysqlite_dbapiunicode_nocextensions 156 # TEST: test.aaa_profiling.test_misc.CacheKeyTest.test_statement_one diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 6f16f05149..5030f9df84 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -3642,16 +3642,17 @@ class UnsupportedTest(fixtures.TestBase): def test_unsupported_element_meth_visit_name(self): from sqlalchemy.sql.expression import ClauseElement - class SomeElement(ClauseElement): - @classmethod - def __visit_name__(cls): - return "some_element" + def go(): + class SomeElement(ClauseElement): + @classmethod + def __visit_name__(cls): + return "some_element" assert_raises_message( - exc.UnsupportedCompilationError, - r"Compiler ", - SomeElement().compile, + exc.InvalidRequestError, + r"__visit_name__ on class SomeElement must be a string at " + r"the class level", + go, ) def test_unsupported_operator(self): -- 2.39.5