summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/util/typing.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/util/typing.py')
-rw-r--r--lib/sqlalchemy/util/typing.py77
1 files changed, 68 insertions, 9 deletions
diff --git a/lib/sqlalchemy/util/typing.py b/lib/sqlalchemy/util/typing.py
index ebcae28a7..44e26f609 100644
--- a/lib/sqlalchemy/util/typing.py
+++ b/lib/sqlalchemy/util/typing.py
@@ -11,7 +11,9 @@ from typing import Dict
from typing import ForwardRef
from typing import Generic
from typing import Iterable
+from typing import NoReturn
from typing import Optional
+from typing import overload
from typing import Tuple
from typing import Type
from typing import TypeVar
@@ -33,7 +35,7 @@ Self = TypeVar("Self", bound=Any)
if compat.py310:
# why they took until py310 to put this in stdlib is beyond me,
# I've been wanting it since py27
- from types import NoneType
+ from types import NoneType as NoneType
else:
NoneType = type(None) # type: ignore
@@ -68,6 +70,8 @@ else:
# copied from TypeShed, required in order to implement
# MutableMapping.update()
+_AnnotationScanType = Union[Type[Any], str]
+
class SupportsKeysAndGetItem(Protocol[_KT, _VT_co]):
def keys(self) -> Iterable[_KT]:
@@ -90,9 +94,9 @@ else:
def de_stringify_annotation(
cls: Type[Any],
- annotation: Union[str, Type[Any]],
+ annotation: _AnnotationScanType,
str_cleanup_fn: Optional[Callable[[str], str]] = None,
-) -> Union[str, Type[Any]]:
+) -> Type[Any]:
"""Resolve annotations that may be string based into real objects.
This is particularly important if a module defines "from __future__ import
@@ -125,20 +129,32 @@ def de_stringify_annotation(
annotation = eval(annotation, base_globals, None)
except NameError:
pass
- return annotation
+ return annotation # type: ignore
-def is_fwd_ref(type_):
+def is_fwd_ref(type_: _AnnotationScanType) -> bool:
return isinstance(type_, ForwardRef)
-def de_optionalize_union_types(type_):
+@overload
+def de_optionalize_union_types(type_: str) -> str:
+ ...
+
+
+@overload
+def de_optionalize_union_types(type_: Type[Any]) -> Type[Any]:
+ ...
+
+
+def de_optionalize_union_types(
+ type_: _AnnotationScanType,
+) -> _AnnotationScanType:
"""Given a type, filter out ``Union`` types that include ``NoneType``
to not include the ``NoneType``.
"""
if is_optional(type_):
- typ = set(type_.__args__)
+ typ = set(type_.__args__) # type: ignore
typ.discard(NoneType)
@@ -148,14 +164,14 @@ def de_optionalize_union_types(type_):
return type_
-def make_union_type(*types):
+def make_union_type(*types: _AnnotationScanType) -> Type[Any]:
"""Make a Union type.
This is needed by :func:`.de_optionalize_union_types` which removes
``NoneType`` from a ``Union``.
"""
- return cast(Any, Union).__getitem__(types)
+ return cast(Any, Union).__getitem__(types) # type: ignore
def expand_unions(
@@ -251,4 +267,47 @@ class DescriptorReference(Generic[_DESC]):
...
+_DESC_co = TypeVar("_DESC_co", bound=DescriptorProto, covariant=True)
+
+
+class RODescriptorReference(Generic[_DESC_co]):
+ """a descriptor that refers to a descriptor.
+
+ same as :class:`.DescriptorReference` but is read-only, so that subclasses
+ can define a subtype as the generically contained element
+
+ """
+
+ def __get__(self, instance: object, owner: Any) -> _DESC_co:
+ ...
+
+ def __set__(self, instance: Any, value: Any) -> NoReturn:
+ ...
+
+ def __delete__(self, instance: Any) -> NoReturn:
+ ...
+
+
+_FN = TypeVar("_FN", bound=Optional[Callable[..., Any]])
+
+
+class CallableReference(Generic[_FN]):
+ """a descriptor that refers to a callable.
+
+ works around mypy's limitation of not allowing callables assigned
+ as instance variables
+
+
+ """
+
+ def __get__(self, instance: object, owner: Any) -> _FN:
+ ...
+
+ def __set__(self, instance: Any, value: _FN) -> None:
+ ...
+
+ def __delete__(self, instance: Any) -> None:
+ ...
+
+
# $def ro_descriptor_reference(fn: Callable[])