From: Mike Bayer Date: Tue, 15 Jul 2014 02:44:33 +0000 (-0400) Subject: - wrestle with conv() and tests some more X-Git-Tag: rel_1_0_0b1~314 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f4653729a6ff952555c0192a5b0f0851c4d40ad5;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - wrestle with conv() and tests some more --- diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py index 1447787cef..4f58f6141f 100644 --- a/lib/sqlalchemy/sql/elements.py +++ b/lib/sqlalchemy/sql/elements.py @@ -3202,6 +3202,52 @@ class _truncated_label(quoted_name): return self +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 _defer_name(_truncated_label): """mark a name as 'deferred' for the purposes of automated name generation. @@ -3210,6 +3256,8 @@ class _defer_name(_truncated_label): def __new__(cls, value): if value is None: return _NONE_NAME + elif isinstance(value, conv): + return value else: return super(_defer_name, cls).__new__(cls, value) diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py index eb017eb259..053db3e340 100644 --- a/lib/sqlalchemy/sql/naming.py +++ b/lib/sqlalchemy/sql/naming.py @@ -14,49 +14,9 @@ from .schema import Constraint, ForeignKeyConstraint, PrimaryKeyConstraint, \ UniqueConstraint, CheckConstraint, Index, Table, Column from .. import event, events from .. import exc -from .elements import _truncated_label, _defer_name, _defer_none_name +from .elements import _truncated_label, _defer_name, _defer_none_name, conv 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): @@ -147,7 +107,10 @@ def _get_convention(dict_, key): def _constraint_name_for_table(const, table): metadata = table.metadata convention = _get_convention(metadata.naming_convention, type(const)) - if convention is not None and ( + + if isinstance(const.name, conv): + return const.name + elif convention is not None and ( const.name is None or not isinstance(const.name, conv) and "constraint_name" in convention ): diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index ee7d372d79..8bd4199649 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -2813,7 +2813,7 @@ class DialectKWArgTest(fixtures.TestBase): class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL): - dialect = 'default' + __dialect__ = 'default' def _fixture(self, naming_convention, table_schema=None): m1 = MetaData(naming_convention=naming_convention) @@ -2957,7 +2957,7 @@ class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL): # but is hit at compile time self.assert_compile( schema.CreateTable(u1), - "CREATE TABLE user (" + 'CREATE TABLE "user" (' "x BOOLEAN, " "CONSTRAINT ck_user_foo CHECK (x IN (0, 1))" ")" @@ -2977,12 +2977,32 @@ class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL): # but is hit at compile time self.assert_compile( schema.CreateTable(u1), - "CREATE TABLE user (" + 'CREATE TABLE "user" (' "x VARCHAR(1), " "CONSTRAINT ck_user_foo CHECK (x IN ('a', 'b'))" ")" ) + def test_schematype_ck_name_propagate_conv(self): + m1 = MetaData(naming_convention={ + "ck": "ck_%(table_name)s_%(constraint_name)s"}) + + u1 = Table('user', m1, + Column('x', Enum('a', 'b', name=naming.conv('foo'))) + ) + eq_( + [c for c in u1.constraints + if isinstance(c, CheckConstraint)][0].name, "foo" + ) + # but is hit at compile time + self.assert_compile( + schema.CreateTable(u1), + 'CREATE TABLE "user" (' + "x VARCHAR(1), " + "CONSTRAINT foo CHECK (x IN ('a', 'b'))" + ")" + ) + def test_schematype_ck_name_boolean_no_name(self): m1 = MetaData(naming_convention={ "ck": "ck_%(table_name)s_%(constraint_name)s" @@ -3028,7 +3048,7 @@ class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL): self.assert_compile( schema.CreateTable(u1), - "CREATE TABLE user (x BOOLEAN, CHECK (x IN (0, 1)))" + 'CREATE TABLE "user" (x BOOLEAN, CHECK (x IN (0, 1)))' )