summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-10-20 10:24:40 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-10-20 14:14:50 -0400
commit30bd28fca2091e4b2b093154a14c668c09ae3ccd (patch)
tree3fe9647770d95e31f0a4cb2695ae9738cf6df372
parent39ac19510989390dddf7a51f65ec7c8830ec04d1 (diff)
downloadsqlalchemy-30bd28fca2091e4b2b093154a14c668c09ae3ccd.tar.gz
Ensure TypeDecorator delegates _set_parent_with_dispatch
Ensure TypeDecorator delegates _set_parent_with_dispatch as well as _set_parent to itself as well as its impl, as the TypeDecorator class itself may have an active SchemaType implementation as well. Fixed regression which occurred as a side effect of :ticket:`2919`, which in the less typical case of a user-defined :class:`.TypeDecorator` that was also itself an instance of :class:`.SchemaType` (rather than the implementation being such) would cause the column attachment events to be skipped for the type itself. Change-Id: I0afb498fd91ab7d948e4439e7323a89eafcce0bc Fixes: #3832
-rw-r--r--doc/build/changelog/changelog_11.rst12
-rw-r--r--lib/sqlalchemy/sql/base.py2
-rw-r--r--lib/sqlalchemy/sql/type_api.py4
-rw-r--r--test/sql/test_metadata.py67
4 files changed, 83 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst
index c8785b766..3c00736c7 100644
--- a/doc/build/changelog/changelog_11.rst
+++ b/doc/build/changelog/changelog_11.rst
@@ -21,6 +21,18 @@
.. changelog::
:version: 1.1.3
+ .. change::
+ :tags: bug, sql
+ :tickets: 3832
+
+ Fixed regression which occurred as a side effect of :ticket:`2919`,
+ which in the less typical case of a user-defined
+ :class:`.TypeDecorator` that was also itself an instance of
+ :class:`.SchemaType` (rather than the implementation being such)
+ would cause the column attachment events to be skipped for the
+ type itself.
+
+
.. changelog::
:version: 1.1.2
:released: October 17, 2016
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py
index cf7dcfd31..0b036847b 100644
--- a/lib/sqlalchemy/sql/base.py
+++ b/lib/sqlalchemy/sql/base.py
@@ -426,8 +426,6 @@ class SchemaEventTarget(object):
def _set_parent(self, parent):
"""Associate with this SchemaEvent's parent object."""
- raise NotImplementedError()
-
def _set_parent_with_dispatch(self, parent):
self.dispatch.before_parent_attach(self, parent)
self._set_parent(parent)
diff --git a/lib/sqlalchemy/sql/type_api.py b/lib/sqlalchemy/sql/type_api.py
index 689b4c79b..98ede4e66 100644
--- a/lib/sqlalchemy/sql/type_api.py
+++ b/lib/sqlalchemy/sql/type_api.py
@@ -860,12 +860,16 @@ class TypeDecorator(SchemaEventTarget, TypeEngine):
def _set_parent(self, column):
"""Support SchemaEentTarget"""
+ super(TypeDecorator, self)._set_parent(column)
+
if isinstance(self.impl, SchemaEventTarget):
self.impl._set_parent(column)
def _set_parent_with_dispatch(self, parent):
"""Support SchemaEentTarget"""
+ super(TypeDecorator, self)._set_parent_with_dispatch(parent)
+
if isinstance(self.impl, SchemaEventTarget):
self.impl._set_parent_with_dispatch(parent)
diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py
index f2df4da06..f790c2aa0 100644
--- a/test/sql/test_metadata.py
+++ b/test/sql/test_metadata.py
@@ -1574,6 +1574,66 @@ class SchemaTypeTest(fixtures.TestBase):
class MyTypeImpl(MyTypeWImpl):
pass
+ class MyTypeDecAndSchema(TypeDecorator, sqltypes.SchemaType):
+ impl = String()
+
+ evt_targets = ()
+
+ def __init__(self):
+ TypeDecorator.__init__(self)
+ sqltypes.SchemaType.__init__(self)
+
+ def _on_table_create(self, target, bind, **kw):
+ self.evt_targets += (target,)
+
+ def _on_metadata_create(self, target, bind, **kw):
+ self.evt_targets += (target,)
+
+ def test_before_parent_attach_plain(self):
+ typ = self.MyType()
+ self._test_before_parent_attach(typ)
+
+ def test_before_parent_attach_typedec_enclosing_schematype(self):
+ # additional test for [ticket:2919] as part of test for
+ # [ticket:3832]
+
+ class MySchemaType(sqltypes.TypeEngine, sqltypes.SchemaType):
+ pass
+
+ target_typ = MySchemaType()
+
+ class MyType(TypeDecorator):
+ impl = target_typ
+
+ typ = MyType()
+ self._test_before_parent_attach(typ, target_typ)
+
+ def test_before_parent_attach_typedec_of_schematype(self):
+ class MyType(TypeDecorator, sqltypes.SchemaType):
+ impl = String
+
+ typ = MyType()
+ self._test_before_parent_attach(typ)
+
+ def test_before_parent_attach_schematype_of_typedec(self):
+ class MyType(sqltypes.SchemaType, TypeDecorator):
+ impl = String
+
+ typ = MyType()
+ self._test_before_parent_attach(typ)
+
+ def _test_before_parent_attach(self, typ, evt_target=None):
+ canary = mock.Mock()
+
+ if evt_target is None:
+ evt_target = typ
+
+ event.listen(evt_target, "before_parent_attach", canary.go)
+
+ c = Column('q', typ)
+
+ eq_(canary.mock_calls, [mock.call.go(evt_target, c)])
+
def test_independent_schema(self):
m = MetaData()
type_ = self.MyType(schema="q")
@@ -1709,6 +1769,13 @@ class SchemaTypeTest(fixtures.TestBase):
dialect_impl = typ.dialect_impl(testing.db.dialect)
eq_(dialect_impl.evt_targets, (m1, ))
+ def test_table_dispatch_decorator_schematype(self):
+ m1 = MetaData()
+ typ = self.MyTypeDecAndSchema()
+ t1 = Table('t1', m1, Column('x', typ))
+ m1.dispatch.before_create(t1, testing.db)
+ eq_(typ.evt_targets, (t1, ))
+
def test_table_dispatch_no_new_impl(self):
m1 = MetaData()
typ = self.MyType()