From ed553fffd65a063d6dbdb3770d1fa0124bd55e23 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 17 Oct 2019 13:09:24 -0400 Subject: Implement facade for pytest parametrize, fixtures, classlevel Add factilities to implement pytest.mark.parametrize and pytest.fixtures patterns, which largely resemble things we are already doing. Ensure a facade is used, so that the test suite remains independent of py.test, but also tailors the functions to the more limited scope in which we are using them. Additionally, create a class-based version that works from the same facade. Several old polymorphic tests as well as two of the sql test are refactored to use the new features. Change-Id: I6ef8af1dafff92534313016944d447f9439856cf References: #4896 --- test/sql/test_operators.py | 315 +++++++++++++-------------------- test/sql/test_types.py | 433 ++++++++++++++++++++++++--------------------- 2 files changed, 355 insertions(+), 393 deletions(-) (limited to 'test/sql') diff --git a/test/sql/test_operators.py b/test/sql/test_operators.py index 66fe18598..637f1f8a5 100644 --- a/test/sql/test_operators.py +++ b/test/sql/test_operators.py @@ -73,12 +73,41 @@ class LoopOperate(operators.ColumnOperators): class DefaultColumnComparatorTest(fixtures.TestBase): - def _do_scalar_test(self, operator, compare_to): + @testing.combinations((operators.desc_op, desc), (operators.asc_op, asc)) + def test_scalar(self, operator, compare_to): left = column("left") assert left.comparator.operate(operator).compare(compare_to(left)) self._loop_test(operator) - def _do_operate_test(self, operator, right=column("right")): + right_column = column("right") + + @testing.combinations( + (operators.add, right_column), + (operators.is_, None), + (operators.isnot, None), + (operators.is_, null()), + (operators.is_, true()), + (operators.is_, false()), + (operators.eq, True), + (operators.ne, True), + (operators.is_distinct_from, True), + (operators.is_distinct_from, False), + (operators.is_distinct_from, None), + (operators.isnot_distinct_from, True), + (operators.is_, True), + (operators.isnot, True), + (operators.is_, False), + (operators.isnot, False), + (operators.like_op, right_column), + (operators.notlike_op, right_column), + (operators.ilike_op, right_column), + (operators.notilike_op, right_column), + (operators.is_, right_column), + (operators.isnot, right_column), + (operators.concat_op, right_column), + id_="ns", + ) + def test_operate(self, operator, right): left = column("left") assert left.comparator.operate(operator, right).compare( @@ -109,84 +138,13 @@ class DefaultColumnComparatorTest(fixtures.TestBase): loop = LoopOperate() is_(operator(loop, *arg), operator) - def test_desc(self): - self._do_scalar_test(operators.desc_op, desc) - - def test_asc(self): - self._do_scalar_test(operators.asc_op, asc) - - def test_plus(self): - self._do_operate_test(operators.add) - - def test_is_null(self): - self._do_operate_test(operators.is_, None) - - def test_isnot_null(self): - self._do_operate_test(operators.isnot, None) - - def test_is_null_const(self): - self._do_operate_test(operators.is_, null()) - - def test_is_true_const(self): - self._do_operate_test(operators.is_, true()) - - def test_is_false_const(self): - self._do_operate_test(operators.is_, false()) - - def test_equals_true(self): - self._do_operate_test(operators.eq, True) - - def test_notequals_true(self): - self._do_operate_test(operators.ne, True) - - def test_is_distinct_from_true(self): - self._do_operate_test(operators.is_distinct_from, True) - - def test_is_distinct_from_false(self): - self._do_operate_test(operators.is_distinct_from, False) - - def test_is_distinct_from_null(self): - self._do_operate_test(operators.is_distinct_from, None) - - def test_isnot_distinct_from_true(self): - self._do_operate_test(operators.isnot_distinct_from, True) - - def test_is_true(self): - self._do_operate_test(operators.is_, True) - - def test_isnot_true(self): - self._do_operate_test(operators.isnot, True) - - def test_is_false(self): - self._do_operate_test(operators.is_, False) - - def test_isnot_false(self): - self._do_operate_test(operators.isnot, False) - - def test_like(self): - self._do_operate_test(operators.like_op) - - def test_notlike(self): - self._do_operate_test(operators.notlike_op) - - def test_ilike(self): - self._do_operate_test(operators.ilike_op) - - def test_notilike(self): - self._do_operate_test(operators.notilike_op) - - def test_is(self): - self._do_operate_test(operators.is_) - - def test_isnot(self): - self._do_operate_test(operators.isnot) - def test_no_getitem(self): assert_raises_message( NotImplementedError, "Operator 'getitem' is not supported on this expression", - self._do_operate_test, + self.test_operate, operators.getitem, + column("right"), ) assert_raises_message( NotImplementedError, @@ -274,9 +232,6 @@ class DefaultColumnComparatorTest(fixtures.TestBase): collate(left, right) ) - def test_concat(self): - self._do_operate_test(operators.concat_op) - def test_default_adapt(self): class TypeOne(TypeEngine): pass @@ -329,7 +284,8 @@ class DefaultColumnComparatorTest(fixtures.TestBase): class CustomUnaryOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): __dialect__ = "default" - def _factorial_fixture(self): + @testing.fixture + def factorial(self): class MyInteger(Integer): class comparator_factory(Integer.Comparator): def factorial(self): @@ -355,24 +311,24 @@ class CustomUnaryOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): return MyInteger - def test_factorial(self): - col = column("somecol", self._factorial_fixture()) + def test_factorial(self, factorial): + col = column("somecol", factorial()) self.assert_compile(col.factorial(), "somecol !") - def test_double_factorial(self): - col = column("somecol", self._factorial_fixture()) + def test_double_factorial(self, factorial): + col = column("somecol", factorial()) self.assert_compile(col.factorial().factorial(), "somecol ! !") - def test_factorial_prefix(self): - col = column("somecol", self._factorial_fixture()) + def test_factorial_prefix(self, factorial): + col = column("somecol", factorial()) self.assert_compile(col.factorial_prefix(), "!! somecol") - def test_factorial_invert(self): - col = column("somecol", self._factorial_fixture()) + def test_factorial_invert(self, factorial): + col = column("somecol", factorial()) self.assert_compile(~col, "!!! somecol") - def test_double_factorial_invert(self): - col = column("somecol", self._factorial_fixture()) + def test_double_factorial_invert(self, factorial): + col = column("somecol", factorial()) self.assert_compile(~(~col), "!!! (!!! somecol)") def test_unary_no_ops(self): @@ -1845,7 +1801,15 @@ class MathOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): table1 = table("mytable", column("myid", Integer)) - def _test_math_op(self, py_op, sql_op): + @testing.combinations( + ("add", operator.add, "+"), + ("mul", operator.mul, "*"), + ("sub", operator.sub, "-"), + ("div", operator.truediv if util.py3k else operator.div, "/"), + ("mod", operator.mod, "%"), + id_="iaa", + ) + def test_math_op(self, py_op, sql_op): for (lhs, rhs, res) in ( (5, self.table1.c.myid, ":myid_1 %s mytable.myid"), (5, literal(5), ":param_1 %s :param_2"), @@ -1862,24 +1826,6 @@ class MathOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): ): self.assert_compile(py_op(lhs, rhs), res % sql_op) - def test_math_op_add(self): - self._test_math_op(operator.add, "+") - - def test_math_op_mul(self): - self._test_math_op(operator.mul, "*") - - def test_math_op_sub(self): - self._test_math_op(operator.sub, "-") - - def test_math_op_div(self): - if util.py3k: - self._test_math_op(operator.truediv, "/") - else: - self._test_math_op(operator.div, "/") - - def test_math_op_mod(self): - self._test_math_op(operator.mod, "%") - class ComparisonOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): __dialect__ = "default" @@ -1898,7 +1844,16 @@ class ComparisonOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): clause = tuple_(1, 2, 3) eq_(str(clause), str(util.pickle.loads(util.pickle.dumps(clause)))) - def _test_comparison_op(self, py_op, fwd_op, rev_op): + @testing.combinations( + (operator.lt, "<", ">"), + (operator.gt, ">", "<"), + (operator.eq, "=", "="), + (operator.ne, "!=", "!="), + (operator.le, "<=", ">="), + (operator.ge, ">=", "<="), + id_="naa", + ) + def test_comparison_op(self, py_op, fwd_op, rev_op): dt = datetime.datetime(2012, 5, 10, 15, 27, 18) for (lhs, rhs, l_sql, r_sql) in ( ("a", self.table1.c.myid, ":myid_1", "mytable.myid"), @@ -1935,24 +1890,6 @@ class ComparisonOperatorTest(fixtures.TestBase, testing.AssertsCompiledSQL): + "'", ) - def test_comparison_operators_lt(self): - self._test_comparison_op(operator.lt, "<", ">"), - - def test_comparison_operators_gt(self): - self._test_comparison_op(operator.gt, ">", "<") - - def test_comparison_operators_eq(self): - self._test_comparison_op(operator.eq, "=", "=") - - def test_comparison_operators_ne(self): - self._test_comparison_op(operator.ne, "!=", "!=") - - def test_comparison_operators_le(self): - self._test_comparison_op(operator.le, "<=", ">=") - - def test_comparison_operators_ge(self): - self._test_comparison_op(operator.ge, ">=", "<=") - class NonZeroTest(fixtures.TestBase): def _raises(self, expr): @@ -2690,38 +2627,39 @@ class CustomOpTest(fixtures.TestBase): assert operators.is_comparison(op1) assert not operators.is_comparison(op2) - def test_return_types(self): + @testing.combinations( + (sqltypes.NULLTYPE,), + (Integer(),), + (ARRAY(String),), + (String(50),), + (Boolean(),), + (DateTime(),), + (sqltypes.JSON(),), + (postgresql.ARRAY(Integer),), + (sqltypes.Numeric(5, 2),), + id_="r", + ) + def test_return_types(self, typ): some_return_type = sqltypes.DECIMAL() - for typ in [ - sqltypes.NULLTYPE, - Integer(), - ARRAY(String), - String(50), - Boolean(), - DateTime(), - sqltypes.JSON(), - postgresql.ARRAY(Integer), - sqltypes.Numeric(5, 2), - ]: - c = column("x", typ) - expr = c.op("$", is_comparison=True)(None) - is_(expr.type, sqltypes.BOOLEANTYPE) + c = column("x", typ) + expr = c.op("$", is_comparison=True)(None) + is_(expr.type, sqltypes.BOOLEANTYPE) - c = column("x", typ) - expr = c.bool_op("$")(None) - is_(expr.type, sqltypes.BOOLEANTYPE) + c = column("x", typ) + expr = c.bool_op("$")(None) + is_(expr.type, sqltypes.BOOLEANTYPE) - expr = c.op("$")(None) - is_(expr.type, typ) + expr = c.op("$")(None) + is_(expr.type, typ) - expr = c.op("$", return_type=some_return_type)(None) - is_(expr.type, some_return_type) + expr = c.op("$", return_type=some_return_type)(None) + is_(expr.type, some_return_type) - expr = c.op("$", is_comparison=True, return_type=some_return_type)( - None - ) - is_(expr.type, some_return_type) + expr = c.op("$", is_comparison=True, return_type=some_return_type)( + None + ) + is_(expr.type, some_return_type) class TupleTypingTest(fixtures.TestBase): @@ -2756,7 +2694,8 @@ class TupleTypingTest(fixtures.TestBase): class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): __dialect__ = "default" - def _fixture(self): + @testing.fixture + def t_fixture(self): m = MetaData() t = Table( @@ -2767,8 +2706,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): ) return t - def test_any_array(self): - t = self._fixture() + def test_any_array(self, t_fixture): + t = t_fixture self.assert_compile( 5 == any_(t.c.arrval), @@ -2776,8 +2715,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_any_array_method(self): - t = self._fixture() + def test_any_array_method(self, t_fixture): + t = t_fixture self.assert_compile( 5 == t.c.arrval.any_(), @@ -2785,8 +2724,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_all_array(self): - t = self._fixture() + def test_all_array(self, t_fixture): + t = t_fixture self.assert_compile( 5 == all_(t.c.arrval), @@ -2794,8 +2733,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_all_array_method(self): - t = self._fixture() + def test_all_array_method(self, t_fixture): + t = t_fixture self.assert_compile( 5 == t.c.arrval.all_(), @@ -2803,8 +2742,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_any_comparator_array(self): - t = self._fixture() + def test_any_comparator_array(self, t_fixture): + t = t_fixture self.assert_compile( 5 > any_(t.c.arrval), @@ -2812,8 +2751,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_all_comparator_array(self): - t = self._fixture() + def test_all_comparator_array(self, t_fixture): + t = t_fixture self.assert_compile( 5 > all_(t.c.arrval), @@ -2821,8 +2760,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_any_comparator_array_wexpr(self): - t = self._fixture() + def test_any_comparator_array_wexpr(self, t_fixture): + t = t_fixture self.assert_compile( t.c.data > any_(t.c.arrval), @@ -2830,8 +2769,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={}, ) - def test_all_comparator_array_wexpr(self): - t = self._fixture() + def test_all_comparator_array_wexpr(self, t_fixture): + t = t_fixture self.assert_compile( t.c.data > all_(t.c.arrval), @@ -2839,8 +2778,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={}, ) - def test_illegal_ops(self): - t = self._fixture() + def test_illegal_ops(self, t_fixture): + t = t_fixture assert_raises_message( exc.ArgumentError, @@ -2856,8 +2795,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): t.c.data + all_(t.c.arrval), "tab1.data + ALL (tab1.arrval)" ) - def test_any_array_comparator_accessor(self): - t = self._fixture() + def test_any_array_comparator_accessor(self, t_fixture): + t = t_fixture self.assert_compile( t.c.arrval.any(5, operator.gt), @@ -2865,8 +2804,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_all_array_comparator_accessor(self): - t = self._fixture() + def test_all_array_comparator_accessor(self, t_fixture): + t = t_fixture self.assert_compile( t.c.arrval.all(5, operator.gt), @@ -2874,8 +2813,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"param_1": 5}, ) - def test_any_array_expression(self): - t = self._fixture() + def test_any_array_expression(self, t_fixture): + t = t_fixture self.assert_compile( 5 == any_(t.c.arrval[5:6] + postgresql.array([3, 4])), @@ -2891,8 +2830,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): dialect="postgresql", ) - def test_all_array_expression(self): - t = self._fixture() + def test_all_array_expression(self, t_fixture): + t = t_fixture self.assert_compile( 5 == all_(t.c.arrval[5:6] + postgresql.array([3, 4])), @@ -2908,8 +2847,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): dialect="postgresql", ) - def test_any_subq(self): - t = self._fixture() + def test_any_subq(self, t_fixture): + t = t_fixture self.assert_compile( 5 @@ -2919,8 +2858,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"data_1": 10, "param_1": 5}, ) - def test_any_subq_method(self): - t = self._fixture() + def test_any_subq_method(self, t_fixture): + t = t_fixture self.assert_compile( 5 @@ -2933,8 +2872,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"data_1": 10, "param_1": 5}, ) - def test_all_subq(self): - t = self._fixture() + def test_all_subq(self, t_fixture): + t = t_fixture self.assert_compile( 5 @@ -2944,8 +2883,8 @@ class AnyAllTest(fixtures.TestBase, testing.AssertsCompiledSQL): checkparams={"data_1": 10, "param_1": 5}, ) - def test_all_subq_method(self): - t = self._fixture() + def test_all_subq_method(self, t_fixture): + t = t_fixture self.assert_compile( 5 diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 7bf83b461..2ffdd83b7 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -5,6 +5,7 @@ import importlib import operator import os +import sqlalchemy as sa from sqlalchemy import and_ from sqlalchemy import ARRAY from sqlalchemy import BigInteger @@ -87,42 +88,83 @@ from sqlalchemy.testing.util import round_decimal from sqlalchemy.util import OrderedDict -class AdaptTest(fixtures.TestBase): - def _all_dialect_modules(self): - return [ - importlib.import_module("sqlalchemy.dialects.%s" % d) - for d in dialects.__all__ - if not d.startswith("_") - ] +def _all_dialect_modules(): + return [ + importlib.import_module("sqlalchemy.dialects.%s" % d) + for d in dialects.__all__ + if not d.startswith("_") + ] - def _all_dialects(self): - return [d.base.dialect() for d in self._all_dialect_modules()] - def _types_for_mod(self, mod): - for key in dir(mod): - typ = getattr(mod, key) - if not isinstance(typ, type) or not issubclass( - typ, types.TypeEngine - ): - continue - yield typ +def _all_dialects(): + return [d.base.dialect() for d in _all_dialect_modules()] - def _all_types(self): - for typ in self._types_for_mod(types): - yield typ - for dialect in self._all_dialect_modules(): - for typ in self._types_for_mod(dialect): - yield typ - def test_uppercase_importable(self): - import sqlalchemy as sa +def _types_for_mod(mod): + for key in dir(mod): + typ = getattr(mod, key) + if not isinstance(typ, type) or not issubclass(typ, types.TypeEngine): + continue + yield typ - for typ in self._types_for_mod(types): - if typ.__name__ == typ.__name__.upper(): - assert getattr(sa, typ.__name__) is typ - assert typ.__name__ in types.__all__ - def test_uppercase_rendering(self): +def _all_types(omit_special_types=False): + seen = set() + for typ in _types_for_mod(types): + if omit_special_types and typ in ( + types.TypeDecorator, + types.TypeEngine, + types.Variant, + ): + continue + + if typ in seen: + continue + seen.add(typ) + yield typ + for dialect in _all_dialect_modules(): + for typ in _types_for_mod(dialect): + if typ in seen: + continue + seen.add(typ) + yield typ + + +class AdaptTest(fixtures.TestBase): + @testing.combinations(((t,) for t in _types_for_mod(types)), id_="n") + def test_uppercase_importable(self, typ): + if typ.__name__ == typ.__name__.upper(): + assert getattr(sa, typ.__name__) is typ + assert typ.__name__ in types.__all__ + + @testing.combinations( + ((d.name, d) for d in _all_dialects()), argnames="dialect", id_="ia" + ) + @testing.combinations( + (REAL(), "REAL"), + (FLOAT(), "FLOAT"), + (NUMERIC(), "NUMERIC"), + (DECIMAL(), "DECIMAL"), + (INTEGER(), "INTEGER"), + (SMALLINT(), "SMALLINT"), + (TIMESTAMP(), ("TIMESTAMP", "TIMESTAMP WITHOUT TIME ZONE")), + (DATETIME(), "DATETIME"), + (DATE(), "DATE"), + (TIME(), ("TIME", "TIME WITHOUT TIME ZONE")), + (CLOB(), "CLOB"), + (VARCHAR(10), ("VARCHAR(10)", "VARCHAR(10 CHAR)")), + ( + NVARCHAR(10), + ("NVARCHAR(10)", "NATIONAL VARCHAR(10)", "NVARCHAR2(10)"), + ), + (CHAR(), "CHAR"), + (NCHAR(), ("NCHAR", "NATIONAL CHAR")), + (BLOB(), ("BLOB", "BLOB SUB_TYPE 0")), + (BOOLEAN(), ("BOOLEAN", "BOOL", "INTEGER")), + argnames="type_, expected", + id_="ra", + ) + def test_uppercase_rendering(self, dialect, type_, expected): """Test that uppercase types from types.py always render as their type. @@ -133,51 +175,48 @@ class AdaptTest(fixtures.TestBase): """ - for dialect in self._all_dialects(): - for type_, expected in ( - (REAL, "REAL"), - (FLOAT, "FLOAT"), - (NUMERIC, "NUMERIC"), - (DECIMAL, "DECIMAL"), - (INTEGER, "INTEGER"), - (SMALLINT, "SMALLINT"), - (TIMESTAMP, ("TIMESTAMP", "TIMESTAMP WITHOUT TIME ZONE")), - (DATETIME, "DATETIME"), - (DATE, "DATE"), - (TIME, ("TIME", "TIME WITHOUT TIME ZONE")), - (CLOB, "CLOB"), - (VARCHAR(10), ("VARCHAR(10)", "VARCHAR(10 CHAR)")), - ( - NVARCHAR(10), - ("NVARCHAR(10)", "NATIONAL VARCHAR(10)", "NVARCHAR2(10)"), - ), - (CHAR, "CHAR"), - (NCHAR, ("NCHAR", "NATIONAL CHAR")), - (BLOB, ("BLOB", "BLOB SUB_TYPE 0")), - (BOOLEAN, ("BOOLEAN", "BOOL", "INTEGER")), - ): - if isinstance(expected, str): - expected = (expected,) + if isinstance(expected, str): + expected = (expected,) - try: - compiled = types.to_instance(type_).compile( - dialect=dialect - ) - except NotImplementedError: - continue + try: + compiled = type_.compile(dialect=dialect) + except NotImplementedError: + return - assert compiled in expected, ( - "%r matches none of %r for dialect %s" - % (compiled, expected, dialect.name) - ) + assert compiled in expected, "%r matches none of %r for dialect %s" % ( + compiled, + expected, + dialect.name, + ) - assert str(types.to_instance(type_)) in expected, ( - "default str() of type %r not expected, %r" - % (type_, expected) - ) + assert ( + str(types.to_instance(type_)) in expected + ), "default str() of type %r not expected, %r" % (type_, expected) + + def _adaptions(): + for typ in _all_types(omit_special_types=True): + + # up adapt from LowerCase to UPPERCASE, + # as well as to all non-sqltypes + up_adaptions = [typ] + typ.__subclasses__() + yield "%s.%s" % ( + typ.__module__, + typ.__name__, + ), False, typ, up_adaptions + for subcl in typ.__subclasses__(): + if ( + subcl is not typ + and typ is not TypeDecorator + and "sqlalchemy" in subcl.__module__ + ): + yield "%s.%s" % ( + subcl.__module__, + subcl.__name__, + ), True, subcl, [typ] @testing.uses_deprecated(".*Binary.*") - def test_adapt_method(self): + @testing.combinations(_adaptions(), id_="iaaa") + def test_adapt_method(self, is_down_adaption, typ, target_adaptions): """ensure all types have a working adapt() method, which creates a distinct copy. @@ -190,67 +229,44 @@ class AdaptTest(fixtures.TestBase): """ - def adaptions(): - for typ in self._all_types(): - # up adapt from LowerCase to UPPERCASE, - # as well as to all non-sqltypes - up_adaptions = [typ] + typ.__subclasses__() - yield False, typ, up_adaptions - for subcl in typ.__subclasses__(): - if ( - subcl is not typ - and typ is not TypeDecorator - and "sqlalchemy" in subcl.__module__ - ): - yield True, subcl, [typ] - - for is_down_adaption, typ, target_adaptions in adaptions(): - if typ in (types.TypeDecorator, types.TypeEngine, types.Variant): + if issubclass(typ, ARRAY): + t1 = typ(String) + else: + t1 = typ() + for cls in target_adaptions: + if (is_down_adaption and issubclass(typ, sqltypes.Emulated)) or ( + not is_down_adaption and issubclass(cls, sqltypes.Emulated) + ): continue - elif issubclass(typ, ARRAY): - t1 = typ(String) - else: - t1 = typ() - for cls in target_adaptions: - if ( - is_down_adaption and issubclass(typ, sqltypes.Emulated) - ) or ( - not is_down_adaption and issubclass(cls, sqltypes.Emulated) - ): - continue - if cls.__module__.startswith("test"): + # print("ADAPT %s -> %s" % (t1.__class__, cls)) + t2 = t1.adapt(cls) + assert t1 is not t2 + + if is_down_adaption: + t2, t1 = t1, t2 + + for k in t1.__dict__: + if k in ( + "impl", + "_is_oracle_number", + "_create_events", + "create_constraint", + "inherit_schema", + "schema", + "metadata", + "name", + ): continue + # assert each value was copied, or that + # the adapted type has a more specific + # value than the original (i.e. SQL Server + # applies precision=24 for REAL) + assert ( + getattr(t2, k) == t1.__dict__[k] or t1.__dict__[k] is None + ) - # print("ADAPT %s -> %s" % (t1.__class__, cls)) - t2 = t1.adapt(cls) - assert t1 is not t2 - - if is_down_adaption: - t2, t1 = t1, t2 - - for k in t1.__dict__: - if k in ( - "impl", - "_is_oracle_number", - "_create_events", - "create_constraint", - "inherit_schema", - "schema", - "metadata", - "name", - ): - continue - # assert each value was copied, or that - # the adapted type has a more specific - # value than the original (i.e. SQL Server - # applies precision=24 for REAL) - assert ( - getattr(t2, k) == t1.__dict__[k] - or t1.__dict__[k] is None - ) - - eq_(t1.evaluates_none().should_evaluate_none, True) + eq_(t1.evaluates_none().should_evaluate_none, True) def test_python_type(self): eq_(types.Integer().python_type, int) @@ -270,15 +286,13 @@ class AdaptTest(fixtures.TestBase): ) @testing.uses_deprecated() - def test_repr(self): - for typ in self._all_types(): - if typ in (types.TypeDecorator, types.TypeEngine, types.Variant): - continue - elif issubclass(typ, ARRAY): - t1 = typ(String) - else: - t1 = typ() - repr(t1) + @testing.combinations(*[(t,) for t in _all_types(omit_special_types=True)]) + def test_repr(self, typ): + if issubclass(typ, ARRAY): + t1 = typ(String) + else: + t1 = typ() + repr(t1) def test_adapt_constructor_copy_override_kw(self): """test that adapt() can accept kw args that override @@ -299,27 +313,30 @@ class AdaptTest(fixtures.TestBase): class TypeAffinityTest(fixtures.TestBase): - def test_type_affinity(self): - for type_, affin in [ - (String(), String), - (VARCHAR(), String), - (Date(), Date), - (LargeBinary(), types._Binary), - ]: - eq_(type_._type_affinity, affin) - - for t1, t2, comp in [ - (Integer(), SmallInteger(), True), - (Integer(), String(), False), - (Integer(), Integer(), True), - (Text(), String(), True), - (Text(), Unicode(), True), - (LargeBinary(), Integer(), False), - (LargeBinary(), PickleType(), True), - (PickleType(), LargeBinary(), True), - (PickleType(), PickleType(), True), - ]: - eq_(t1._compare_type_affinity(t2), comp, "%s %s" % (t1, t2)) + @testing.combinations( + (String(), String), + (VARCHAR(), String), + (Date(), Date), + (LargeBinary(), types._Binary), + id_="rn", + ) + def test_type_affinity(self, type_, affin): + eq_(type_._type_affinity, affin) + + @testing.combinations( + (Integer(), SmallInteger(), True), + (Integer(), String(), False), + (Integer(), Integer(), True), + (Text(), String(), True), + (Text(), Unicode(), True), + (LargeBinary(), Integer(), False), + (LargeBinary(), PickleType(), True), + (PickleType(), LargeBinary(), True), + (PickleType(), PickleType(), True), + id_="rra", + ) + def test_compare_type_affinity(self, t1, t2, comp): + eq_(t1._compare_type_affinity(t2), comp, "%s %s" % (t1, t2)) def test_decorator_doesnt_cache(self): from sqlalchemy.dialects import postgresql @@ -340,30 +357,32 @@ class TypeAffinityTest(fixtures.TestBase): class PickleTypesTest(fixtures.TestBase): - def test_pickle_types(self): + @testing.combinations( + ("Boo", Boolean()), + ("Str", String()), + ("Tex", Text()), + ("Uni", Unicode()), + ("Int", Integer()), + ("Sma", SmallInteger()), + ("Big", BigInteger()), + ("Num", Numeric()), + ("Flo", Float()), + ("Dat", DateTime()), + ("Dat", Date()), + ("Tim", Time()), + ("Lar", LargeBinary()), + ("Pic", PickleType()), + ("Int", Interval()), + id_="ar", + ) + def test_pickle_types(self, name, type_): + column_type = Column(name, type_) + meta = MetaData() + Table("foo", meta, column_type) + for loads, dumps in picklers(): - column_types = [ - Column("Boo", Boolean()), - Column("Str", String()), - Column("Tex", Text()), - Column("Uni", Unicode()), - Column("Int", Integer()), - Column("Sma", SmallInteger()), - Column("Big", BigInteger()), - Column("Num", Numeric()), - Column("Flo", Float()), - Column("Dat", DateTime()), - Column("Dat", Date()), - Column("Tim", Time()), - Column("Lar", LargeBinary()), - Column("Pic", PickleType()), - Column("Int", Interval()), - ] - for column_type in column_types: - meta = MetaData() - Table("foo", meta, column_type) - loads(dumps(column_type)) - loads(dumps(meta)) + loads(dumps(column_type)) + loads(dumps(meta)) class _UserDefinedTypeFixture(object): @@ -2414,19 +2433,19 @@ class ExpressionTest( expr = column("foo", CHAR) == "asdf" eq_(expr.right.type.__class__, CHAR) - def test_actual_literal_adapters(self): - for data, expected in [ - (5, Integer), - (2.65, Float), - (True, Boolean), - (decimal.Decimal("2.65"), Numeric), - (datetime.date(2015, 7, 20), Date), - (datetime.time(10, 15, 20), Time), - (datetime.datetime(2015, 7, 20, 10, 15, 20), DateTime), - (datetime.timedelta(seconds=5), Interval), - (None, types.NullType), - ]: - is_(literal(data).type.__class__, expected) + @testing.combinations( + (5, Integer), + (2.65, Float), + (True, Boolean), + (decimal.Decimal("2.65"), Numeric), + (datetime.date(2015, 7, 20), Date), + (datetime.time(10, 15, 20), Time), + (datetime.datetime(2015, 7, 20, 10, 15, 20), DateTime), + (datetime.timedelta(seconds=5), Interval), + (None, types.NullType), + ) + def test_actual_literal_adapters(self, data, expected): + is_(literal(data).type.__class__, expected) def test_typedec_operator_adapt(self): expr = test_table.c.bvalue + "hi" @@ -2592,18 +2611,22 @@ class ExpressionTest( expr = column("bar", types.Interval) * column("foo", types.Numeric) eq_(expr.type._type_affinity, types.Interval) - def test_numerics_coercion(self): - - for op in (operator.add, operator.mul, operator.truediv, operator.sub): - for other in (Numeric(10, 2), Integer): - expr = op( - column("bar", types.Numeric(10, 2)), column("foo", other) - ) - assert isinstance(expr.type, types.Numeric) - expr = op( - column("foo", other), column("bar", types.Numeric(10, 2)) - ) - assert isinstance(expr.type, types.Numeric) + @testing.combinations( + (operator.add,), + (operator.mul,), + (operator.truediv,), + (operator.sub,), + argnames="op", + id_="n", + ) + @testing.combinations( + (Numeric(10, 2),), (Integer(),), argnames="other", id_="r" + ) + def test_numerics_coercion(self, op, other): + expr = op(column("bar", types.Numeric(10, 2)), column("foo", other)) + assert isinstance(expr.type, types.Numeric) + expr = op(column("foo", other), column("bar", types.Numeric(10, 2))) + assert isinstance(expr.type, types.Numeric) def test_asdecimal_int_to_numeric(self): expr = column("a", Integer) * column("b", Numeric(asdecimal=False)) -- cgit v1.2.1