summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul <pbrackin@gmail.com>2017-02-20 15:20:17 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2017-02-21 16:28:51 -0500
commitf1cf86ea6a33a6fa09de4fb727f6383ce6698304 (patch)
treeeecf5d37a5392d1894c0f069d8ba27374d866365
parent44d028f42b2a27b8710f2d4d9443e11515814eb4 (diff)
downloadalembic-f1cf86ea6a33a6fa09de4fb727f6383ce6698304.tar.gz
Fix postgresql automigration for ARRAY types
Adds a new codepath into render._repr_type() that will consult the dialect impl for specific types. On the postgresql side, the exisiting repr() is combined with a replace featuring the full autogen render of the nested type. Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com> Fixes: #85 Change-Id: I8796bfeea27d48e6f8bb5ea4562bdc04961ba0d5 Pull-request: https://github.com/zzzeek/alembic/pull/38
-rw-r--r--alembic/autogenerate/render.py9
-rw-r--r--alembic/ddl/impl.py3
-rw-r--r--alembic/ddl/postgresql.py14
-rw-r--r--docs/build/changelog.rst9
-rw-r--r--tests/test_postgresql.py44
5 files changed, 76 insertions, 3 deletions
diff --git a/alembic/autogenerate/render.py b/alembic/autogenerate/render.py
index 476c1f9..6e10792 100644
--- a/alembic/autogenerate/render.py
+++ b/alembic/autogenerate/render.py
@@ -566,13 +566,20 @@ def _repr_type(type_, autogen_context):
if rendered is not False:
return rendered
+ if hasattr(autogen_context.migration_context, 'impl'):
+ impl_rt = autogen_context.migration_context.impl.render_type(
+ type_, autogen_context)
+
mod = type(type_).__module__
imports = autogen_context.imports
if mod.startswith("sqlalchemy.dialects"):
dname = re.match(r"sqlalchemy\.dialects\.(\w+)", mod).group(1)
if imports is not None:
imports.add("from sqlalchemy.dialects import %s" % dname)
- return "%s.%r" % (dname, type_)
+ if impl_rt:
+ return impl_rt
+ else:
+ return "%s.%r" % (dname, type_)
elif mod.startswith("sqlalchemy."):
prefix = _sqlalchemy_autogenerate_prefix(autogen_context)
return "%s%r" % (prefix, type_)
diff --git a/alembic/ddl/impl.py b/alembic/ddl/impl.py
index 52cc470..0971c21 100644
--- a/alembic/ddl/impl.py
+++ b/alembic/ddl/impl.py
@@ -320,6 +320,9 @@ class DefaultImpl(with_metaclass(ImplMeta)):
"""
self.static_output("COMMIT" + self.command_terminator)
+ def render_type(self, type_obj, autogen_context):
+ return False
+
def _string_compare(t1, t2):
return \
diff --git a/alembic/ddl/postgresql.py b/alembic/ddl/postgresql.py
index fa78e53..ecf0dda 100644
--- a/alembic/ddl/postgresql.py
+++ b/alembic/ddl/postgresql.py
@@ -6,6 +6,7 @@ from .base import compiles, alter_column, alter_table, format_table_name, \
format_type, AlterColumn, RenameTable
from .impl import DefaultImpl
from sqlalchemy.dialects.postgresql import INTEGER, BIGINT
+from ..autogenerate import render
from sqlalchemy import text, Numeric, Column
from sqlalchemy import types as sqltypes
@@ -105,7 +106,6 @@ class PostgresqlImpl(DefaultImpl):
**kw)
-
def autogen_column_reflect(self, inspector, table, column_info):
if column_info.get('default') and \
isinstance(column_info['type'], (INTEGER, BIGINT)):
@@ -171,6 +171,18 @@ class PostgresqlImpl(DefaultImpl):
)
metadata_indexes.discard(idx)
+ def render_type(self, type_, autogen_context):
+ if hasattr(self, '_render_%s_type' % type_.__visit_name__):
+ meth = getattr(self, '_render_%s_type' % type_.__visit_name__)
+ return meth(type_, autogen_context)
+
+ return False
+
+ def _render_ARRAY_type(self, type_, autogen_context):
+ sub_type = render._repr_type(type_.item_type, autogen_context)
+ outer_type = repr(type_).replace(repr(type_.item_type), sub_type)
+ return "%s.%s" % ("postgresql", outer_type)
+
class PostgresqlColumnType(AlterColumn):
diff --git a/docs/build/changelog.rst b/docs/build/changelog.rst
index 2ccdf6c..ca6834d 100644
--- a/docs/build/changelog.rst
+++ b/docs/build/changelog.rst
@@ -7,6 +7,15 @@ Changelog
:version: 0.9.0
:released:
+ .. change:: 85
+ :tags: bug, postgresql
+ :tickets: 85
+
+ Fixed bug where Postgresql ARRAY type would not render the import prefix
+ for the inner type; additionally, user-defined renderers take place
+ for the inner type as well as the outer type. Pull request courtesy
+ Paul Brackin.
+
.. change:: fk_schema_compare
:tags: bug, operations
diff --git a/tests/test_postgresql.py b/tests/test_postgresql.py
index 2a3378d..628357b 100644
--- a/tests/test_postgresql.py
+++ b/tests/test_postgresql.py
@@ -1,7 +1,7 @@
from sqlalchemy import DateTime, MetaData, Table, Column, text, Integer, \
String, Interval, Sequence, Numeric, BigInteger, Float, Numeric
-from sqlalchemy.dialects.postgresql import ARRAY, UUID
+from sqlalchemy.dialects.postgresql import ARRAY, UUID, BYTEA
from sqlalchemy.engine.reflection import Inspector
from alembic.operations import Operations
from sqlalchemy.sql import table, column
@@ -602,3 +602,45 @@ unique=False, """
'nullable=False)'
)
+ @config.requirements.sqlalchemy_09
+ def test_array_type(self):
+
+ eq_ignore_whitespace(
+ autogenerate.render._repr_type(
+ ARRAY(Integer), self.autogen_context),
+ "postgresql.ARRAY(sa.Integer())"
+ )
+
+ eq_ignore_whitespace(
+ autogenerate.render._repr_type(
+ ARRAY(DateTime(timezone=True)), self.autogen_context),
+ "postgresql.ARRAY(sa.DateTime(timezone=True))"
+ )
+
+ eq_ignore_whitespace(
+ autogenerate.render._repr_type(
+ ARRAY(BYTEA, as_tuple=True, dimensions=2),
+ self.autogen_context),
+ "postgresql.ARRAY(postgresql.BYTEA(), as_tuple=True, dimensions=2)"
+ )
+
+ assert 'from sqlalchemy.dialects import postgresql' in \
+ self.autogen_context.imports
+
+ @config.requirements.sqlalchemy_09
+ def test_array_type_user_defined_inner(self):
+ def repr_type(typestring, object_, autogen_context):
+ if typestring == 'type' and isinstance(object_, String):
+ return "foobar.MYVARCHAR"
+ else:
+ return False
+
+ self.autogen_context.opts.update(
+ render_item=repr_type
+ )
+
+ eq_ignore_whitespace(
+ autogenerate.render._repr_type(
+ ARRAY(String), self.autogen_context),
+ "postgresql.ARRAY(foobar.MYVARCHAR)"
+ )