cols = insp.get_columns("data_table")
assert isinstance(cols[0]["type"], self._col_type)
+ def test_type_decorator_round_trip(self, connection, metadata):
+ """test #9020"""
+
+ class MyRange(TypeDecorator):
+ cache_ok = True
+ impl = self._col_type
+
+ table = Table(
+ "typedec_table",
+ metadata,
+ Column("range", MyRange, primary_key=True),
+ )
+ table.create(connection)
+ connection.execute(table.insert(), {"range": self._data_obj()})
+ data = connection.execute(
+ select(table.c.range).where(table.c.range == self._data_obj())
+ ).fetchall()
+ eq_(data, [(self._data_obj(),)])
+
def test_textual_round_trip_w_dialect_type(self, connection):
"""test #8690"""
data_table = self.tables.data_table
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
from sqlalchemy.testing import is_not
+from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.testing import pickleable
from sqlalchemy.testing.assertions import expect_raises_message
def _all_types(omit_special_types=False):
+ yield from (
+ typ
+ for typ, _ in _all_types_w_their_dialect(
+ omit_special_types=omit_special_types
+ )
+ )
+
+
+def _all_types_w_their_dialect(omit_special_types=False):
seen = set()
for typ in _types_for_mod(types):
if omit_special_types and (
type_api.TypeEngineMixin,
types.Variant,
types.TypeDecorator,
+ types.PickleType,
)
or type_api.TypeEngineMixin in typ.__bases__
):
if typ in seen:
continue
seen.add(typ)
- yield typ
+ yield typ, default.DefaultDialect
for dialect in _all_dialect_modules():
for typ in _types_for_mod(dialect):
if typ in seen:
continue
seen.add(typ)
- yield typ
+ yield typ, dialect.dialect
def _get_instance(type_):
t2 = t1.adapt(Text)
eq_(t2.length, 50)
+ @testing.combinations(
+ *[
+ (t, d)
+ for t, d in _all_types_w_their_dialect(omit_special_types=True)
+ ]
+ )
+ def test_every_possible_type_can_be_decorated(self, typ, dialect_cls):
+ """test for #9020
+
+ Apparently the adapt() method is called with the same class as given
+ in the case of :class:`.TypeDecorator`, at least with the
+ PostgreSQL RANGE types, which is not usually expected.
+
+ """
+ my_type = type("MyType", (TypeDecorator,), {"impl": typ})
+
+ if issubclass(typ, ARRAY):
+ inst = my_type(Integer)
+ elif issubclass(typ, pg.ENUM):
+ inst = my_type(name="my_enum")
+ elif issubclass(typ, pg.DOMAIN):
+ inst = my_type(name="my_domain", data_type=Integer)
+ else:
+ inst = my_type()
+ impl = inst._unwrapped_dialect_impl(dialect_cls())
+
+ if dialect_cls is default.DefaultDialect:
+ is_true(isinstance(impl, typ))
+
+ if impl._type_affinity is Interval:
+ is_true(issubclass(typ, sqltypes._AbstractInterval))
+ else:
+ is_true(issubclass(typ, impl._type_affinity))
+
class TypeAffinityTest(fixtures.TestBase):
@testing.combinations(