summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/base.py18
-rw-r--r--lib/sqlalchemy/sql/schema.py84
-rw-r--r--lib/sqlalchemy/sql/selectable.py2
3 files changed, 69 insertions, 35 deletions
diff --git a/lib/sqlalchemy/sql/base.py b/lib/sqlalchemy/sql/base.py
index f9b5ce7e1..f912163bc 100644
--- a/lib/sqlalchemy/sql/base.py
+++ b/lib/sqlalchemy/sql/base.py
@@ -956,12 +956,12 @@ class SchemaEventTarget(object):
"""
- def _set_parent(self, parent):
+ def _set_parent(self, parent, **kw):
"""Associate with this SchemaEvent's parent object."""
- def _set_parent_with_dispatch(self, parent):
+ def _set_parent_with_dispatch(self, parent, **kw):
self.dispatch.before_parent_attach(self, parent)
- self._set_parent(parent)
+ self._set_parent(parent, **kw)
self.dispatch.after_parent_attach(self, parent)
@@ -1185,7 +1185,16 @@ class ColumnCollection(object):
)
def contains_column(self, col):
- return col in self._colset
+ """Checks if a column object exists in this collection"""
+ if col not in self._colset:
+ if isinstance(col, util.string_types):
+ raise exc.ArgumentError(
+ "contains_column cannot be used with string arguments. "
+ "Use ``col_name in table.c`` instead."
+ )
+ return False
+ else:
+ return True
def as_immutable(self):
return ImmutableColumnCollection(self)
@@ -1302,6 +1311,7 @@ class DedupeColumnCollection(ColumnCollection):
"""
def add(self, column, key=None):
+
if key is not None and column.key != key:
raise exc.ArgumentError(
"DedupeColumnCollection requires columns be under "
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 50d7d1f5b..f1cfaaef4 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -100,9 +100,8 @@ class SchemaItem(SchemaEventTarget, visitors.Visitable):
__visit_name__ = "schema_item"
- def _init_items(self, *args):
+ def _init_items(self, *args, **kw):
"""Initialize the list of child items for this SchemaItem."""
-
for item in args:
if item is not None:
try:
@@ -116,7 +115,7 @@ class SchemaItem(SchemaEventTarget, visitors.Visitable):
replace_context=err,
)
else:
- spwd(self)
+ spwd(self, **kw)
def __repr__(self):
return util.generic_repr(self, omit_kwarg=["info"])
@@ -202,14 +201,14 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
:class:`.PrimaryKeyConstraint`, and
:class:`_schema.ForeignKeyConstraint`.
- :param autoload: Defaults to False, unless
+ :param autoload: Defaults to ``False``, unless
:paramref:`_schema.Table.autoload_with`
- is set in which case it defaults to True; :class:`_schema.Column`
- objects
+ is set in which case it defaults to ``True``;
+ :class:`_schema.Column` objects
for this table should be reflected from the database, possibly
- augmenting or replacing existing :class:`_schema.Column`
- objects that were
- explicitly specified.
+ augmenting objects that were explicitly specified.
+ :class:`_schema.Column` and other objects explicitly set on the
+ table will replace corresponding reflected objects.
.. deprecated:: 1.4
@@ -501,8 +500,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
schema = metadata.schema
elif schema is BLANK_SCHEMA:
schema = None
- keep_existing = kw.pop("keep_existing", False)
- extend_existing = kw.pop("extend_existing", False)
+ keep_existing = kw.get("keep_existing", False)
+ extend_existing = kw.get("extend_existing", False)
if keep_existing and extend_existing:
msg = "keep_existing and extend_existing are mutually exclusive."
@@ -533,7 +532,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
table._init(name, metadata, *args, **kw)
table.dispatch.after_parent_attach(table, metadata)
return table
- except:
+ except Exception:
with util.safe_reraise():
metadata._remove_table(name, schema)
@@ -565,7 +564,6 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
self.indexes = set()
self.constraints = set()
- self._columns = DedupeColumnCollection()
PrimaryKeyConstraint(
_implicit_generated=True
)._set_parent_with_dispatch(self)
@@ -580,6 +578,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
autoload = kwargs.pop("autoload", autoload_with is not None)
# this argument is only used with _init_existing()
kwargs.pop("autoload_replace", True)
+ keep_existing = kwargs.pop("keep_existing", False)
+ extend_existing = kwargs.pop("extend_existing", False)
_extend_on = kwargs.pop("_extend_on", None)
resolve_fks = kwargs.pop("resolve_fks", True)
@@ -614,7 +614,11 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
# initialize all the column, etc. objects. done after reflection to
# allow user-overrides
- self._init_items(*args)
+
+ self._init_items(
+ *args,
+ allow_replacements=extend_existing or keep_existing or autoload
+ )
def _autoload(
self,
@@ -670,6 +674,9 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
autoload_replace = kwargs.pop("autoload_replace", True)
schema = kwargs.pop("schema", None)
_extend_on = kwargs.pop("_extend_on", None)
+ # these arguments are only used with _init()
+ kwargs.pop("extend_existing", False)
+ kwargs.pop("keep_existing", False)
if schema and schema != self.schema:
raise exc.ArgumentError(
@@ -776,7 +783,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
"""
self._extra_dependencies.add(table)
- def append_column(self, column):
+ def append_column(self, column, replace_existing=False):
"""Append a :class:`_schema.Column` to this :class:`_schema.Table`.
The "key" of the newly added :class:`_schema.Column`, i.e. the
@@ -794,9 +801,17 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
emitted for an already-existing table that doesn't contain
the newly added column.
+ :param replace_existing: When ``True``, allows replacing existing
+ columns. When ``False``, the default, an warning will be raised
+ if a column with the same ``.key`` already exists. A future
+ version of sqlalchemy will instead rise a warning.
+
+ .. versionadded:: 1.4.0
"""
- column._set_parent_with_dispatch(self)
+ column._set_parent_with_dispatch(
+ self, allow_replacements=replace_existing
+ )
def append_constraint(self, constraint):
"""Append a :class:`_schema.Constraint` to this
@@ -819,7 +834,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
constraint._set_parent_with_dispatch(self)
- def _set_parent(self, metadata):
+ def _set_parent(self, metadata, **kw):
metadata._add_table(self.name, self.schema, self)
self.metadata = metadata
@@ -1495,7 +1510,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause):
+ ["%s=%s" % (k, repr(getattr(self, k))) for k in kwarg]
)
- def _set_parent(self, table):
+ def _set_parent(self, table, allow_replacements=True):
if not self.name:
raise exc.ArgumentError(
"Column must be constructed with a non-blank name or "
@@ -1517,6 +1532,15 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause):
if self.key in table._columns:
col = table._columns.get(self.key)
if col is not self:
+ if not allow_replacements:
+ util.warn_deprecated(
+ "A column with name '%s' is already present "
+ "in table '%s'. Please use method "
+ ":meth:`_schema.Table.append_column` with the "
+ "parameter ``replace_existing=True`` to replace an "
+ "existing column." % (self.key, table.name),
+ "1.4",
+ )
for fk in col.foreign_keys:
table.foreign_keys.remove(fk)
if fk.constraint in table.constraints:
@@ -2129,7 +2153,7 @@ class ForeignKey(DialectKWArgs, SchemaItem):
_column = self._colspec
return _column
- def _set_parent(self, column):
+ def _set_parent(self, column, **kw):
if self.parent is not None and self.parent is not column:
raise exc.InvalidRequestError(
"This ForeignKey already has a parent !"
@@ -2204,7 +2228,7 @@ class DefaultGenerator(SchemaItem):
def __init__(self, for_update=False):
self.for_update = for_update
- def _set_parent(self, column):
+ def _set_parent(self, column, **kw):
self.column = column
if self.for_update:
self.column.onupdate = self
@@ -2653,7 +2677,7 @@ class Sequence(IdentityOptions, roles.StatementRole, DefaultGenerator):
self, bind=self.bind
)
- def _set_parent(self, column):
+ def _set_parent(self, column, **kw):
super(Sequence, self)._set_parent(column)
column._on_table_attach(self._set_table)
@@ -2736,7 +2760,7 @@ class FetchedValue(SchemaEventTarget):
n.for_update = for_update
return n
- def _set_parent(self, column):
+ def _set_parent(self, column, **kw):
self.column = column
if self.for_update:
self.column.server_onupdate = self
@@ -2862,7 +2886,7 @@ class Constraint(DialectKWArgs, SchemaItem):
"mean to call table.append_constraint(constraint) ?"
)
- def _set_parent(self, parent):
+ def _set_parent(self, parent, **kw):
self.parent = parent
parent.constraints.add(self)
@@ -2965,7 +2989,7 @@ class ColumnCollectionMixin(object):
for col in self._pending_colargs
]
- def _set_parent(self, table):
+ def _set_parent(self, table, **kw):
for col in self._col_expressions(table):
if col is not None:
self.columns.add(col)
@@ -3007,7 +3031,7 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
"""
- def _set_parent(self, table):
+ def _set_parent(self, table, **kw):
Constraint._set_parent(self, table)
ColumnCollectionMixin._set_parent(self, table)
@@ -3394,7 +3418,7 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
def _col_description(self):
return ", ".join(self.column_keys)
- def _set_parent(self, table):
+ def _set_parent(self, table, **kw):
Constraint._set_parent(self, table)
try:
@@ -3522,7 +3546,7 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
self._implicit_generated = kw.pop("_implicit_generated", False)
super(PrimaryKeyConstraint, self).__init__(*columns, **kw)
- def _set_parent(self, table):
+ def _set_parent(self, table, **kw):
super(PrimaryKeyConstraint, self)._set_parent(table)
if table.primary_key is not self:
@@ -3809,7 +3833,7 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
if table is not None:
self._set_parent(table)
- def _set_parent(self, table):
+ def _set_parent(self, table, **kw):
ColumnCollectionMixin._set_parent(self, table)
if self.table is not None and table is not self.table:
@@ -4607,7 +4631,7 @@ class Computed(FetchedValue, SchemaItem):
self.persisted = persisted
self.column = None
- def _set_parent(self, parent):
+ def _set_parent(self, parent, **kw):
if not isinstance(
parent.server_default, (type(None), Computed)
) or not isinstance(parent.server_onupdate, (type(None), Computed)):
@@ -4734,7 +4758,7 @@ class Identity(IdentityOptions, FetchedValue, SchemaItem):
self.on_null = on_null
self.column = None
- def _set_parent(self, parent):
+ def _set_parent(self, parent, **kw):
if not isinstance(
parent.server_default, (type(None), Identity)
) or not isinstance(parent.server_onupdate, type(None)):
diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py
index 951f50ae1..eebf3b96e 100644
--- a/lib/sqlalchemy/sql/selectable.py
+++ b/lib/sqlalchemy/sql/selectable.py
@@ -2167,7 +2167,7 @@ class TableClause(roles.DMLTableRole, Immutable, FromClause):
else:
return self.name.encode("ascii", "backslashreplace")
- def append_column(self, c):
+ def append_column(self, c, **kw):
existing = c.table
if existing is not None and existing is not self:
raise exc.ArgumentError(