openmedialibrary_platform/Darwin/lib/python2.7/site-packages/alembic/autogenerate/render.py
2014-05-16 01:20:41 +02:00

457 lines
16 KiB
Python

from sqlalchemy import schema as sa_schema, types as sqltypes, sql
import logging
from .. import compat
import re
from ..compat import string_types
log = logging.getLogger(__name__)
try:
from sqlalchemy.sql.naming import conv
def _render_gen_name(autogen_context, name):
if isinstance(name, conv):
return _f_name(_alembic_autogenerate_prefix(autogen_context), name)
else:
return name
except ImportError:
def _render_gen_name(autogen_context, name):
return name
class _f_name(object):
def __init__(self, prefix, name):
self.prefix = prefix
self.name = name
def __repr__(self):
return "%sf(%r)" % (self.prefix, self.name)
def _render_potential_expr(value, autogen_context):
if isinstance(value, sql.ClauseElement):
if compat.sqla_08:
compile_kw = dict(compile_kwargs={'literal_binds': True})
else:
compile_kw = {}
return "%(prefix)stext(%(sql)r)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"sql": str(
value.compile(dialect=autogen_context['dialect'],
**compile_kw)
)
}
else:
return repr(value)
def _add_table(table, autogen_context):
text = "%(prefix)screate_table(%(tablename)r,\n%(args)s" % {
'tablename': table.name,
'prefix': _alembic_autogenerate_prefix(autogen_context),
'args': ',\n'.join(
[col for col in
[_render_column(col, autogen_context) for col in table.c]
if col] +
sorted([rcons for rcons in
[_render_constraint(cons, autogen_context) for cons in
table.constraints]
if rcons is not None
])
)
}
if table.schema:
text += ",\nschema=%r" % table.schema
for k in sorted(table.kwargs):
text += ",\n%s=%r" % (k.replace(" ", "_"), table.kwargs[k])
text += "\n)"
return text
def _drop_table(table, autogen_context):
text = "%(prefix)sdrop_table(%(tname)r" % {
"prefix": _alembic_autogenerate_prefix(autogen_context),
"tname": table.name
}
if table.schema:
text += ", schema=%r" % table.schema
text += ")"
return text
def _add_index(index, autogen_context):
"""
Generate Alembic operations for the CREATE INDEX of an
:class:`~sqlalchemy.schema.Index` instance.
"""
from .compare import _get_index_column_names
text = "%(prefix)screate_index(%(name)r, '%(table)s', %(columns)s, "\
"unique=%(unique)r%(schema)s%(kwargs)s)" % {
'prefix': _alembic_autogenerate_prefix(autogen_context),
'name': _render_gen_name(autogen_context, index.name),
'table': index.table.name,
'columns': _get_index_column_names(index),
'unique': index.unique or False,
'schema': (", schema='%s'" % index.table.schema) if index.table.schema else '',
'kwargs': (', '+', '.join(
["%s=%s" % (key, _render_potential_expr(val, autogen_context))
for key, val in index.kwargs.items()]))\
if len(index.kwargs) else ''
}
return text
def _drop_index(index, autogen_context):
"""
Generate Alembic operations for the DROP INDEX of an
:class:`~sqlalchemy.schema.Index` instance.
"""
text = "%(prefix)sdrop_index(%(name)r, "\
"table_name='%(table_name)s'%(schema)s)" % {
'prefix': _alembic_autogenerate_prefix(autogen_context),
'name': _render_gen_name(autogen_context, index.name),
'table_name': index.table.name,
'schema': ((", schema='%s'" % index.table.schema)
if index.table.schema else '')
}
return text
def _render_unique_constraint(constraint, autogen_context):
rendered = _user_defined_render("unique", constraint, autogen_context)
if rendered is not False:
return rendered
return _uq_constraint(constraint, autogen_context, False)
def _add_unique_constraint(constraint, autogen_context):
"""
Generate Alembic operations for the ALTER TABLE .. ADD CONSTRAINT ...
UNIQUE of a :class:`~sqlalchemy.schema.UniqueConstraint` instance.
"""
return _uq_constraint(constraint, autogen_context, True)
def _uq_constraint(constraint, autogen_context, alter):
opts = []
if constraint.deferrable:
opts.append(("deferrable", str(constraint.deferrable)))
if constraint.initially:
opts.append(("initially", str(constraint.initially)))
if alter and constraint.table.schema:
opts.append(("schema", str(constraint.table.schema)))
if not alter and constraint.name:
opts.append(("name", _render_gen_name(autogen_context, constraint.name)))
if alter:
args = [repr(_render_gen_name(autogen_context, constraint.name)),
repr(constraint.table.name)]
args.append(repr([col.name for col in constraint.columns]))
args.extend(["%s=%r" % (k, v) for k, v in opts])
return "%(prefix)screate_unique_constraint(%(args)s)" % {
'prefix': _alembic_autogenerate_prefix(autogen_context),
'args': ", ".join(args)
}
else:
args = [repr(col.name) for col in constraint.columns]
args.extend(["%s=%r" % (k, v) for k, v in opts])
return "%(prefix)sUniqueConstraint(%(args)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"args": ", ".join(args)
}
def _add_fk_constraint(constraint, autogen_context):
raise NotImplementedError()
def _add_pk_constraint(constraint, autogen_context):
raise NotImplementedError()
def _add_check_constraint(constraint, autogen_context):
raise NotImplementedError()
def _add_constraint(constraint, autogen_context):
"""
Dispatcher for the different types of constraints.
"""
funcs = {
"unique_constraint": _add_unique_constraint,
"foreign_key_constraint": _add_fk_constraint,
"primary_key_constraint": _add_pk_constraint,
"check_constraint": _add_check_constraint,
"column_check_constraint": _add_check_constraint,
}
return funcs[constraint.__visit_name__](constraint, autogen_context)
def _drop_constraint(constraint, autogen_context):
"""
Generate Alembic operations for the ALTER TABLE ... DROP CONSTRAINT
of a :class:`~sqlalchemy.schema.UniqueConstraint` instance.
"""
text = "%(prefix)sdrop_constraint(%(name)r, '%(table_name)s'%(schema)s)" % {
'prefix': _alembic_autogenerate_prefix(autogen_context),
'name': _render_gen_name(autogen_context, constraint.name),
'table_name': constraint.table.name,
'schema': (", schema='%s'" % constraint.table.schema)
if constraint.table.schema else '',
}
return text
def _add_column(schema, tname, column, autogen_context):
text = "%(prefix)sadd_column(%(tname)r, %(column)s" % {
"prefix": _alembic_autogenerate_prefix(autogen_context),
"tname": tname,
"column": _render_column(column, autogen_context)
}
if schema:
text += ", schema=%r" % schema
text += ")"
return text
def _drop_column(schema, tname, column, autogen_context):
text = "%(prefix)sdrop_column(%(tname)r, %(cname)r" % {
"prefix": _alembic_autogenerate_prefix(autogen_context),
"tname": tname,
"cname": column.name
}
if schema:
text += ", schema=%r" % schema
text += ")"
return text
def _modify_col(tname, cname,
autogen_context,
server_default=False,
type_=None,
nullable=None,
existing_type=None,
existing_nullable=None,
existing_server_default=False,
schema=None):
indent = " " * 11
text = "%(prefix)salter_column(%(tname)r, %(cname)r" % {
'prefix': _alembic_autogenerate_prefix(
autogen_context),
'tname': tname,
'cname': cname}
text += ",\n%sexisting_type=%s" % (indent,
_repr_type(existing_type, autogen_context))
if server_default is not False:
rendered = _render_server_default(
server_default, autogen_context)
text += ",\n%sserver_default=%s" % (indent, rendered)
if type_ is not None:
text += ",\n%stype_=%s" % (indent,
_repr_type(type_, autogen_context))
if nullable is not None:
text += ",\n%snullable=%r" % (
indent, nullable,)
if existing_nullable is not None:
text += ",\n%sexisting_nullable=%r" % (
indent, existing_nullable)
if existing_server_default:
rendered = _render_server_default(
existing_server_default,
autogen_context)
text += ",\n%sexisting_server_default=%s" % (
indent, rendered)
if schema:
text += ",\n%sschema=%r" % (indent, schema)
text += ")"
return text
def _user_autogenerate_prefix(autogen_context):
prefix = autogen_context['opts']['user_module_prefix']
if prefix is None:
return _sqlalchemy_autogenerate_prefix(autogen_context)
else:
return prefix
def _sqlalchemy_autogenerate_prefix(autogen_context):
return autogen_context['opts']['sqlalchemy_module_prefix'] or ''
def _alembic_autogenerate_prefix(autogen_context):
return autogen_context['opts']['alembic_module_prefix'] or ''
def _user_defined_render(type_, object_, autogen_context):
if 'opts' in autogen_context and \
'render_item' in autogen_context['opts']:
render = autogen_context['opts']['render_item']
if render:
rendered = render(type_, object_, autogen_context)
if rendered is not False:
return rendered
return False
def _render_column(column, autogen_context):
rendered = _user_defined_render("column", column, autogen_context)
if rendered is not False:
return rendered
opts = []
if column.server_default:
rendered = _render_server_default(
column.server_default, autogen_context
)
if rendered:
opts.append(("server_default", rendered))
if not column.autoincrement:
opts.append(("autoincrement", column.autoincrement))
if column.nullable is not None:
opts.append(("nullable", column.nullable))
# TODO: for non-ascii colname, assign a "key"
return "%(prefix)sColumn(%(name)r, %(type)s, %(kw)s)" % {
'prefix': _sqlalchemy_autogenerate_prefix(autogen_context),
'name': column.name,
'type': _repr_type(column.type, autogen_context),
'kw': ", ".join(["%s=%s" % (kwname, val) for kwname, val in opts])
}
def _render_server_default(default, autogen_context):
rendered = _user_defined_render("server_default", default, autogen_context)
if rendered is not False:
return rendered
if isinstance(default, sa_schema.DefaultClause):
if isinstance(default.arg, string_types):
default = default.arg
else:
default = str(default.arg.compile(
dialect=autogen_context['dialect']))
if isinstance(default, string_types):
# TODO: this is just a hack to get
# tests to pass until we figure out
# WTF sqlite is doing
default = re.sub(r"^'|'$", "", default)
return repr(default)
else:
return None
def _repr_type(type_, autogen_context):
rendered = _user_defined_render("type", type_, autogen_context)
if rendered is not False:
return rendered
mod = type(type_).__module__
imports = autogen_context.get('imports', None)
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_)
elif mod.startswith("sqlalchemy"):
prefix = _sqlalchemy_autogenerate_prefix(autogen_context)
return "%s%r" % (prefix, type_)
else:
prefix = _user_autogenerate_prefix(autogen_context)
return "%s%r" % (prefix, type_)
def _render_constraint(constraint, autogen_context):
renderer = _constraint_renderers.get(type(constraint), None)
if renderer:
return renderer(constraint, autogen_context)
else:
return None
def _render_primary_key(constraint, autogen_context):
rendered = _user_defined_render("primary_key", constraint, autogen_context)
if rendered is not False:
return rendered
if not constraint.columns:
return None
opts = []
if constraint.name:
opts.append(("name", repr(_render_gen_name(autogen_context, constraint.name))))
return "%(prefix)sPrimaryKeyConstraint(%(args)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"args": ", ".join(
[repr(c.key) for c in constraint.columns] +
["%s=%s" % (kwname, val) for kwname, val in opts]
),
}
def _fk_colspec(fk, metadata_schema):
"""Implement a 'safe' version of ForeignKey._get_colspec() that
never tries to resolve the remote table.
"""
if metadata_schema is None:
return fk._get_colspec()
else:
# need to render schema breaking up tokens by hand, since the
# ForeignKeyConstraint here may not actually have a remote
# Table present
tokens = fk._colspec.split(".")
# no schema in the colspec, render it
if len(tokens) == 2:
return "%s.%s" % (metadata_schema, fk._colspec)
else:
return fk._colspec
def _render_foreign_key(constraint, autogen_context):
rendered = _user_defined_render("foreign_key", constraint, autogen_context)
if rendered is not False:
return rendered
opts = []
if constraint.name:
opts.append(("name", repr(_render_gen_name(autogen_context, constraint.name))))
if constraint.onupdate:
opts.append(("onupdate", repr(constraint.onupdate)))
if constraint.ondelete:
opts.append(("ondelete", repr(constraint.ondelete)))
if constraint.initially:
opts.append(("initially", repr(constraint.initially)))
if constraint.deferrable:
opts.append(("deferrable", repr(constraint.deferrable)))
if constraint.use_alter:
opts.append(("use_alter", repr(constraint.use_alter)))
apply_metadata_schema = constraint.parent.metadata.schema
return "%(prefix)sForeignKeyConstraint([%(cols)s], "\
"[%(refcols)s], %(args)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"cols": ", ".join("'%s'" % f.parent.key for f in constraint.elements),
"refcols": ", ".join(repr(_fk_colspec(f, apply_metadata_schema))
for f in constraint.elements),
"args": ", ".join(
["%s=%s" % (kwname, val) for kwname, val in opts]
),
}
def _render_check_constraint(constraint, autogen_context):
rendered = _user_defined_render("check", constraint, autogen_context)
if rendered is not False:
return rendered
# detect the constraint being part of
# a parent type which is probably in the Table already.
# ideally SQLAlchemy would give us more of a first class
# way to detect this.
if constraint._create_rule and \
hasattr(constraint._create_rule, 'target') and \
isinstance(constraint._create_rule.target,
sqltypes.TypeEngine):
return None
opts = []
if constraint.name:
opts.append(("name", repr(_render_gen_name(autogen_context, constraint.name))))
return "%(prefix)sCheckConstraint(%(sqltext)r%(opts)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"opts": ", " + (", ".join("%s=%s" % (k, v)
for k, v in opts)) if opts else "",
"sqltext": str(
constraint.sqltext.compile(
dialect=autogen_context['dialect']
)
)
}
_constraint_renderers = {
sa_schema.PrimaryKeyConstraint: _render_primary_key,
sa_schema.ForeignKeyConstraint: _render_foreign_key,
sa_schema.UniqueConstraint: _render_unique_constraint,
sa_schema.CheckConstraint: _render_check_constraint
}