diff options
Diffstat (limited to 'lib/sqlalchemy/sql/annotation.py')
| -rw-r--r-- | lib/sqlalchemy/sql/annotation.py | 138 |
1 files changed, 62 insertions, 76 deletions
diff --git a/lib/sqlalchemy/sql/annotation.py b/lib/sqlalchemy/sql/annotation.py index 046c9bc79..7487e074c 100644 --- a/lib/sqlalchemy/sql/annotation.py +++ b/lib/sqlalchemy/sql/annotation.py @@ -39,6 +39,7 @@ from .visitors import ExternallyTraversible from .visitors import InternalTraversal from .. import util from ..util.typing import Literal +from ..util.typing import Self if TYPE_CHECKING: from .base import _EntityNamespace @@ -49,11 +50,6 @@ _AnnotationDict = Mapping[str, Any] EMPTY_ANNOTATIONS: util.immutabledict[str, Any] = util.EMPTY_DICT -SelfSupportsAnnotations = TypeVar( - "SelfSupportsAnnotations", bound="SupportsAnnotations" -) - - class SupportsAnnotations(ExternallyTraversible): __slots__ = () @@ -63,17 +59,15 @@ class SupportsAnnotations(ExternallyTraversible): _is_immutable: bool - def _annotate( - self: SelfSupportsAnnotations, values: _AnnotationDict - ) -> SelfSupportsAnnotations: + def _annotate(self, values: _AnnotationDict) -> Self: raise NotImplementedError() @overload def _deannotate( - self: SelfSupportsAnnotations, + self, values: Literal[None] = ..., clone: bool = ..., - ) -> SelfSupportsAnnotations: + ) -> Self: ... @overload @@ -117,46 +111,37 @@ class SupportsAnnotations(ExternallyTraversible): ) -class SupportsCloneAnnotations(SupportsAnnotations): - if not typing.TYPE_CHECKING: - __slots__ = () +class SupportsWrappingAnnotations(SupportsAnnotations): + __slots__ = () - _clone_annotations_traverse_internals: _TraverseInternalsType = [ - ("_annotations", InternalTraversal.dp_annotations_key) - ] + _constructor: Callable[..., SupportsWrappingAnnotations] + + if TYPE_CHECKING: + + @util.ro_non_memoized_property + def entity_namespace(self) -> _EntityNamespace: + ... - def _annotate( - self: SelfSupportsAnnotations, values: _AnnotationDict - ) -> SelfSupportsAnnotations: + def _annotate(self, values: _AnnotationDict) -> Self: """return a copy of this ClauseElement with annotations updated by the given dictionary. """ - new = self._clone() - new._annotations = new._annotations.union(values) - new.__dict__.pop("_annotations_cache_key", None) - new.__dict__.pop("_generate_cache_key", None) - return new + return Annotated._as_annotated_instance(self, values) # type: ignore - def _with_annotations( - self: SelfSupportsAnnotations, values: _AnnotationDict - ) -> SelfSupportsAnnotations: + def _with_annotations(self, values: _AnnotationDict) -> Self: """return a copy of this ClauseElement with annotations replaced by the given dictionary. """ - new = self._clone() - new._annotations = util.immutabledict(values) - new.__dict__.pop("_annotations_cache_key", None) - new.__dict__.pop("_generate_cache_key", None) - return new + return Annotated._as_annotated_instance(self, values) # type: ignore @overload def _deannotate( - self: SelfSupportsAnnotations, + self, values: Literal[None] = ..., clone: bool = ..., - ) -> SelfSupportsAnnotations: + ) -> Self: ... @overload @@ -180,52 +165,56 @@ class SupportsCloneAnnotations(SupportsAnnotations): to remove. """ - if clone or self._annotations: - # clone is used when we are also copying - # the expression for a deep deannotation - new = self._clone() - new._annotations = util.immutabledict() - new.__dict__.pop("_annotations_cache_key", None) - return new + if clone: + s = self._clone() + return s else: return self -class SupportsWrappingAnnotations(SupportsAnnotations): - __slots__ = () +class SupportsCloneAnnotations(SupportsWrappingAnnotations): + # SupportsCloneAnnotations extends from SupportsWrappingAnnotations + # to support the structure of having the base ClauseElement + # be a subclass of SupportsWrappingAnnotations. Any ClauseElement + # subclass that wants to extend from SupportsCloneAnnotations + # will inherently also be subclassing SupportsWrappingAnnotations, so + # make that specific here. - _constructor: Callable[..., SupportsWrappingAnnotations] - - if TYPE_CHECKING: + if not typing.TYPE_CHECKING: + __slots__ = () - @util.ro_non_memoized_property - def entity_namespace(self) -> _EntityNamespace: - ... + _clone_annotations_traverse_internals: _TraverseInternalsType = [ + ("_annotations", InternalTraversal.dp_annotations_key) + ] - def _annotate( - self: SelfSupportsAnnotations, values: _AnnotationDict - ) -> SelfSupportsAnnotations: + def _annotate(self, values: _AnnotationDict) -> Self: """return a copy of this ClauseElement with annotations updated by the given dictionary. """ - return Annotated._as_annotated_instance(self, values) # type: ignore + new = self._clone() + new._annotations = new._annotations.union(values) + new.__dict__.pop("_annotations_cache_key", None) + new.__dict__.pop("_generate_cache_key", None) + return new - def _with_annotations( - self: SelfSupportsAnnotations, values: _AnnotationDict - ) -> SelfSupportsAnnotations: + def _with_annotations(self, values: _AnnotationDict) -> Self: """return a copy of this ClauseElement with annotations replaced by the given dictionary. """ - return Annotated._as_annotated_instance(self, values) # type: ignore + new = self._clone() + new._annotations = util.immutabledict(values) + new.__dict__.pop("_annotations_cache_key", None) + new.__dict__.pop("_generate_cache_key", None) + return new @overload def _deannotate( - self: SelfSupportsAnnotations, + self, values: Literal[None] = ..., clone: bool = ..., - ) -> SelfSupportsAnnotations: + ) -> Self: ... @overload @@ -249,16 +238,17 @@ class SupportsWrappingAnnotations(SupportsAnnotations): to remove. """ - if clone: - s = self._clone() - return s + if clone or self._annotations: + # clone is used when we are also copying + # the expression for a deep deannotation + new = self._clone() + new._annotations = util.immutabledict() + new.__dict__.pop("_annotations_cache_key", None) + return new else: return self -SelfAnnotated = TypeVar("SelfAnnotated", bound="Annotated") - - class Annotated(SupportsAnnotations): """clones a SupportsAnnotations and applies an 'annotations' dictionary. @@ -295,7 +285,7 @@ class Annotated(SupportsAnnotations): __element: SupportsWrappingAnnotations _hash: int - def __new__(cls: Type[SelfAnnotated], *args: Any) -> SelfAnnotated: + def __new__(cls: Type[Self], *args: Any) -> Self: return object.__new__(cls) def __init__( @@ -308,16 +298,12 @@ class Annotated(SupportsAnnotations): self._annotations = util.immutabledict(values) self._hash = hash(element) - def _annotate( - self: SelfAnnotated, values: _AnnotationDict - ) -> SelfAnnotated: + def _annotate(self, values: _AnnotationDict) -> Self: _values = self._annotations.union(values) - new: SelfAnnotated = self._with_annotations(_values) # type: ignore + new = self._with_annotations(_values) # type: ignore return new - def _with_annotations( - self: SelfAnnotated, values: _AnnotationDict - ) -> SupportsAnnotations: + def _with_annotations(self, values: _AnnotationDict) -> Self: clone = self.__class__.__new__(self.__class__) clone.__dict__ = self.__dict__.copy() clone.__dict__.pop("_annotations_cache_key", None) @@ -327,10 +313,10 @@ class Annotated(SupportsAnnotations): @overload def _deannotate( - self: SelfAnnotated, + self, values: Literal[None] = ..., clone: bool = ..., - ) -> SelfAnnotated: + ) -> Self: ... @overload @@ -370,7 +356,7 @@ class Annotated(SupportsAnnotations): def _constructor(self): return self.__element._constructor - def _clone(self: SelfAnnotated, **kw: Any) -> SelfAnnotated: + def _clone(self, **kw: Any) -> Self: clone = self.__element._clone(**kw) if clone is self.__element: # detect immutable, don't change anything |
