diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2023-01-17 01:18:47 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@ci3.zzzcomputing.com> | 2023-01-17 01:18:47 +0000 |
| commit | 030b757d1e1efdc56c42e40ce07ee34a3d00f73a (patch) | |
| tree | 97f07287ef9a21571341d2bb62c7bdf94f26bcc0 /lib/sqlalchemy | |
| parent | 3bd40c1b9a265c3bed52bfe3394f21d75bf52025 (diff) | |
| parent | 046272e06aa3284a87e0dd1f90d2242fb434de10 (diff) | |
| download | sqlalchemy-030b757d1e1efdc56c42e40ce07ee34a3d00f73a.tar.gz | |
Merge "dont assume copy_with() on builtins list, dict, etc; improve error msg." into main
Diffstat (limited to 'lib/sqlalchemy')
| -rw-r--r-- | lib/sqlalchemy/orm/relationships.py | 12 | ||||
| -rw-r--r-- | lib/sqlalchemy/util/typing.py | 21 |
2 files changed, 30 insertions, 3 deletions
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index bfd39c369..66d3a6035 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -18,6 +18,7 @@ from __future__ import annotations import collections from collections import abc import dataclasses +import inspect as _py_inspect import re import typing from typing import Any @@ -1768,7 +1769,18 @@ class RelationshipProperty( arg_origin, abc.Collection ): if self.collection_class is None: + if _py_inspect.isabstract(arg_origin): + raise sa_exc.ArgumentError( + f"Collection annotation type {arg_origin} cannot " + "be instantiated; please provide an explicit " + "'collection_class' parameter " + "(e.g. list, set, etc.) to the " + "relationship() function to accompany this " + "annotation" + ) + self.collection_class = arg_origin + elif not is_write_only and not is_dynamic: self.uselist = False 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__ |
