diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-01-09 08:53:57 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2023-01-09 09:29:31 -0500 |
| commit | eb9d00c4b4f4f15e871aa9ea88d41023054c6e97 (patch) | |
| tree | 04935d2a29ade93983d09b7da06f9131e3c41779 /lib/sqlalchemy | |
| parent | a76f4cbb7d3066f71b035b29e511eb811b810c9c (diff) | |
| download | sqlalchemy-eb9d00c4b4f4f15e871aa9ea88d41023054c6e97.tar.gz | |
accept TableClause through mapped selectable chain
type annotation somehow decided that TableClause doesn't have
primary key fields which is not the case at all. In particular
the "views" recipe relies on TableClause so adding a restriction
like this does not make any sense.
It seems the issue was to open this up for typing, by allowing
TableClause out as far as ddl.sort_tables() typing is passing
for now. Support it out in get_bind() etc.
Fixes: #9071
Change-Id: If0e22e0e7df7bee0ff4b295b0ffacfbc6b7a0142
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/mapper.py | 26 | ||||
| -rw-r--r-- | lib/sqlalchemy/orm/session.py | 7 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/ddl.py | 7 |
3 files changed, 19 insertions, 21 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 522028274..20ad635b0 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -78,6 +78,7 @@ from ..sql import coercions from ..sql import expression from ..sql import operators from ..sql import roles +from ..sql import TableClause from ..sql import util as sql_util from ..sql import visitors from ..sql.cache_key import MemoizedHasCacheKey @@ -892,7 +893,7 @@ class Mapper( _dependency_processors: List[DependencyProcessor] _memoized_values: Dict[Any, Callable[[], Any]] _inheriting_mappers: util.WeakSequence[Mapper[Any]] - _all_tables: Set[Table] + _all_tables: Set[TableClause] _polymorphic_attr_key: Optional[str] _pks_by_table: Dict[FromClause, OrderedSet[ColumnClause[Any]]] @@ -908,9 +909,10 @@ class Mapper( Callable[[Mapper[_O], InstanceState[_O], _InstanceDict], None] ] - tables: Sequence[Table] - """A sequence containing the collection of :class:`_schema.Table` objects - which this :class:`_orm.Mapper` is aware of. + tables: Sequence[TableClause] + """A sequence containing the collection of :class:`_schema.Table` + or :class:`_schema.TableClause` objects which this :class:`_orm.Mapper` + is aware of. If the mapper is mapped to a :class:`_expression.Join`, or an :class:`_expression.Alias` @@ -1534,17 +1536,9 @@ class Mapper( self.__dict__.pop("_configure_failed", None) def _configure_pks(self) -> None: - self.tables = cast( - "List[Table]", sql_util.find_tables(self.persist_selectable) - ) - for t in self.tables: - if not isinstance(t, Table): - raise sa_exc.ArgumentError( - f"ORM mappings can only be made against schema-level " - f"Table objects, not TableClause; got " - f"tableclause {t.name !r}" - ) - self._all_tables.update(t for t in self.tables if isinstance(t, Table)) + self.tables = sql_util.find_tables(self.persist_selectable) + + self._all_tables.update(t for t in self.tables) self._pks_by_table = {} self._cols_by_table = {} @@ -3802,7 +3796,7 @@ class Mapper( @HasMemoized.memoized_attribute def _sorted_tables(self): - table_to_mapper: Dict[Table, Mapper[Any]] = {} + table_to_mapper: Dict[TableClause, Mapper[Any]] = {} for mapper in self.base_mapper.self_and_descendants: for t in mapper.tables: diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 0298b17a7..5bcb22a08 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -80,6 +80,7 @@ from ..sql import coercions from ..sql import dml from ..sql import roles from ..sql import Select +from ..sql import TableClause from ..sql import visitors from ..sql.base import CompileState from ..sql.schema import Table @@ -152,7 +153,7 @@ _PKIdentityArgument = Union[Any, Tuple[Any, ...]] _BindArguments = Dict[str, Any] _EntityBindKey = Union[Type[_O], "Mapper[_O]"] -_SessionBindKey = Union[Type[Any], "Mapper[Any]", "Table", str] +_SessionBindKey = Union[Type[Any], "Mapper[Any]", "TableClause", str] _SessionBind = Union["Engine", "Connection"] JoinTransactionMode = Literal[ @@ -2439,7 +2440,7 @@ class Session(_SessionClassMethods, EventTarget): if TYPE_CHECKING: assert isinstance(insp, Inspectable) - if isinstance(insp, Table): + if isinstance(insp, TableClause): self.__binds[insp] = bind elif insp_is_mapper(insp): self.__binds[insp.class_] = bind @@ -2480,7 +2481,7 @@ class Session(_SessionClassMethods, EventTarget): """ self._add_bind(mapper, bind) - def bind_table(self, table: Table, bind: _SessionBind) -> None: + def bind_table(self, table: TableClause, bind: _SessionBind) -> None: """Associate a :class:`_schema.Table` with a "bind", e.g. an :class:`_engine.Engine` or :class:`_engine.Connection`. diff --git a/lib/sqlalchemy/sql/ddl.py b/lib/sqlalchemy/sql/ddl.py index 9a5b00244..5ea500a32 100644 --- a/lib/sqlalchemy/sql/ddl.py +++ b/lib/sqlalchemy/sql/ddl.py @@ -42,6 +42,7 @@ if typing.TYPE_CHECKING: from .schema import SchemaItem from .schema import Sequence from .schema import Table + from .selectable import TableClause from ..engine.base import Connection from ..engine.interfaces import CacheStats from ..engine.interfaces import CompiledCacheType @@ -1179,9 +1180,11 @@ class SchemaDropper(InvokeDropDDLBase): def sort_tables( - tables: Iterable[Table], + tables: Iterable[TableClause], skip_fn: Optional[Callable[[ForeignKeyConstraint], bool]] = None, - extra_dependencies: Optional[typing_Sequence[Tuple[Table, Table]]] = None, + extra_dependencies: Optional[ + typing_Sequence[Tuple[TableClause, TableClause]] + ] = None, ) -> List[Table]: """Sort a collection of :class:`_schema.Table` objects based on dependency. |
