diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-06-27 13:25:12 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-06-27 16:27:22 -0400 |
commit | 401a2691fbeebd5a26341e732644584cb096bc58 (patch) | |
tree | fe188b760decdc2abbf4f568c8b4a2508cd22805 | |
parent | ec2c32bf93cc6fd60db87009643ece32c7926021 (diff) | |
download | sqlalchemy-401a2691fbeebd5a26341e732644584cb096bc58.tar.gz |
Unwrap TIMESTAMP when doing an isinstance()
Fixed bug where the special logic to render "NULL" for the
:class:`.TIMESTAMP` datatype when ``nullable=True`` would not work if the
column's datatype were a :class:`.TypeDecorator` or a :class:`.Variant`.
The logic now ensures that it unwraps down to the original
:class:`.TIMESTAMP` so that this special case NULL keyword is correctly
rendered when requested.
Fixes: #4743
Change-Id: I02b22dfa3db06daea37b044e2206a8569e2e5d22
-rw-r--r-- | .pre-commit-config.yaml | 2 | ||||
-rw-r--r-- | doc/build/changelog/unreleased_13/4743.rst | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 5 | ||||
-rw-r--r-- | test/dialect/mysql/test_types.py | 21 |
4 files changed, 32 insertions, 6 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e11efe17b..f9b217e55 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: rev: 19.3b0 hooks: - id: black - args: [-l 79, --target-version=py27] + args: [-l 79] - repo: https://github.com/sqlalchemyorg/zimports/ rev: master diff --git a/doc/build/changelog/unreleased_13/4743.rst b/doc/build/changelog/unreleased_13/4743.rst new file mode 100644 index 000000000..0bac5dc68 --- /dev/null +++ b/doc/build/changelog/unreleased_13/4743.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, mysql + :tickets: 4743 + + Fixed bug where the special logic to render "NULL" for the + :class:`.TIMESTAMP` datatype when ``nullable=True`` would not work if the + column's datatype were a :class:`.TypeDecorator` or a :class:`.Variant`. + The logic now ensures that it unwraps down to the original + :class:`.TIMESTAMP` so that this special case NULL keyword is correctly + rendered when requested. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index da76201f2..3c2e8e84b 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1501,7 +1501,10 @@ class MySQLDDLCompiler(compiler.DDLCompiler): ), ] - is_timestamp = isinstance(column.type, sqltypes.TIMESTAMP) + is_timestamp = isinstance( + column.type._unwrapped_dialect_impl(self.dialect), + sqltypes.TIMESTAMP, + ) if not column.nullable: colspec.append("NOT NULL") diff --git a/test/dialect/mysql/test_types.py b/test/dialect/mysql/test_types.py index 2801c800b..86e4b13a0 100644 --- a/test/dialect/mysql/test_types.py +++ b/test/dialect/mysql/test_types.py @@ -1,5 +1,4 @@ # coding: utf-8 - from collections import OrderedDict import datetime import decimal @@ -19,6 +18,7 @@ from sqlalchemy import String from sqlalchemy import Table from sqlalchemy import testing from sqlalchemy import TIMESTAMP +from sqlalchemy import TypeDecorator from sqlalchemy import types as sqltypes from sqlalchemy import UnicodeText from sqlalchemy import util @@ -667,14 +667,27 @@ class TypesTest( Table("t", MetaData(), c) self.assert_compile(schema.CreateColumn(c), "t %s" % expected) + def test_timestamp_nullable_plain(self): + self._test_timestamp_nullable(TIMESTAMP) + + def test_timestamp_nullable_typedecorator(self): + class MyTime(TypeDecorator): + impl = TIMESTAMP + + self._test_timestamp_nullable(MyTime()) + + def test_timestamp_nullable_variant(self): + t = String().with_variant(TIMESTAMP, "mysql") + self._test_timestamp_nullable(t) + @testing.requires.mysql_zero_date @testing.provide_metadata - def test_timestamp_nullable(self): + def _test_timestamp_nullable(self, type_): ts_table = Table( "mysql_timestamp", self.metadata, - Column("t1", TIMESTAMP), - Column("t2", TIMESTAMP, nullable=False), + Column("t1", type_), + Column("t2", type_, nullable=False), mysql_engine="InnoDB", ) self.metadata.create_all() |