From: Mike Bayer Date: Thu, 16 Aug 2012 17:25:46 +0000 (-0400) Subject: - we're going to attempt to get the type/operator system to eat its own dogfood and X-Git-Tag: rel_0_8_0b1~238 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fd4ac5b3171dacf2efba31c520c546e2422fba36;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - we're going to attempt to get the type/operator system to eat its own dogfood and use the type-based comparator in all cases. will attempt to remove the _adapt_expression() method entirely as this represents an incomplete and redundant system (though it might be a lot faster) --- diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 613705c387..a0715a975d 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2099,6 +2099,8 @@ class _DefaultColumnComparator(object): if isinstance(other, (SelectBase, Alias)): other = other.as_scalar() return other + elif isinstance(other, sqltypes.TypeEngine.Comparator): + return other.expr elif not isinstance(other, ClauseElement): return expr._bind_param(operator, other) elif isinstance(other, (SelectBase, Alias)): @@ -2152,24 +2154,24 @@ class ColumnElement(ClauseElement, ColumnOperators): __visit_name__ = 'column' primary_key = False foreign_keys = [] - type = None quote = None _label = None _key_label = None _alt_names = () + @util.memoized_property + def type(self): + return sqltypes.NULLTYPE + @util.memoized_property def comparator(self): - if self.type is None: - return None - elif self.type.comparator_factory is not None: - return self.type.comparator_factory(self) - else: - return None + return self.type.comparator_factory(self) + + #def _assert_comparator(self): + # assert self.comparator.expr is self def __getattr__(self, key): - if self.comparator is None: - raise AttributeError(key) + #self._assert_comparator() try: return getattr(self.comparator, key) except AttributeError: @@ -2180,32 +2182,28 @@ class ColumnElement(ClauseElement, ColumnOperators): key) ) - @property - def expression(self): - """Return a column expression. - - Part of the inspection interface; returns self. - - """ - return self - def operate(self, op, *other, **kwargs): - if self.comparator: - return op(self.comparator, *other, **kwargs) - else: - return _DEFAULT_COMPARATOR.operate(self, op, *other, **kwargs) + #self._assert_comparator() + return op(self.comparator, *other, **kwargs) def reverse_operate(self, op, other, **kwargs): - if self.comparator: - return op(other, self.comparator, **kwargs) - else: - return _DEFAULT_COMPARATOR.reverse_operate(self, op, other, **kwargs) + #self._assert_comparator() + return op(other, self.comparator, **kwargs) def _bind_param(self, operator, obj): return BindParameter(None, obj, _compared_to_operator=operator, _compared_to_type=self.type, unique=True) + @property + def expression(self): + """Return a column expression. + + Part of the inspection interface; returns self. + + """ + return self + @property def _select_iterable(self): return (self, ) @@ -4007,7 +4005,7 @@ class Grouping(ColumnElement): def __init__(self, element): self.element = element - self.type = getattr(element, 'type', None) + self.type = getattr(element, 'type', sqltypes.NULLTYPE) @property def _label(self): diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 6bfaf4b8c9..35761def16 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -420,6 +420,7 @@ class Annotated(object): element.c self.__dict__ = element.__dict__.copy() + self.__dict__.pop('comparator', None) self.__element = element self._annotations = values @@ -431,6 +432,7 @@ class Annotated(object): def _with_annotations(self, values): clone = self.__class__.__new__(self.__class__) clone.__dict__ = self.__dict__.copy() + clone.__dict__.pop('comparator', None) clone._annotations = values return clone diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 6c90416304..40cf2f3314 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -47,9 +47,13 @@ class TypeEngine(AbstractType): type level. See :attr:`.TypeEngine.comparator_factory`. """ + def __init__(self, expr): self.expr = expr + def __reduce__(self): + return _reconstitute_comparator, (self.expr, ) + def operate(self, op, *other, **kwargs): return _DEFAULT_COMPARATOR.operate(self.expr, op, *other, **kwargs) @@ -57,7 +61,7 @@ class TypeEngine(AbstractType): return _DEFAULT_COMPARATOR.reverse_operate(self.expr, op, other, **kwargs) - comparator_factory = None + comparator_factory = Comparator """A :class:`.TypeEngine.Comparator` class which will apply to operations performed by owning :class:`.ColumnElement` objects. @@ -406,6 +410,9 @@ class TypeEngine(AbstractType): def __repr__(self): return util.generic_repr(self) +def _reconstitute_comparator(expression): + return expression.comparator + class UserDefinedType(TypeEngine): """Base for user defined types. diff --git a/test/lib/profiles.txt b/test/lib/profiles.txt index 5572a8ebce..edbee75e95 100644 --- a/test/lib/profiles.txt +++ b/test/lib/profiles.txt @@ -1,15 +1,15 @@ # /Users/classic/dev/sqla_comparators/./test/lib/profiles.txt # This file is written out on a per-environment basis. -# For each test in aaa_profiling, the corresponding function and +# For each test in aaa_profiling, the corresponding function and # environment is located within this file. If it doesn't exist, # the test is skipped. -# If a callcount does exist, it is compared to what we received. +# If a callcount does exist, it is compared to what we received. # assertions are raised if the counts do not match. -# -# To add a new callcount test, apply the function_call_count -# decorator and re-run the tests using the --write-profiles option - +# +# To add a new callcount test, apply the function_call_count +# decorator and re-run the tests using the --write-profiles option - # this file will be rewritten including the new count. -# +# # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert @@ -195,13 +195,6 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.2_ # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.6_sqlite_pysqlite_nocextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_cextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_mysql_mysqldb_nocextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_cextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_postgresql_psycopg2_nocextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_cextensions 12 -test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 2.7_sqlite_pysqlite_nocextensions 12 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_string