diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-05-06 16:09:52 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2022-05-15 21:57:01 -0400 |
commit | 18a73fb1d1c267842ead5dacd05a49f4344d8b22 (patch) | |
tree | cdd1144c7661b13bc4ada83912800f91055b466d /lib/sqlalchemy/ext | |
parent | 257de6ebe15d3076e19f05f93c5b3c7fae25a4d3 (diff) | |
download | sqlalchemy-18a73fb1d1c267842ead5dacd05a49f4344d8b22.tar.gz |
revenge of pep 484
trying to get remaining must-haves for ORM
Change-Id: I66a3ecbbb8e5ba37c818c8a92737b576ecf012f7
Diffstat (limited to 'lib/sqlalchemy/ext')
-rw-r--r-- | lib/sqlalchemy/ext/associationproxy.py | 35 | ||||
-rw-r--r-- | lib/sqlalchemy/ext/declarative/extensions.py | 36 | ||||
-rw-r--r-- | lib/sqlalchemy/ext/hybrid.py | 6 |
3 files changed, 51 insertions, 26 deletions
diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 420ba5c8c..7db95eac9 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -53,7 +53,6 @@ from ..orm import ORMDescriptor from ..orm.base import SQLORMOperations from ..sql import operators from ..sql import or_ -from ..sql.elements import SQLCoreOperations from ..util.typing import Literal from ..util.typing import Protocol from ..util.typing import Self @@ -64,8 +63,10 @@ if typing.TYPE_CHECKING: from ..orm.interfaces import MapperProperty from ..orm.interfaces import PropComparator from ..orm.mapper import Mapper + from ..sql._typing import _ColumnExpressionArgument from ..sql._typing import _InfoType + _T = TypeVar("_T", bound=Any) _T_co = TypeVar("_T_co", bound=Any, covariant=True) _T_con = TypeVar("_T_con", bound=Any, contravariant=True) @@ -631,7 +632,9 @@ class AssociationProxyInstance(SQLORMOperations[_T]): @property def _comparator(self) -> PropComparator[Any]: - return self._get_property().comparator + return getattr( # type: ignore + self.owning_class, self.target_collection + ).comparator def __clause_element__(self) -> NoReturn: raise NotImplementedError( @@ -957,7 +960,9 @@ class AssociationProxyInstance(SQLORMOperations[_T]): proxy.setter = setter def _criterion_exists( - self, criterion: Optional[SQLCoreOperations[Any]] = None, **kwargs: Any + self, + criterion: Optional[_ColumnExpressionArgument[bool]] = None, + **kwargs: Any, ) -> ColumnElement[bool]: is_has = kwargs.pop("is_has", None) @@ -969,8 +974,8 @@ class AssociationProxyInstance(SQLORMOperations[_T]): return self._comparator._criterion_exists(inner) if self._target_is_object: - prop = getattr(self.target_class, self.value_attr) - value_expr = prop._criterion_exists(criterion, **kwargs) + attr = getattr(self.target_class, self.value_attr) + value_expr = attr.comparator._criterion_exists(criterion, **kwargs) else: if kwargs: raise exc.ArgumentError( @@ -988,8 +993,10 @@ class AssociationProxyInstance(SQLORMOperations[_T]): return self._comparator._criterion_exists(value_expr) def any( - self, criterion: Optional[SQLCoreOperations[Any]] = None, **kwargs: Any - ) -> SQLCoreOperations[Any]: + self, + criterion: Optional[_ColumnExpressionArgument[bool]] = None, + **kwargs: Any, + ) -> ColumnElement[bool]: """Produce a proxied 'any' expression using EXISTS. This expression will be a composed product @@ -1010,8 +1017,10 @@ class AssociationProxyInstance(SQLORMOperations[_T]): ) def has( - self, criterion: Optional[SQLCoreOperations[Any]] = None, **kwargs: Any - ) -> SQLCoreOperations[Any]: + self, + criterion: Optional[_ColumnExpressionArgument[bool]] = None, + **kwargs: Any, + ) -> ColumnElement[bool]: """Produce a proxied 'has' expression using EXISTS. This expression will be a composed product @@ -1069,12 +1078,16 @@ class AmbiguousAssociationProxyInstance(AssociationProxyInstance[_T]): self._ambiguous() def any( - self, criterion: Optional[SQLCoreOperations[Any]] = None, **kwargs: Any + self, + criterion: Optional[_ColumnExpressionArgument[bool]] = None, + **kwargs: Any, ) -> NoReturn: self._ambiguous() def has( - self, criterion: Optional[SQLCoreOperations[Any]] = None, **kwargs: Any + self, + criterion: Optional[_ColumnExpressionArgument[bool]] = None, + **kwargs: Any, ) -> NoReturn: self._ambiguous() diff --git a/lib/sqlalchemy/ext/declarative/extensions.py b/lib/sqlalchemy/ext/declarative/extensions.py index 9faf2ed51..22fa83c58 100644 --- a/lib/sqlalchemy/ext/declarative/extensions.py +++ b/lib/sqlalchemy/ext/declarative/extensions.py @@ -8,7 +8,10 @@ """Public API functions and helpers for declarative.""" +from __future__ import annotations +from typing import Callable +from typing import TYPE_CHECKING from ... import inspection from ...orm import exc as orm_exc @@ -20,6 +23,10 @@ from ...orm.util import polymorphic_union from ...schema import Table from ...util import OrderedDict +if TYPE_CHECKING: + from ...engine.reflection import Inspector + from ...sql.schema import MetaData + class ConcreteBase: """A helper class for 'concrete' declarative mappings. @@ -380,31 +387,36 @@ class DeferredReflection: mapper = thingy.cls.__mapper__ metadata = mapper.class_.metadata for rel in mapper._props.values(): + if ( isinstance(rel, relationships.Relationship) - and rel.secondary is not None + and rel._init_args.secondary._is_populated() ): - if isinstance(rel.secondary, Table): - cls._reflect_table(rel.secondary, insp) - elif isinstance(rel.secondary, str): + + secondary_arg = rel._init_args.secondary + + if isinstance(secondary_arg.argument, Table): + cls._reflect_table(secondary_arg.argument, insp) + elif isinstance(secondary_arg.argument, str): _, resolve_arg = _resolver(rel.parent.class_, rel) - rel.secondary = resolve_arg(rel.secondary) - rel.secondary._resolvers += ( + resolver = resolve_arg( + secondary_arg.argument, True + ) + resolver._resolvers += ( cls._sa_deferred_table_resolver( insp, metadata ), ) - # controversy! do we resolve it here? or leave - # it deferred? I think doing it here is necessary - # so the connection does not leak. - rel.secondary = rel.secondary() + secondary_arg.argument = resolver() @classmethod - def _sa_deferred_table_resolver(cls, inspector, metadata): - def _resolve(key): + def _sa_deferred_table_resolver( + cls, inspector: Inspector, metadata: MetaData + ) -> Callable[[str], Table]: + def _resolve(key: str) -> Table: t1 = Table(key, metadata) cls._reflect_table(t1, inspector) return t1 diff --git a/lib/sqlalchemy/ext/hybrid.py b/lib/sqlalchemy/ext/hybrid.py index ea558495b..accfa8949 100644 --- a/lib/sqlalchemy/ext/hybrid.py +++ b/lib/sqlalchemy/ext/hybrid.py @@ -1305,8 +1305,8 @@ class Comparator(interfaces.PropComparator[_T]): return ret_expr @util.non_memoized_property - def property(self) -> Optional[interfaces.MapperProperty[_T]]: - return None + def property(self) -> interfaces.MapperProperty[_T]: + raise NotImplementedError() def adapt_to_entity( self, adapt_to_entity: AliasedInsp[Any] @@ -1344,7 +1344,7 @@ class ExprComparator(Comparator[_T]): return [(self.expression, value)] @util.non_memoized_property - def property(self) -> Optional[MapperProperty[_T]]: + def property(self) -> MapperProperty[_T]: # this accessor is not normally used, however is accessed by things # like ORM synonyms if the hybrid is used in this context; the # .property attribute is not necessarily accessible |