summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/schema.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql/schema.py')
-rw-r--r--lib/sqlalchemy/sql/schema.py95
1 files changed, 62 insertions, 33 deletions
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 2118868fc..cbd0c77f4 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -37,6 +37,7 @@ import typing
from typing import Any
from typing import Callable
from typing import Dict
+from typing import Iterator
from typing import List
from typing import MutableMapping
from typing import Optional
@@ -54,7 +55,6 @@ from . import ddl
from . import roles
from . import type_api
from . import visitors
-from .base import ColumnCollection
from .base import DedupeColumnCollection
from .base import DialectKWArgs
from .base import Executable
@@ -78,6 +78,7 @@ from ..util.typing import Protocol
from ..util.typing import TypeGuard
if typing.TYPE_CHECKING:
+ from .base import ReadOnlyColumnCollection
from .type_api import TypeEngine
from ..engine import Connection
from ..engine import Engine
@@ -281,6 +282,16 @@ class Table(DialectKWArgs, HasSchemaAttr, TableClause):
__visit_name__ = "table"
+ if TYPE_CHECKING:
+
+ @util.ro_non_memoized_property
+ def primary_key(self) -> PrimaryKeyConstraint:
+ ...
+
+ @util.ro_non_memoized_property
+ def foreign_keys(self) -> Set[ForeignKey]:
+ ...
+
constraints: Set[Constraint]
"""A collection of all :class:`_schema.Constraint` objects associated with
this :class:`_schema.Table`.
@@ -324,12 +335,18 @@ class Table(DialectKWArgs, HasSchemaAttr, TableClause):
]
if TYPE_CHECKING:
-
- @util.non_memoized_property
- def columns(self) -> ColumnCollection[Column[Any]]:
+ # we are upgrading .c and .columns to return Column, not
+ # ColumnClause. mypy typically sees this as incompatible because
+ # the contract of TableClause is that we can put a ColumnClause
+ # into this collection. does not recognize its immutability
+ # for the moment.
+ @util.ro_non_memoized_property
+ def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]: # type: ignore # noqa: E501
...
- c: ColumnCollection[Column[Any]]
+ @util.ro_non_memoized_property
+ def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]: # type: ignore # noqa: E501
+ ...
def _gen_cache_key(self, anon_map, bindparams):
if self._annotations:
@@ -724,7 +741,7 @@ class Table(DialectKWArgs, HasSchemaAttr, TableClause):
PrimaryKeyConstraint(
_implicit_generated=True
)._set_parent_with_dispatch(self)
- self.foreign_keys = set()
+ self.foreign_keys = set() # type: ignore
self._extra_dependencies = set()
if self.schema is not None:
self.fullname = "%s.%s" % (self.schema, self.name)
@@ -3524,7 +3541,7 @@ class ColumnCollectionMixin:
"""
- columns: ColumnCollection[Column[Any]]
+ _columns: DedupeColumnCollection[Column[Any]]
_allow_multiple_tables = False
@@ -3538,7 +3555,7 @@ class ColumnCollectionMixin:
def __init__(self, *columns, **kw):
_autoattach = kw.pop("_autoattach", True)
self._column_flag = kw.pop("_column_flag", False)
- self.columns = DedupeColumnCollection()
+ self._columns = DedupeColumnCollection()
processed_expressions = kw.pop("_gather_expressions", None)
if processed_expressions is not None:
@@ -3611,6 +3628,14 @@ class ColumnCollectionMixin:
)
)
+ @util.ro_memoized_property
+ def columns(self) -> ReadOnlyColumnCollection[str, Column[Any]]:
+ return self._columns.as_readonly()
+
+ @util.ro_memoized_property
+ def c(self) -> ReadOnlyColumnCollection[str, Column[Any]]:
+ return self._columns.as_readonly()
+
def _col_expressions(self, table: Table) -> List[Column[Any]]:
return [
table.c[col] if isinstance(col, str) else col
@@ -3622,7 +3647,7 @@ class ColumnCollectionMixin:
assert isinstance(parent, Table)
for col in self._col_expressions(parent):
if col is not None:
- self.columns.add(col)
+ self._columns.add(col)
class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
@@ -3655,7 +3680,7 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
self, *columns, _autoattach=_autoattach, _column_flag=_column_flag
)
- columns: DedupeColumnCollection[Column[Any]]
+ columns: ReadOnlyColumnCollection[str, Column[Any]]
"""A :class:`_expression.ColumnCollection` representing the set of columns
for this constraint.
@@ -3666,7 +3691,7 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
ColumnCollectionMixin._set_parent(self, table)
def __contains__(self, x):
- return x in self.columns
+ return x in self._columns
@util.deprecated(
"1.4",
@@ -3695,7 +3720,7 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
initially=self.initially,
*[
_copy_expression(expr, self.parent, target_table)
- for expr in self.columns
+ for expr in self._columns
],
**constraint_kwargs,
)
@@ -3710,13 +3735,13 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
"""
- return self.columns.contains_column(col)
+ return self._columns.contains_column(col)
- def __iter__(self):
- return iter(self.columns)
+ def __iter__(self) -> Iterator[Column[Any]]:
+ return iter(self._columns)
- def __len__(self):
- return len(self.columns)
+ def __len__(self) -> int:
+ return len(self._columns)
class CheckConstraint(ColumnCollectionConstraint):
@@ -3989,10 +4014,10 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
self._set_parent_with_dispatch(table)
def _append_element(self, column: Column[Any], fk: ForeignKey) -> None:
- self.columns.add(column)
+ self._columns.add(column)
self.elements.append(fk)
- columns: DedupeColumnCollection[Column[Any]]
+ columns: ReadOnlyColumnCollection[str, Column[Any]]
"""A :class:`_expression.ColumnCollection` representing the set of columns
for this constraint.
@@ -4059,7 +4084,7 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
"""
if hasattr(self, "parent"):
- return self.columns.keys()
+ return self._columns.keys()
else:
return [
col.key if isinstance(col, ColumnElement) else str(col)
@@ -4082,7 +4107,7 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
"named '%s' is present." % (table.description, ke.args[0])
) from ke
- for col, fk in zip(self.columns, self.elements):
+ for col, fk in zip(self._columns, self.elements):
if not hasattr(fk, "parent") or fk.parent is not col:
fk._set_parent_with_dispatch(col)
@@ -4213,7 +4238,11 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
table.constraints.add(self)
table_pks = [c for c in table.c if c.primary_key]
- if self.columns and table_pks and set(table_pks) != set(self.columns):
+ if (
+ self._columns
+ and table_pks
+ and set(table_pks) != set(self._columns)
+ ):
util.warn(
"Table '%s' specifies columns %s as primary_key=True, "
"not matching locally specified columns %s; setting the "
@@ -4222,18 +4251,18 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
% (
table.name,
", ".join("'%s'" % c.name for c in table_pks),
- ", ".join("'%s'" % c.name for c in self.columns),
- ", ".join("'%s'" % c.name for c in self.columns),
+ ", ".join("'%s'" % c.name for c in self._columns),
+ ", ".join("'%s'" % c.name for c in self._columns),
)
)
table_pks[:] = []
- for c in self.columns:
+ for c in self._columns:
c.primary_key = True
if c._user_defined_nullable is NULL_UNSPECIFIED:
c.nullable = False
if table_pks:
- self.columns.extend(table_pks)
+ self._columns.extend(table_pks)
def _reload(self, columns):
"""repopulate this :class:`.PrimaryKeyConstraint` given
@@ -4259,14 +4288,14 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
for col in columns:
col.primary_key = True
- self.columns.extend(columns)
+ self._columns.extend(columns)
PrimaryKeyConstraint._autoincrement_column._reset(self)
self._set_parent_with_dispatch(self.table)
def _replace(self, col):
PrimaryKeyConstraint._autoincrement_column._reset(self)
- self.columns.replace(col)
+ self._columns.replace(col)
self.dispatch._sa_event_column_added_to_pk_constraint(self, col)
@@ -4275,9 +4304,9 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
autoinc = self._autoincrement_column
if autoinc is not None:
- return [autoinc] + [c for c in self.columns if c is not autoinc]
+ return [autoinc] + [c for c in self._columns if c is not autoinc]
else:
- return list(self.columns)
+ return list(self._columns)
@util.memoized_property
def _autoincrement_column(self):
@@ -4310,8 +4339,8 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
return False
return True
- if len(self.columns) == 1:
- col = list(self.columns)[0]
+ if len(self._columns) == 1:
+ col = list(self._columns)[0]
if col.autoincrement is True:
_validate_autoinc(col, True)
@@ -4324,7 +4353,7 @@ class PrimaryKeyConstraint(ColumnCollectionConstraint):
else:
autoinc = None
- for col in self.columns:
+ for col in self._columns:
if col.autoincrement is True:
_validate_autoinc(col, True)
if autoinc is not None: