From 36792434c74dea43a0f10f5fe1cc45c4206f01ee Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 12 Mar 2014 17:33:03 -0400 Subject: - Added a new feature :func:`.schema.conv`, the purpose of which is to mark a constraint name as already having had a naming convention applied. This token will be used by Alembic migrations as of Alembic 0.6.4 in order to render constraints in migration scripts with names marked as already having been subject to a naming convention. re: #2991 --- lib/sqlalchemy/sql/naming.py | 50 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) (limited to 'lib/sqlalchemy/sql/naming.py') diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py index 3ba7f5105..1c5fae193 100644 --- a/lib/sqlalchemy/sql/naming.py +++ b/lib/sqlalchemy/sql/naming.py @@ -16,13 +16,54 @@ from .. import exc from .elements import _truncated_label import re +class conv(_truncated_label): + """Mark a string indicating that a name has already been converted + by a naming convention. + + This is a string subclass that indicates a name that should not be + subject to any further naming conventions. + + E.g. when we create a :class:`.Constraint` using a naming convention + as follows:: + + m = MetaData(naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}) + t = Table('t', m, Column('x', Integer), + CheckConstraint('x > 5', name='x5')) + + The name of the above constraint will be rendered as ``"ck_t_x5"``. That is, + the existing name ``x5`` is used in the naming convention as the ``constraint_name`` + token. + + In some situations, such as in migration scripts, we may be rendering + the above :class:`.CheckConstraint` with a name that's already been + converted. In order to make sure the name isn't double-modified, the + new name is applied using the :func:`.schema.conv` marker. We can + use this explicitly as follows:: + + + m = MetaData(naming_convention={"ck": "ck_%(table_name)s_%(constraint_name)s"}) + t = Table('t', m, Column('x', Integer), + CheckConstraint('x > 5', name=conv('ck_t_x5'))) + + Where above, the :func:`.schema.conv` marker indicates that the constraint + name here is final, and the name will render as ``"ck_t_x5"`` and not + ``"ck_t_ck_t_x5"`` + + .. versionadded:: 0.9.4 + + .. seealso:: + + :ref:`constraint_naming_conventions` + + """ + class ConventionDict(object): def __init__(self, const, table, convention): self.const = const self._is_fk = isinstance(const, ForeignKeyConstraint) self.table = table self.convention = convention - self._const_name = const._orig_name = getattr(const, '_orig_name', const.name) + self._const_name = const.name def _key_table_name(self): return self.table.name @@ -41,9 +82,8 @@ class ConventionDict(object): "%(constraint_name)s token requires that " "constraint is explicitly named." ) - # they asked for a name that's derived from the existing - # name, so set the existing name to None - self.const.name = None + if not isinstance(self._const_name, conv): + self.const.name = None return self._const_name def _key_column_X_name(self, idx): @@ -118,7 +158,7 @@ def _constraint_name(const, table): metadata = table.metadata convention = _get_convention(metadata.naming_convention, type(const)) if convention is not None: - newname = _truncated_label( + newname = conv( convention % ConventionDict(const, table, metadata.naming_convention) ) if const.name is None: -- cgit v1.2.1