summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util/typing.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2023-01-16 10:31:39 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2023-01-16 14:23:49 -0500
commit046272e06aa3284a87e0dd1f90d2242fb434de10 (patch)
tree8a6ea002b34241c4b24355107361aef8590472bc /lib/sqlalchemy/util/typing.py
parent6da2f72b1144738ddae23e7fd882a8cd79ea1c60 (diff)
downloadsqlalchemy-046272e06aa3284a87e0dd1f90d2242fb434de10.tar.gz
dont assume copy_with() on builtins list, dict, etc; improve error msg.
Fixed issue where using an ``Annotated`` type in the ``type_annotation_map`` which itself contained a plain container type (e.g. ``list``, ``dict``) generic type as the target type would produce an internal error where the ORM were trying to interpret the ``Annotated`` instance. Added an error message when a :func:`_orm.relationship` is mapped against an abstract container type, such as ``Mapped[Sequence[B]]``, without providing the :paramref:`_orm.relationship.container_class` parameter which is necessary when the type is abstract. Previously the the abstract container would attempt to be instantiated and fail. Fixes: #9099 Fixes: #9100 Change-Id: I18aa6abd5451c5ac75a9caed8441ff0cd8f44589
Diffstat (limited to 'lib/sqlalchemy/util/typing.py')
-rw-r--r--lib/sqlalchemy/util/typing.py21
1 files changed, 18 insertions, 3 deletions
diff --git a/lib/sqlalchemy/util/typing.py b/lib/sqlalchemy/util/typing.py
index b1ef87db1..e1670ed21 100644
--- a/lib/sqlalchemy/util/typing.py
+++ b/lib/sqlalchemy/util/typing.py
@@ -97,8 +97,12 @@ class GenericProtocol(Protocol[_T]):
__args__: Tuple[_AnnotationScanType, ...]
__origin__: Type[_T]
- def copy_with(self, params: Tuple[_AnnotationScanType, ...]) -> Type[_T]:
- ...
+ # Python's builtin _GenericAlias has this method, however builtins like
+ # list, dict, etc. do not, even though they have ``__origin__`` and
+ # ``__args__``
+ #
+ # def copy_with(self, params: Tuple[_AnnotationScanType, ...]) -> Type[_T]:
+ # ...
class SupportsKeysAndGetItem(Protocol[_KT, _VT_co]):
@@ -158,10 +162,21 @@ def de_stringify_annotation(
for elem in annotation.__args__
)
- return annotation.copy_with(elements)
+ return _copy_generic_annotation_with(annotation, elements)
return annotation # type: ignore
+def _copy_generic_annotation_with(
+ annotation: GenericProtocol[_T], elements: Tuple[_AnnotationScanType, ...]
+) -> Type[_T]:
+ if hasattr(annotation, "copy_with"):
+ # List, Dict, etc. real generics
+ return annotation.copy_with(elements) # type: ignore
+ else:
+ # Python builtins list, dict, etc.
+ return annotation.__origin__[elements] # type: ignore
+
+
def eval_expression(expression: str, module_name: str) -> Any:
try:
base_globals: Dict[str, Any] = sys.modules[module_name].__dict__