summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/sqlalchemy/sql/compiler.py8
-rw-r--r--lib/sqlalchemy/sql/elements.py16
-rw-r--r--lib/sqlalchemy/sql/naming.py38
-rw-r--r--lib/sqlalchemy/sql/sqltypes.py6
4 files changed, 49 insertions, 19 deletions
diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py
index 7a8b07f8f..99b74b3c8 100644
--- a/lib/sqlalchemy/sql/compiler.py
+++ b/lib/sqlalchemy/sql/compiler.py
@@ -2902,7 +2902,13 @@ class IdentifierPreparer(object):
def format_savepoint(self, savepoint, name=None):
return self.quote(name or savepoint.ident)
- def format_constraint(self, constraint):
+ @util.dependencies("sqlalchemy.sql.naming")
+ def format_constraint(self, naming, constraint):
+ if isinstance(constraint.name, elements._defer_name):
+ name = naming._constraint_name_for_table(
+ constraint, constraint.table)
+ if name:
+ return self.quote(name)
return self.quote(constraint.name)
def format_table(self, table, use_schema=True, name=None):
diff --git a/lib/sqlalchemy/sql/elements.py b/lib/sqlalchemy/sql/elements.py
index 3882d9e5b..d273d9881 100644
--- a/lib/sqlalchemy/sql/elements.py
+++ b/lib/sqlalchemy/sql/elements.py
@@ -3201,6 +3201,22 @@ class _truncated_label(quoted_name):
def apply_map(self, map_):
return self
+
+class _defer_name(_truncated_label):
+ """mark a name as 'deferred' for the purposes of automated name
+ generation.
+
+ """
+ def __new__(cls, value):
+ if value is None:
+ return _defer_none_name('_unnamed_')
+ else:
+ return super(_defer_name, cls).__new__(cls, value)
+
+
+class _defer_none_name(_defer_name):
+ """indicate a 'deferred' name that was ultimately the value None."""
+
# for backwards compatibility in case
# someone is re-implementing the
# _truncated_identifier() sequence in a custom
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py
index d05054bc6..bb838c542 100644
--- a/lib/sqlalchemy/sql/naming.py
+++ b/lib/sqlalchemy/sql/naming.py
@@ -14,7 +14,7 @@ from .schema import Constraint, ForeignKeyConstraint, PrimaryKeyConstraint, \
UniqueConstraint, CheckConstraint, Index, Table, Column
from .. import event, events
from .. import exc
-from .elements import _truncated_label
+from .elements import _truncated_label, _defer_name, _defer_none_name
import re
class conv(_truncated_label):
@@ -77,12 +77,12 @@ class ConventionDict(object):
return list(self.const.columns)[idx]
def _key_constraint_name(self):
- if not self._const_name:
+ if isinstance(self._const_name, (type(None), _defer_none_name)):
raise exc.InvalidRequestError(
- "Naming convention including "
- "%(constraint_name)s token requires that "
- "constraint is explicitly named."
- )
+ "Naming convention including "
+ "%(constraint_name)s token requires that "
+ "constraint is explicitly named."
+ )
if not isinstance(self._const_name, conv):
self.const.name = None
return self._const_name
@@ -144,6 +144,17 @@ def _get_convention(dict_, key):
else:
return None
+def _constraint_name_for_table(const, table):
+ metadata = table.metadata
+ convention = _get_convention(metadata.naming_convention, type(const))
+ if convention is not None and (
+ const.name is None or not isinstance(const.name, conv) and
+ "constraint_name" in convention
+ ):
+ return conv(
+ convention % ConventionDict(const, table,
+ metadata.naming_convention)
+ )
@event.listens_for(Constraint, "after_parent_attach")
@event.listens_for(Index, "after_parent_attach")
@@ -156,12 +167,9 @@ def _constraint_name(const, table):
lambda col, table: _constraint_name(const, table)
)
elif isinstance(table, Table):
- metadata = table.metadata
- convention = _get_convention(metadata.naming_convention, type(const))
- if convention is not None:
- if const.name is None or "constraint_name" in convention:
- newname = conv(
- convention % ConventionDict(const, table, metadata.naming_convention)
- )
- if const.name is None:
- const.name = newname
+ if isinstance(const.name, (conv, _defer_name)):
+ return
+
+ newname = _constraint_name_for_table(const, table)
+ if newname is not None:
+ const.name = newname
diff --git a/lib/sqlalchemy/sql/sqltypes.py b/lib/sqlalchemy/sql/sqltypes.py
index b4d2d2390..52e5053ef 100644
--- a/lib/sqlalchemy/sql/sqltypes.py
+++ b/lib/sqlalchemy/sql/sqltypes.py
@@ -13,7 +13,7 @@ import datetime as dt
import codecs
from .type_api import TypeEngine, TypeDecorator, to_instance
-from .elements import quoted_name, type_coerce
+from .elements import quoted_name, type_coerce, _defer_name
from .default_comparator import _DefaultColumnComparator
from .. import exc, util, processors
from .base import _bind_or_error, SchemaEventTarget
@@ -1132,7 +1132,7 @@ class Enum(String, SchemaType):
e = schema.CheckConstraint(
type_coerce(column, self).in_(self.enums),
- name=self.name,
+ name=_defer_name(self.name),
_create_rule=util.portable_instancemethod(
self._should_create_constraint)
)
@@ -1268,7 +1268,7 @@ class Boolean(TypeEngine, SchemaType):
e = schema.CheckConstraint(
type_coerce(column, self).in_([0, 1]),
- name=self.name,
+ name=_defer_name(self.name),
_create_rule=util.portable_instancemethod(
self._should_create_constraint)
)