summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/ext
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2022-05-06 16:09:52 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2022-05-15 21:57:01 -0400
commit18a73fb1d1c267842ead5dacd05a49f4344d8b22 (patch)
treecdd1144c7661b13bc4ada83912800f91055b466d /lib/sqlalchemy/ext
parent257de6ebe15d3076e19f05f93c5b3c7fae25a4d3 (diff)
downloadsqlalchemy-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.py35
-rw-r--r--lib/sqlalchemy/ext/declarative/extensions.py36
-rw-r--r--lib/sqlalchemy/ext/hybrid.py6
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