about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py')
-rw-r--r--.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py b/.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py
new file mode 100644
index 00000000..f01cc178
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/sqlalchemy/orm/descriptor_props.py
@@ -0,0 +1,1077 @@
+# orm/descriptor_props.py
+# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
+# <see AUTHORS file>
+#
+# This module is part of SQLAlchemy and is released under
+# the MIT License: https://www.opensource.org/licenses/mit-license.php
+
+"""Descriptor properties are more "auxiliary" properties
+that exist as configurational elements, but don't participate
+as actively in the load/persist ORM loop.
+
+"""
+from __future__ import annotations
+
+from dataclasses import is_dataclass
+import inspect
+import itertools
+import operator
+import typing
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import List
+from typing import NoReturn
+from typing import Optional
+from typing import Sequence
+from typing import Tuple
+from typing import Type
+from typing import TYPE_CHECKING
+from typing import TypeVar
+from typing import Union
+import weakref
+
+from . import attributes
+from . import util as orm_util
+from .base import _DeclarativeMapped
+from .base import LoaderCallableStatus
+from .base import Mapped
+from .base import PassiveFlag
+from .base import SQLORMOperations
+from .interfaces import _AttributeOptions
+from .interfaces import _IntrospectsAnnotations
+from .interfaces import _MapsColumns
+from .interfaces import MapperProperty
+from .interfaces import PropComparator
+from .util import _none_set
+from .util import de_stringify_annotation
+from .. import event
+from .. import exc as sa_exc
+from .. import schema
+from .. import sql
+from .. import util
+from ..sql import expression
+from ..sql import operators
+from ..sql.elements import BindParameter
+from ..util.typing import get_args
+from ..util.typing import is_fwd_ref
+from ..util.typing import is_pep593
+
+
+if typing.TYPE_CHECKING:
+    from ._typing import _InstanceDict
+    from ._typing import _RegistryType
+    from .attributes import History
+    from .attributes import InstrumentedAttribute
+    from .attributes import QueryableAttribute
+    from .context import ORMCompileState
+    from .decl_base import _ClassScanMapperConfig
+    from .mapper import Mapper
+    from .properties import ColumnProperty
+    from .properties import MappedColumn
+    from .state import InstanceState
+    from ..engine.base import Connection
+    from ..engine.row import Row
+    from ..sql._typing import _DMLColumnArgument
+    from ..sql._typing import _InfoType
+    from ..sql.elements import ClauseList
+    from ..sql.elements import ColumnElement
+    from ..sql.operators import OperatorType
+    from ..sql.schema import Column
+    from ..sql.selectable import Select
+    from ..util.typing import _AnnotationScanType
+    from ..util.typing import CallableReference
+    from ..util.typing import DescriptorReference
+    from ..util.typing import RODescriptorReference
+
+_T = TypeVar("_T", bound=Any)
+_PT = TypeVar("_PT", bound=Any)
+
+
+class DescriptorProperty(MapperProperty[_T]):
+    """:class:`.MapperProperty` which proxies access to a
+    user-defined descriptor."""
+
+    doc: Optional[str] = None
+
+    uses_objects = False
+    _links_to_entity = False
+
+    descriptor: DescriptorReference[Any]
+
+    def get_history(
+        self,
+        state: InstanceState[Any],
+        dict_: _InstanceDict,
+        passive: PassiveFlag = PassiveFlag.PASSIVE_OFF,
+    ) -> History:
+        raise NotImplementedError()
+
+    def instrument_class(self, mapper: Mapper[Any]) -> None:
+        prop = self
+
+        class _ProxyImpl(attributes.AttributeImpl):
+            accepts_scalar_loader = False
+            load_on_unexpire = True
+            collection = False
+
+            @property
+            def uses_objects(self) -> bool:  # type: ignore
+                return prop.uses_objects
+
+            def __init__(self, key: str):
+                self.key = key
+
+            def get_history(
+                self,
+                state: InstanceState[Any],
+                dict_: _InstanceDict,
+                passive: PassiveFlag = PassiveFlag.PASSIVE_OFF,
+            ) -> History:
+                return prop.get_history(state, dict_, passive)
+
+        if self.descriptor is None:
+            desc = getattr(mapper.class_, self.key, None)
+            if mapper._is_userland_descriptor(self.key, desc):
+                self.descriptor = desc
+
+        if self.descriptor is None:
+
+            def fset(obj: Any, value: Any) -> None:
+                setattr(obj, self.name, value)
+
+            def fdel(obj: Any) -> None:
+                delattr(obj, self.name)
+
+            def fget(obj: Any) -> Any:
+                return getattr(obj, self.name)
+
+            self.descriptor = property(fget=fget, fset=fset, fdel=fdel)
+
+        proxy_attr = attributes.create_proxied_attribute(self.descriptor)(
+            self.parent.class_,
+            self.key,
+            self.descriptor,
+            lambda: self._comparator_factory(mapper),
+            doc=self.doc,
+            original_property=self,
+        )
+        proxy_attr.impl = _ProxyImpl(self.key)
+        mapper.class_manager.instrument_attribute(self.key, proxy_attr)
+
+
+_CompositeAttrType = Union[
+    str,
+    "Column[_T]",
+    "MappedColumn[_T]",
+    "InstrumentedAttribute[_T]",
+    "Mapped[_T]",
+]
+
+
+_CC = TypeVar("_CC", bound=Any)
+
+
+_composite_getters: weakref.WeakKeyDictionary[
+    Type[Any], Callable[[Any], Tuple[Any, ...]]
+] = weakref.WeakKeyDictionary()
+
+
+class CompositeProperty(
+    _MapsColumns[_CC], _IntrospectsAnnotations, DescriptorProperty[_CC]
+):
+    """Defines a "composite" mapped attribute, representing a collection
+    of columns as one attribute.
+
+    :class:`.CompositeProperty` is constructed using the :func:`.composite`
+    function.
+
+    .. seealso::
+
+        :ref:`mapper_composite`
+
+    """
+
+    composite_class: Union[Type[_CC], Callable[..., _CC]]
+    attrs: Tuple[_CompositeAttrType[Any], ...]
+
+    _generated_composite_accessor: CallableReference[
+        Optional[Callable[[_CC], Tuple[Any, ...]]]
+    ]
+
+    comparator_factory: Type[Comparator[_CC]]
+
+    def __init__(
+        self,
+        _class_or_attr: Union[
+            None, Type[_CC], Callable[..., _CC], _CompositeAttrType[Any]
+        ] = None,
+        *attrs: _CompositeAttrType[Any],
+        attribute_options: Optional[_AttributeOptions] = None,
+        active_history: bool = False,
+        deferred: bool = False,
+        group: Optional[str] = None,
+        comparator_factory: Optional[Type[Comparator[_CC]]] = None,
+        info: Optional[_InfoType] = None,
+        **kwargs: Any,
+    ):
+        super().__init__(attribute_options=attribute_options)
+
+        if isinstance(_class_or_attr, (Mapped, str, sql.ColumnElement)):
+            self.attrs = (_class_or_attr,) + attrs
+            # will initialize within declarative_scan
+            self.composite_class = None  # type: ignore
+        else:
+            self.composite_class = _class_or_attr  # type: ignore
+            self.attrs = attrs
+
+        self.active_history = active_history
+        self.deferred = deferred
+        self.group = group
+        self.comparator_factory = (
+            comparator_factory
+            if comparator_factory is not None
+            else self.__class__.Comparator
+        )
+        self._generated_composite_accessor = None
+        if info is not None:
+            self.info.update(info)
+
+        util.set_creation_order(self)
+        self._create_descriptor()
+        self._init_accessor()
+
+    def instrument_class(self, mapper: Mapper[Any]) -> None:
+        super().instrument_class(mapper)
+        self._setup_event_handlers()
+
+    def _composite_values_from_instance(self, value: _CC) -> Tuple[Any, ...]:
+        if self._generated_composite_accessor:
+            return self._generated_composite_accessor(value)
+        else:
+            try:
+                accessor = value.__composite_values__
+            except AttributeError as ae:
+                raise sa_exc.InvalidRequestError(
+                    f"Composite class {self.composite_class.__name__} is not "
+                    f"a dataclass and does not define a __composite_values__()"
+                    " method; can't get state"
+                ) from ae
+            else:
+                return accessor()  # type: ignore
+
+    def do_init(self) -> None:
+        """Initialization which occurs after the :class:`.Composite`
+        has been associated with its parent mapper.
+
+        """
+        self._setup_arguments_on_columns()
+
+    _COMPOSITE_FGET = object()
+
+    def _create_descriptor(self) -> None:
+        """Create the Python descriptor that will serve as
+        the access point on instances of the mapped class.
+
+        """
+
+        def fget(instance: Any) -> Any:
+            dict_ = attributes.instance_dict(instance)
+            state = attributes.instance_state(instance)
+
+            if self.key not in dict_:
+                # key not present.  Iterate through related
+                # attributes, retrieve their values.  This
+                # ensures they all load.
+                values = [
+                    getattr(instance, key) for key in self._attribute_keys
+                ]
+
+                # current expected behavior here is that the composite is
+                # created on access if the object is persistent or if
+                # col attributes have non-None.  This would be better
+                # if the composite were created unconditionally,
+                # but that would be a behavioral change.
+                if self.key not in dict_ and (
+                    state.key is not None or not _none_set.issuperset(values)
+                ):
+                    dict_[self.key] = self.composite_class(*values)
+                    state.manager.dispatch.refresh(
+                        state, self._COMPOSITE_FGET, [self.key]
+                    )
+
+            return dict_.get(self.key, None)
+
+        def fset(instance: Any, value: Any) -> None:
+            dict_ = attributes.instance_dict(instance)
+            state = attributes.instance_state(instance)
+            attr = state.manager[self.key]
+
+            if attr.dispatch._active_history:
+                previous = fget(instance)
+            else:
+                previous = dict_.get(self.key, LoaderCallableStatus.NO_VALUE)
+
+            for fn in attr.dispatch.set:
+                value = fn(state, value, previous, attr.impl)
+            dict_[self.key] = value
+            if value is None:
+                for key in self._attribute_keys:
+                    setattr(instance, key, None)
+            else:
+                for key, value in zip(
+                    self._attribute_keys,
+                    self._composite_values_from_instance(value),
+                ):
+                    setattr(instance, key, value)
+
+        def fdel(instance: Any) -> None:
+            state = attributes.instance_state(instance)
+            dict_ = attributes.instance_dict(instance)
+            attr = state.manager[self.key]
+
+            if attr.dispatch._active_history:
+                previous = fget(instance)
+                dict_.pop(self.key, None)
+            else:
+                previous = dict_.pop(self.key, LoaderCallableStatus.NO_VALUE)
+
+            attr = state.manager[self.key]
+            attr.dispatch.remove(state, previous, attr.impl)
+            for key in self._attribute_keys:
+                setattr(instance, key, None)
+
+        self.descriptor = property(fget, fset, fdel)
+
+    @util.preload_module("sqlalchemy.orm.properties")
+    def declarative_scan(
+        self,
+        decl_scan: _ClassScanMapperConfig,
+        registry: _RegistryType,
+        cls: Type[Any],
+        originating_module: Optional[str],
+        key: str,
+        mapped_container: Optional[Type[Mapped[Any]]],
+        annotation: Optional[_AnnotationScanType],
+        extracted_mapped_annotation: Optional[_AnnotationScanType],
+        is_dataclass_field: bool,
+    ) -> None:
+        MappedColumn = util.preloaded.orm_properties.MappedColumn
+        if (
+            self.composite_class is None
+            and extracted_mapped_annotation is None
+        ):
+            self._raise_for_required(key, cls)
+        argument = extracted_mapped_annotation
+
+        if is_pep593(argument):
+            argument = get_args(argument)[0]
+
+        if argument and self.composite_class is None:
+            if isinstance(argument, str) or is_fwd_ref(
+                argument, check_generic=True
+            ):
+                if originating_module is None:
+                    str_arg = (
+                        argument.__forward_arg__
+                        if hasattr(argument, "__forward_arg__")
+                        else str(argument)
+                    )
+                    raise sa_exc.ArgumentError(
+                        f"Can't use forward ref {argument} for composite "
+                        f"class argument; set up the type as Mapped[{str_arg}]"
+                    )
+                argument = de_stringify_annotation(
+                    cls, argument, originating_module, include_generic=True
+                )
+
+            self.composite_class = argument
+
+        if is_dataclass(self.composite_class):
+            self._setup_for_dataclass(registry, cls, originating_module, key)
+        else:
+            for attr in self.attrs:
+                if (
+                    isinstance(attr, (MappedColumn, schema.Column))
+                    and attr.name is None
+                ):
+                    raise sa_exc.ArgumentError(
+                        "Composite class column arguments must be named "
+                        "unless a dataclass is used"
+                    )
+        self._init_accessor()
+
+    def _init_accessor(self) -> None:
+        if is_dataclass(self.composite_class) and not hasattr(
+            self.composite_class, "__composite_values__"
+        ):
+            insp = inspect.signature(self.composite_class)
+            getter = operator.attrgetter(
+                *[p.name for p in insp.parameters.values()]
+            )
+            if len(insp.parameters) == 1:
+                self._generated_composite_accessor = lambda obj: (getter(obj),)
+            else:
+                self._generated_composite_accessor = getter
+
+        if (
+            self.composite_class is not None
+            and isinstance(self.composite_class, type)
+            and self.composite_class not in _composite_getters
+        ):
+            if self._generated_composite_accessor is not None:
+                _composite_getters[self.composite_class] = (
+                    self._generated_composite_accessor
+                )
+            elif hasattr(self.composite_class, "__composite_values__"):
+                _composite_getters[self.composite_class] = (
+                    lambda obj: obj.__composite_values__()
+                )
+
+    @util.preload_module("sqlalchemy.orm.properties")
+    @util.preload_module("sqlalchemy.orm.decl_base")
+    def _setup_for_dataclass(
+        self,
+        registry: _RegistryType,
+        cls: Type[Any],
+        originating_module: Optional[str],
+        key: str,
+    ) -> None:
+        MappedColumn = util.preloaded.orm_properties.MappedColumn
+
+        decl_base = util.preloaded.orm_decl_base
+
+        insp = inspect.signature(self.composite_class)
+        for param, attr in itertools.zip_longest(
+            insp.parameters.values(), self.attrs
+        ):
+            if param is None:
+                raise sa_exc.ArgumentError(
+                    f"number of composite attributes "
+                    f"{len(self.attrs)} exceeds "
+                    f"that of the number of attributes in class "
+                    f"{self.composite_class.__name__} {len(insp.parameters)}"
+                )
+            if attr is None:
+                # fill in missing attr spots with empty MappedColumn
+                attr = MappedColumn()
+                self.attrs += (attr,)
+
+            if isinstance(attr, MappedColumn):
+                attr.declarative_scan_for_composite(
+                    registry,
+                    cls,
+                    originating_module,
+                    key,
+                    param.name,
+                    param.annotation,
+                )
+            elif isinstance(attr, schema.Column):
+                decl_base._undefer_column_name(param.name, attr)
+
+    @util.memoized_property
+    def _comparable_elements(self) -> Sequence[QueryableAttribute[Any]]:
+        return [getattr(self.parent.class_, prop.key) for prop in self.props]
+
+    @util.memoized_property
+    @util.preload_module("orm.properties")
+    def props(self) -> Sequence[MapperProperty[Any]]:
+        props = []
+        MappedColumn = util.preloaded.orm_properties.MappedColumn
+
+        for attr in self.attrs:
+            if isinstance(attr, str):
+                prop = self.parent.get_property(attr, _configure_mappers=False)
+            elif isinstance(attr, schema.Column):
+                prop = self.parent._columntoproperty[attr]
+            elif isinstance(attr, MappedColumn):
+                prop = self.parent._columntoproperty[attr.column]
+            elif isinstance(attr, attributes.InstrumentedAttribute):
+                prop = attr.property
+            else:
+                prop = None
+
+            if not isinstance(prop, MapperProperty):
+                raise sa_exc.ArgumentError(
+                    "Composite expects Column objects or mapped "
+                    f"attributes/attribute names as arguments, got: {attr!r}"
+                )
+
+            props.append(prop)
+        return props
+
+    @util.non_memoized_property
+    @util.preload_module("orm.properties")
+    def columns(self) -> Sequence[Column[Any]]:
+        MappedColumn = util.preloaded.orm_properties.MappedColumn
+        return [
+            a.column if isinstance(a, MappedColumn) else a
+            for a in self.attrs
+            if isinstance(a, (schema.Column, MappedColumn))
+        ]
+
+    @property
+    def mapper_property_to_assign(self) -> Optional[MapperProperty[_CC]]:
+        return self
+
+    @property
+    def columns_to_assign(self) -> List[Tuple[schema.Column[Any], int]]:
+        return [(c, 0) for c in self.columns if c.table is None]
+
+    @util.preload_module("orm.properties")
+    def _setup_arguments_on_columns(self) -> None:
+        """Propagate configuration arguments made on this composite
+        to the target columns, for those that apply.
+
+        """
+        ColumnProperty = util.preloaded.orm_properties.ColumnProperty
+
+        for prop in self.props:
+            if not isinstance(prop, ColumnProperty):
+                continue
+            else:
+                cprop = prop
+
+            cprop.active_history = self.active_history
+            if self.deferred:
+                cprop.deferred = self.deferred
+                cprop.strategy_key = (("deferred", True), ("instrument", True))
+            cprop.group = self.group
+
+    def _setup_event_handlers(self) -> None:
+        """Establish events that populate/expire the composite attribute."""
+
+        def load_handler(
+            state: InstanceState[Any], context: ORMCompileState
+        ) -> None:
+            _load_refresh_handler(state, context, None, is_refresh=False)
+
+        def refresh_handler(
+            state: InstanceState[Any],
+            context: ORMCompileState,
+            to_load: Optional[Sequence[str]],
+        ) -> None:
+            # note this corresponds to sqlalchemy.ext.mutable load_attrs()
+
+            if not to_load or (
+                {self.key}.union(self._attribute_keys)
+            ).intersection(to_load):
+                _load_refresh_handler(state, context, to_load, is_refresh=True)
+
+        def _load_refresh_handler(
+            state: InstanceState[Any],
+            context: ORMCompileState,
+            to_load: Optional[Sequence[str]],
+            is_refresh: bool,
+        ) -> None:
+            dict_ = state.dict
+
+            # if context indicates we are coming from the
+            # fget() handler, this already set the value; skip the
+            # handler here. (other handlers like mutablecomposite will still
+            # want to catch it)
+            # there's an insufficiency here in that the fget() handler
+            # really should not be using the refresh event and there should
+            # be some other event that mutablecomposite can subscribe
+            # towards for this.
+
+            if (
+                not is_refresh or context is self._COMPOSITE_FGET
+            ) and self.key in dict_:
+                return
+
+            # if column elements aren't loaded, skip.
+            # __get__() will initiate a load for those
+            # columns
+            for k in self._attribute_keys:
+                if k not in dict_:
+                    return
+
+            dict_[self.key] = self.composite_class(
+                *[state.dict[key] for key in self._attribute_keys]
+            )
+
+        def expire_handler(
+            state: InstanceState[Any], keys: Optional[Sequence[str]]
+        ) -> None:
+            if keys is None or set(self._attribute_keys).intersection(keys):
+                state.dict.pop(self.key, None)
+
+        def insert_update_handler(
+            mapper: Mapper[Any],
+            connection: Connection,
+            state: InstanceState[Any],
+        ) -> None:
+            """After an insert or update, some columns may be expired due
+            to server side defaults, or re-populated due to client side
+            defaults.  Pop out the composite value here so that it
+            recreates.
+
+            """
+
+            state.dict.pop(self.key, None)
+
+        event.listen(
+            self.parent, "after_insert", insert_update_handler, raw=True
+        )
+        event.listen(
+            self.parent, "after_update", insert_update_handler, raw=True
+        )
+        event.listen(
+            self.parent, "load", load_handler, raw=True, propagate=True
+        )
+        event.listen(
+            self.parent, "refresh", refresh_handler, raw=True, propagate=True
+        )
+        event.listen(
+            self.parent, "expire", expire_handler, raw=True, propagate=True
+        )
+
+        proxy_attr = self.parent.class_manager[self.key]
+        proxy_attr.impl.dispatch = proxy_attr.dispatch  # type: ignore
+        proxy_attr.impl.dispatch._active_history = self.active_history
+
+        # TODO: need a deserialize hook here
+
+    @util.memoized_property
+    def _attribute_keys(self) -> Sequence[str]:
+        return [prop.key for prop in self.props]
+
+    def _populate_composite_bulk_save_mappings_fn(
+        self,
+    ) -> Callable[[Dict[str, Any]], None]:
+        if self._generated_composite_accessor:
+            get_values = self._generated_composite_accessor
+        else:
+
+            def get_values(val: Any) -> Tuple[Any]:
+                return val.__composite_values__()  # type: ignore
+
+        attrs = [prop.key for prop in self.props]
+
+        def populate(dest_dict: Dict[str, Any]) -> None:
+            dest_dict.update(
+                {
+                    key: val
+                    for key, val in zip(
+                        attrs, get_values(dest_dict.pop(self.key))
+                    )
+                }
+            )
+
+        return populate
+
+    def get_history(
+        self,
+        state: InstanceState[Any],
+        dict_: _InstanceDict,
+        passive: PassiveFlag = PassiveFlag.PASSIVE_OFF,
+    ) -> History:
+        """Provided for userland code that uses attributes.get_history()."""
+
+        added: List[Any] = []
+        deleted: List[Any] = []
+
+        has_history = False
+        for prop in self.props:
+            key = prop.key
+            hist = state.manager[key].impl.get_history(state, dict_)
+            if hist.has_changes():
+                has_history = True
+
+            non_deleted = hist.non_deleted()
+            if non_deleted:
+                added.extend(non_deleted)
+            else:
+                added.append(None)
+            if hist.deleted:
+                deleted.extend(hist.deleted)
+            else:
+                deleted.append(None)
+
+        if has_history:
+            return attributes.History(
+                [self.composite_class(*added)],
+                (),
+                [self.composite_class(*deleted)],
+            )
+        else:
+            return attributes.History((), [self.composite_class(*added)], ())
+
+    def _comparator_factory(
+        self, mapper: Mapper[Any]
+    ) -> Composite.Comparator[_CC]:
+        return self.comparator_factory(self, mapper)
+
+    class CompositeBundle(orm_util.Bundle[_T]):
+        def __init__(
+            self,
+            property_: Composite[_T],
+            expr: ClauseList,
+        ):
+            self.property = property_
+            super().__init__(property_.key, *expr)
+
+        def create_row_processor(
+            self,
+            query: Select[Any],
+            procs: Sequence[Callable[[Row[Any]], Any]],
+            labels: Sequence[str],
+        ) -> Callable[[Row[Any]], Any]:
+            def proc(row: Row[Any]) -> Any:
+                return self.property.composite_class(
+                    *[proc(row) for proc in procs]
+                )
+
+            return proc
+
+    class Comparator(PropComparator[_PT]):
+        """Produce boolean, comparison, and other operators for
+        :class:`.Composite` attributes.
+
+        See the example in :ref:`composite_operations` for an overview
+        of usage , as well as the documentation for :class:`.PropComparator`.
+
+        .. seealso::
+
+            :class:`.PropComparator`
+
+            :class:`.ColumnOperators`
+
+            :ref:`types_operators`
+
+            :attr:`.TypeEngine.comparator_factory`
+
+        """
+
+        # https://github.com/python/mypy/issues/4266
+        __hash__ = None  # type: ignore
+
+        prop: RODescriptorReference[Composite[_PT]]
+
+        @util.memoized_property
+        def clauses(self) -> ClauseList:
+            return expression.ClauseList(
+                group=False, *self._comparable_elements
+            )
+
+        def __clause_element__(self) -> CompositeProperty.CompositeBundle[_PT]:
+            return self.expression
+
+        @util.memoized_property
+        def expression(self) -> CompositeProperty.CompositeBundle[_PT]:
+            clauses = self.clauses._annotate(
+                {
+                    "parententity": self._parententity,
+                    "parentmapper": self._parententity,
+                    "proxy_key": self.prop.key,
+                }
+            )
+            return CompositeProperty.CompositeBundle(self.prop, clauses)
+
+        def _bulk_update_tuples(
+            self, value: Any
+        ) -> Sequence[Tuple[_DMLColumnArgument, Any]]:
+            if isinstance(value, BindParameter):
+                value = value.value
+
+            values: Sequence[Any]
+
+            if value is None:
+                values = [None for key in self.prop._attribute_keys]
+            elif isinstance(self.prop.composite_class, type) and isinstance(
+                value, self.prop.composite_class
+            ):
+                values = self.prop._composite_values_from_instance(
+                    value  # type: ignore[arg-type]
+                )
+            else:
+                raise sa_exc.ArgumentError(
+                    "Can't UPDATE composite attribute %s to %r"
+                    % (self.prop, value)
+                )
+
+            return list(zip(self._comparable_elements, values))
+
+        @util.memoized_property
+        def _comparable_elements(self) -> Sequence[QueryableAttribute[Any]]:
+            if self._adapt_to_entity:
+                return [
+                    getattr(self._adapt_to_entity.entity, prop.key)
+                    for prop in self.prop._comparable_elements
+                ]
+            else:
+                return self.prop._comparable_elements
+
+        def __eq__(self, other: Any) -> ColumnElement[bool]:  # type: ignore[override]  # noqa: E501
+            return self._compare(operators.eq, other)
+
+        def __ne__(self, other: Any) -> ColumnElement[bool]:  # type: ignore[override]  # noqa: E501
+            return self._compare(operators.ne, other)
+
+        def __lt__(self, other: Any) -> ColumnElement[bool]:
+            return self._compare(operators.lt, other)
+
+        def __gt__(self, other: Any) -> ColumnElement[bool]:
+            return self._compare(operators.gt, other)
+
+        def __le__(self, other: Any) -> ColumnElement[bool]:
+            return self._compare(operators.le, other)
+
+        def __ge__(self, other: Any) -> ColumnElement[bool]:
+            return self._compare(operators.ge, other)
+
+        # what might be interesting would be if we create
+        # an instance of the composite class itself with
+        # the columns as data members, then use "hybrid style" comparison
+        # to create these comparisons.  then your Point.__eq__() method could
+        # be where comparison behavior is defined for SQL also.   Likely
+        # not a good choice for default behavior though, not clear how it would
+        # work w/ dataclasses, etc.  also no demand for any of this anyway.
+        def _compare(
+            self, operator: OperatorType, other: Any
+        ) -> ColumnElement[bool]:
+            values: Sequence[Any]
+            if other is None:
+                values = [None] * len(self.prop._comparable_elements)
+            else:
+                values = self.prop._composite_values_from_instance(other)
+            comparisons = [
+                operator(a, b)
+                for a, b in zip(self.prop._comparable_elements, values)
+            ]
+            if self._adapt_to_entity:
+                assert self.adapter is not None
+                comparisons = [self.adapter(x) for x in comparisons]
+            return sql.and_(*comparisons)
+
+    def __str__(self) -> str:
+        return str(self.parent.class_.__name__) + "." + self.key
+
+
+class Composite(CompositeProperty[_T], _DeclarativeMapped[_T]):
+    """Declarative-compatible front-end for the :class:`.CompositeProperty`
+    class.
+
+    Public constructor is the :func:`_orm.composite` function.
+
+    .. versionchanged:: 2.0 Added :class:`_orm.Composite` as a Declarative
+       compatible subclass of :class:`_orm.CompositeProperty`.
+
+    .. seealso::
+
+        :ref:`mapper_composite`
+
+    """
+
+    inherit_cache = True
+    """:meta private:"""
+
+
+class ConcreteInheritedProperty(DescriptorProperty[_T]):
+    """A 'do nothing' :class:`.MapperProperty` that disables
+    an attribute on a concrete subclass that is only present
+    on the inherited mapper, not the concrete classes' mapper.
+
+    Cases where this occurs include:
+
+    * When the superclass mapper is mapped against a
+      "polymorphic union", which includes all attributes from
+      all subclasses.
+    * When a relationship() is configured on an inherited mapper,
+      but not on the subclass mapper.  Concrete mappers require
+      that relationship() is configured explicitly on each
+      subclass.
+
+    """
+
+    def _comparator_factory(
+        self, mapper: Mapper[Any]
+    ) -> Type[PropComparator[_T]]:
+        comparator_callable = None
+
+        for m in self.parent.iterate_to_root():
+            p = m._props[self.key]
+            if getattr(p, "comparator_factory", None) is not None:
+                comparator_callable = p.comparator_factory
+                break
+        assert comparator_callable is not None
+        return comparator_callable(p, mapper)  # type: ignore
+
+    def __init__(self) -> None:
+        super().__init__()
+
+        def warn() -> NoReturn:
+            raise AttributeError(
+                "Concrete %s does not implement "
+                "attribute %r at the instance level.  Add "
+                "this property explicitly to %s."
+                % (self.parent, self.key, self.parent)
+            )
+
+        class NoninheritedConcreteProp:
+            def __set__(s: Any, obj: Any, value: Any) -> NoReturn:
+                warn()
+
+            def __delete__(s: Any, obj: Any) -> NoReturn:
+                warn()
+
+            def __get__(s: Any, obj: Any, owner: Any) -> Any:
+                if obj is None:
+                    return self.descriptor
+                warn()
+
+        self.descriptor = NoninheritedConcreteProp()
+
+
+class SynonymProperty(DescriptorProperty[_T]):
+    """Denote an attribute name as a synonym to a mapped property,
+    in that the attribute will mirror the value and expression behavior
+    of another attribute.
+
+    :class:`.Synonym` is constructed using the :func:`_orm.synonym`
+    function.
+
+    .. seealso::
+
+        :ref:`synonyms` - Overview of synonyms
+
+    """
+
+    comparator_factory: Optional[Type[PropComparator[_T]]]
+
+    def __init__(
+        self,
+        name: str,
+        map_column: Optional[bool] = None,
+        descriptor: Optional[Any] = None,
+        comparator_factory: Optional[Type[PropComparator[_T]]] = None,
+        attribute_options: Optional[_AttributeOptions] = None,
+        info: Optional[_InfoType] = None,
+        doc: Optional[str] = None,
+    ):
+        super().__init__(attribute_options=attribute_options)
+
+        self.name = name
+        self.map_column = map_column
+        self.descriptor = descriptor
+        self.comparator_factory = comparator_factory
+        if doc:
+            self.doc = doc
+        elif descriptor and descriptor.__doc__:
+            self.doc = descriptor.__doc__
+        else:
+            self.doc = None
+        if info:
+            self.info.update(info)
+
+        util.set_creation_order(self)
+
+    if not TYPE_CHECKING:
+
+        @property
+        def uses_objects(self) -> bool:
+            return getattr(self.parent.class_, self.name).impl.uses_objects
+
+    # TODO: when initialized, check _proxied_object,
+    # emit a warning if its not a column-based property
+
+    @util.memoized_property
+    def _proxied_object(
+        self,
+    ) -> Union[MapperProperty[_T], SQLORMOperations[_T]]:
+        attr = getattr(self.parent.class_, self.name)
+        if not hasattr(attr, "property") or not isinstance(
+            attr.property, MapperProperty
+        ):
+            # attribute is a non-MapperProprerty proxy such as
+            # hybrid or association proxy
+            if isinstance(attr, attributes.QueryableAttribute):
+                return attr.comparator
+            elif isinstance(attr, SQLORMOperations):
+                # assocaition proxy comes here
+                return attr
+
+            raise sa_exc.InvalidRequestError(
+                """synonym() attribute "%s.%s" only supports """
+                """ORM mapped attributes, got %r"""
+                % (self.parent.class_.__name__, self.name, attr)
+            )
+        return attr.property
+
+    def _comparator_factory(self, mapper: Mapper[Any]) -> SQLORMOperations[_T]:
+        prop = self._proxied_object
+
+        if isinstance(prop, MapperProperty):
+            if self.comparator_factory:
+                comp = self.comparator_factory(prop, mapper)
+            else:
+                comp = prop.comparator_factory(prop, mapper)
+            return comp
+        else:
+            return prop
+
+    def get_history(
+        self,
+        state: InstanceState[Any],
+        dict_: _InstanceDict,
+        passive: PassiveFlag = PassiveFlag.PASSIVE_OFF,
+    ) -> History:
+        attr: QueryableAttribute[Any] = getattr(self.parent.class_, self.name)
+        return attr.impl.get_history(state, dict_, passive=passive)
+
+    @util.preload_module("sqlalchemy.orm.properties")
+    def set_parent(self, parent: Mapper[Any], init: bool) -> None:
+        properties = util.preloaded.orm_properties
+
+        if self.map_column:
+            # implement the 'map_column' option.
+            if self.key not in parent.persist_selectable.c:
+                raise sa_exc.ArgumentError(
+                    "Can't compile synonym '%s': no column on table "
+                    "'%s' named '%s'"
+                    % (
+                        self.name,
+                        parent.persist_selectable.description,
+                        self.key,
+                    )
+                )
+            elif (
+                parent.persist_selectable.c[self.key]
+                in parent._columntoproperty
+                and parent._columntoproperty[
+                    parent.persist_selectable.c[self.key]
+                ].key
+                == self.name
+            ):
+                raise sa_exc.ArgumentError(
+                    "Can't call map_column=True for synonym %r=%r, "
+                    "a ColumnProperty already exists keyed to the name "
+                    "%r for column %r"
+                    % (self.key, self.name, self.name, self.key)
+                )
+            p: ColumnProperty[Any] = properties.ColumnProperty(
+                parent.persist_selectable.c[self.key]
+            )
+            parent._configure_property(self.name, p, init=init, setparent=True)
+            p._mapped_by_synonym = self.key
+
+        self.parent = parent
+
+
+class Synonym(SynonymProperty[_T], _DeclarativeMapped[_T]):
+    """Declarative front-end for the :class:`.SynonymProperty` class.
+
+    Public constructor is the :func:`_orm.synonym` function.
+
+    .. versionchanged:: 2.0 Added :class:`_orm.Synonym` as a Declarative
+       compatible subclass for :class:`_orm.SynonymProperty`
+
+    .. seealso::
+
+        :ref:`synonyms` - Overview of synonyms
+
+    """
+
+    inherit_cache = True
+    """:meta private:"""