From: Mike Bayer Date: Wed, 22 Jan 2014 20:38:00 +0000 (-0500) Subject: - Added new test coverage for so-called "down adaptions" of SQL types, X-Git-Tag: rel_0_9_2~36 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1732414076677e8fb84134325635729691f3d26d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added new test coverage for so-called "down adaptions" of SQL types, where a more specific type is adapted to a more generic one - this use case is needed by some third party tools such as ``sqlacodegen``. The specific cases that needed repair within this test suite were that of :class:`.mysql.ENUM` being downcast into a :class:`.types.Enum`, and that of SQLite date types being cast into generic date types. The ``adapt()`` method needed to become more specific here to counteract the removal of a "catch all" ``**kwargs`` collection on the base :class:`.TypeEngine` class that was removed in 0.9. [ticket:2917] --- diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index d59f3ec604..7683265284 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -14,6 +14,20 @@ .. changelog:: :version: 0.9.2 + .. change:: + :tags: bug, mysql, sql + :tickets: 2917 + + Added new test coverage for so-called "down adaptions" of SQL types, + where a more specific type is adapted to a more generic one - this + use case is needed by some third party tools such as ``sqlacodegen``. + The specific cases that needed repair within this test suite were that + of :class:`.mysql.ENUM` being downcast into a :class:`.types.Enum`, + and that of SQLite date types being cast into generic date types. + The ``adapt()`` method needed to become more specific here to counteract + the removal of a "catch all" ``**kwargs`` collection on the base + :class:`.TypeEngine` class that was removed in 0.9. + .. change:: :tags: feature, sql :tickets: 2910 diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index e45f6ecd85..61698b038e 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1189,9 +1189,10 @@ class ENUM(sqltypes.Enum, _EnumeratedValues): return value return process - def adapt(self, impltype, **kw): - kw['strict'] = self.strict - return sqltypes.Enum.adapt(self, impltype, **kw) + def adapt(self, cls, **kw): + if issubclass(cls, ENUM): + kw['strict'] = self.strict + return sqltypes.Enum.adapt(self, cls, **kw) class SET(_EnumeratedValues): diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index 579a61046c..d8aa58c2c1 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -154,11 +154,12 @@ class _DateTimeMixin(object): self._storage_format = storage_format def adapt(self, cls, **kw): - if self._storage_format: - kw["storage_format"] = self._storage_format - if self._reg: - kw["regexp"] = self._reg - return util.constructor_copy(self, cls, **kw) + if issubclass(cls, _DateTimeMixin): + if self._storage_format: + kw["storage_format"] = self._storage_format + if self._reg: + kw["regexp"] = self._reg + return super(_DateTimeMixin, self).adapt(cls, **kw) def literal_processor(self, dialect): bp = self.bind_processor(dialect) diff --git a/test/sql/test_types.py b/test/sql/test_types.py index 3a263aab2e..3df19874bf 100644 --- a/test/sql/test_types.py +++ b/test/sql/test_types.py @@ -114,21 +114,37 @@ class AdaptTest(fixtures.TestBase): """ - for typ in self._all_types(): + def adaptions(): + for typ in self._all_types(): + 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): continue elif typ is dialects.postgresql.ARRAY: t1 = typ(String) else: t1 = typ() - for cls in [typ] + typ.__subclasses__(): + for cls in target_adaptions: if not issubclass(typ, types.Enum) and \ issubclass(cls, types.Enum): continue + + # 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 == 'impl': + if k in ('impl', '_is_oracle_number'): continue # assert each value was copied, or that # the adapted type has a more specific