Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/base.py: 59%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# orm/base.py
2# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
8"""Constants and rudimental functions used throughout the ORM."""
10from __future__ import annotations
12from enum import Enum
13import operator
14import typing
15from typing import Any
16from typing import Callable
17from typing import cast
18from typing import Dict
19from typing import Generic
20from typing import Literal
21from typing import no_type_check
22from typing import Optional
23from typing import overload
24from typing import Tuple
25from typing import Type
26from typing import TYPE_CHECKING
27from typing import TypeVar
28from typing import Union
30from . import exc
31from ._typing import _HasPathString
32from ._typing import _O
33from ._typing import insp_is_mapper
34from .. import exc as sa_exc
35from .. import inspection
36from .. import util
37from ..sql import roles
38from ..sql._typing import _T
39from ..sql._typing import _T_co
40from ..sql.elements import SQLColumnExpression
41from ..sql.elements import SQLCoreOperations
42from ..util import FastIntFlag
43from ..util.langhelpers import TypingOnly
45if typing.TYPE_CHECKING:
46 from ._typing import _EntityType
47 from ._typing import _ExternalEntityType
48 from ._typing import _InternalEntityType
49 from .attributes import InstrumentedAttribute
50 from .dynamic import AppenderQuery
51 from .instrumentation import ClassManager
52 from .interfaces import PropComparator
53 from .mapper import Mapper
54 from .properties import MappedColumn
55 from .state import InstanceState
56 from .util import AliasedClass
57 from .writeonly import WriteOnlyCollection
58 from ..sql._annotated_cols import TypedColumns
59 from ..sql._typing import _ColumnExpressionArgument
60 from ..sql._typing import _InfoType
61 from ..sql.elements import ColumnElement
62 from ..sql.operators import OperatorType
63 from ..sql.schema import Column
66class LoaderCallableStatus(Enum):
67 PASSIVE_NO_RESULT = 0
68 """Symbol returned by a loader callable or other attribute/history
69 retrieval operation when a value could not be determined, based
70 on loader callable flags.
71 """
73 PASSIVE_CLASS_MISMATCH = 1
74 """Symbol indicating that an object is locally present for a given
75 primary key identity but it is not of the requested class. The
76 return value is therefore None and no SQL should be emitted."""
78 ATTR_WAS_SET = 2
79 """Symbol returned by a loader callable to indicate the
80 retrieved value, or values, were assigned to their attributes
81 on the target object.
82 """
84 ATTR_EMPTY = 3
85 """Symbol used internally to indicate an attribute had no callable."""
87 NO_VALUE = 4
88 """Symbol which may be placed as the 'previous' value of an attribute,
89 indicating no value was loaded for an attribute when it was modified,
90 and flags indicated we were not to load it.
91 """
93 NEVER_SET = NO_VALUE
94 """
95 Synonymous with NO_VALUE
97 .. versionchanged:: 1.4 NEVER_SET was merged with NO_VALUE
99 """
101 DONT_SET = 5
104(
105 PASSIVE_NO_RESULT,
106 PASSIVE_CLASS_MISMATCH,
107 ATTR_WAS_SET,
108 ATTR_EMPTY,
109 NO_VALUE,
110 DONT_SET,
111) = tuple(LoaderCallableStatus)
113NEVER_SET = NO_VALUE
116class PassiveFlag(FastIntFlag):
117 """Bitflag interface that passes options onto loader callables"""
119 NO_CHANGE = 0
120 """No callables or SQL should be emitted on attribute access
121 and no state should change
122 """
124 CALLABLES_OK = 1
125 """Loader callables can be fired off if a value
126 is not present.
127 """
129 SQL_OK = 2
130 """Loader callables can emit SQL at least on scalar value attributes."""
132 RELATED_OBJECT_OK = 4
133 """Callables can use SQL to load related objects as well
134 as scalar value attributes.
135 """
137 INIT_OK = 8
138 """Attributes should be initialized with a blank
139 value (None or an empty collection) upon get, if no other
140 value can be obtained.
141 """
143 NON_PERSISTENT_OK = 16
144 """Callables can be emitted if the parent is not persistent."""
146 LOAD_AGAINST_COMMITTED = 32
147 """Callables should use committed values as primary/foreign keys during a
148 load.
149 """
151 NO_AUTOFLUSH = 64
152 """Loader callables should disable autoflush."""
154 NO_RAISE = 128
155 """Loader callables should not raise any assertions"""
157 DEFERRED_HISTORY_LOAD = 256
158 """indicates special load of the previous value of an attribute"""
160 INCLUDE_PENDING_MUTATIONS = 512
162 # pre-packaged sets of flags used as inputs
163 PASSIVE_OFF = (
164 RELATED_OBJECT_OK | NON_PERSISTENT_OK | INIT_OK | CALLABLES_OK | SQL_OK
165 )
166 "Callables can be emitted in all cases."
168 PASSIVE_RETURN_NO_VALUE = PASSIVE_OFF ^ INIT_OK
169 """PASSIVE_OFF ^ INIT_OK"""
171 PASSIVE_NO_INITIALIZE = PASSIVE_RETURN_NO_VALUE ^ CALLABLES_OK
172 "PASSIVE_RETURN_NO_VALUE ^ CALLABLES_OK"
174 PASSIVE_NO_FETCH = PASSIVE_OFF ^ SQL_OK
175 "PASSIVE_OFF ^ SQL_OK"
177 PASSIVE_NO_FETCH_RELATED = PASSIVE_OFF ^ RELATED_OBJECT_OK
178 "PASSIVE_OFF ^ RELATED_OBJECT_OK"
180 PASSIVE_ONLY_PERSISTENT = PASSIVE_OFF ^ NON_PERSISTENT_OK
181 "PASSIVE_OFF ^ NON_PERSISTENT_OK"
183 PASSIVE_MERGE = PASSIVE_OFF | NO_RAISE
184 """PASSIVE_OFF | NO_RAISE
186 Symbol used specifically for session.merge() and similar cases
188 """
191(
192 NO_CHANGE,
193 CALLABLES_OK,
194 SQL_OK,
195 RELATED_OBJECT_OK,
196 INIT_OK,
197 NON_PERSISTENT_OK,
198 LOAD_AGAINST_COMMITTED,
199 NO_AUTOFLUSH,
200 NO_RAISE,
201 DEFERRED_HISTORY_LOAD,
202 INCLUDE_PENDING_MUTATIONS,
203 PASSIVE_OFF,
204 PASSIVE_RETURN_NO_VALUE,
205 PASSIVE_NO_INITIALIZE,
206 PASSIVE_NO_FETCH,
207 PASSIVE_NO_FETCH_RELATED,
208 PASSIVE_ONLY_PERSISTENT,
209 PASSIVE_MERGE,
210) = PassiveFlag.__members__.values()
212DEFAULT_MANAGER_ATTR = "_sa_class_manager"
213DEFAULT_STATE_ATTR = "_sa_instance_state"
216class EventConstants(Enum):
217 EXT_CONTINUE = 1
218 EXT_STOP = 2
219 EXT_SKIP = 3
220 NO_KEY = 4
221 """indicates an :class:`.AttributeEvent` event that did not have any
222 key argument.
224 .. versionadded:: 2.0
226 """
229EXT_CONTINUE, EXT_STOP, EXT_SKIP, NO_KEY = tuple(EventConstants)
232class RelationshipDirection(Enum):
233 """enumeration which indicates the 'direction' of a
234 :class:`_orm.RelationshipProperty`.
236 :class:`.RelationshipDirection` is accessible from the
237 :attr:`_orm.Relationship.direction` attribute of
238 :class:`_orm.RelationshipProperty`.
240 """
242 ONETOMANY = 1
243 """Indicates the one-to-many direction for a :func:`_orm.relationship`.
245 This symbol is typically used by the internals but may be exposed within
246 certain API features.
248 """
250 MANYTOONE = 2
251 """Indicates the many-to-one direction for a :func:`_orm.relationship`.
253 This symbol is typically used by the internals but may be exposed within
254 certain API features.
256 """
258 MANYTOMANY = 3
259 """Indicates the many-to-many direction for a :func:`_orm.relationship`.
261 This symbol is typically used by the internals but may be exposed within
262 certain API features.
264 """
267ONETOMANY, MANYTOONE, MANYTOMANY = tuple(RelationshipDirection)
270class InspectionAttrExtensionType(Enum):
271 """Symbols indicating the type of extension that a
272 :class:`.InspectionAttr` is part of."""
275class NotExtension(InspectionAttrExtensionType):
276 NOT_EXTENSION = "not_extension"
277 """Symbol indicating an :class:`InspectionAttr` that's
278 not part of sqlalchemy.ext.
280 Is assigned to the :attr:`.InspectionAttr.extension_type`
281 attribute.
283 """
286_never_set = frozenset([NEVER_SET])
288_none_set = frozenset([None, NEVER_SET, PASSIVE_NO_RESULT])
290_none_only_set = frozenset([None])
292_SET_DEFERRED_EXPIRED = util.symbol("SET_DEFERRED_EXPIRED")
294_DEFER_FOR_STATE = util.symbol("DEFER_FOR_STATE")
296_RAISE_FOR_STATE = util.symbol("RAISE_FOR_STATE")
299_F = TypeVar("_F", bound=Callable[..., Any])
300_Self = TypeVar("_Self")
303def _assertions(
304 *assertions: Any,
305) -> Callable[[_F], _F]:
306 @util.decorator
307 def generate(fn: _F, self: _Self, *args: Any, **kw: Any) -> _Self:
308 for assertion in assertions:
309 assertion(self, fn.__name__)
310 fn(self, *args, **kw)
311 return self
313 return generate
316if TYPE_CHECKING:
318 def manager_of_class(cls: Type[_O]) -> ClassManager[_O]: ...
320 @overload
321 def opt_manager_of_class(cls: AliasedClass[Any]) -> None: ...
323 @overload
324 def opt_manager_of_class(
325 cls: _ExternalEntityType[_O],
326 ) -> Optional[ClassManager[_O]]: ...
328 def opt_manager_of_class(
329 cls: _ExternalEntityType[_O],
330 ) -> Optional[ClassManager[_O]]: ...
332 def instance_state(instance: _O) -> InstanceState[_O]: ...
334 def instance_dict(instance: object) -> Dict[str, Any]: ...
336else:
337 # these can be replaced by sqlalchemy.ext.instrumentation
338 # if augmented class instrumentation is enabled.
340 def manager_of_class(cls):
341 try:
342 return cls.__dict__[DEFAULT_MANAGER_ATTR]
343 except KeyError as ke:
344 raise exc.UnmappedClassError(
345 cls, f"Can't locate an instrumentation manager for class {cls}"
346 ) from ke
348 def opt_manager_of_class(cls):
349 return cls.__dict__.get(DEFAULT_MANAGER_ATTR)
351 instance_state = operator.attrgetter(DEFAULT_STATE_ATTR)
353 instance_dict = operator.attrgetter("__dict__")
356def instance_str(instance: object) -> str:
357 """Return a string describing an instance."""
359 return state_str(instance_state(instance))
362def state_str(state: InstanceState[Any]) -> str:
363 """Return a string describing an instance via its InstanceState."""
365 if state is None:
366 return "None"
367 else:
368 return "<%s at 0x%x>" % (state.class_.__name__, id(state.obj()))
371def state_class_str(state: InstanceState[Any]) -> str:
372 """Return a string describing an instance's class via its
373 InstanceState.
374 """
376 if state is None:
377 return "None"
378 else:
379 return "<%s>" % (state.class_.__name__,)
382def attribute_str(instance: object, attribute: str) -> str:
383 return instance_str(instance) + "." + attribute
386def state_attribute_str(state: InstanceState[Any], attribute: str) -> str:
387 return state_str(state) + "." + attribute
390def entity_str(entity: Any) -> str:
391 """Return a user-facing string for a mapped entity, such as a mapped
392 class, :class:`_orm.Mapper`, or :func:`_orm.aliased` construct.
394 Also accepts a :class:`_orm.PathRegistry` directly, which is itself
395 ``inspect()``-able and implements ``path_string()``; in that case
396 this is equivalent to calling
397 :meth:`_orm.PathRegistry.path_string` directly.
399 """
400 return cast(_HasPathString, inspection.inspect(entity)).path_string()
403def object_mapper(instance: _T) -> Mapper[_T]:
404 """Given an object, return the primary Mapper associated with the object
405 instance.
407 Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
408 if no mapping is configured.
410 This function is available via the inspection system as::
412 inspect(instance).mapper
414 Using the inspection system will raise
415 :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
416 not part of a mapping.
418 """
419 return object_state(instance).mapper
422def object_state(instance: _T) -> InstanceState[_T]:
423 """Given an object, return the :class:`.InstanceState`
424 associated with the object.
426 Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
427 if no mapping is configured.
429 Equivalent functionality is available via the :func:`_sa.inspect`
430 function as::
432 inspect(instance)
434 Using the inspection system will raise
435 :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
436 not part of a mapping.
438 """
439 state = _inspect_mapped_object(instance)
440 if state is None:
441 raise exc.UnmappedInstanceError(instance)
442 else:
443 return state
446@inspection._inspects(object)
447def _inspect_mapped_object(instance: _T) -> Optional[InstanceState[_T]]:
448 try:
449 return instance_state(instance)
450 except (exc.UnmappedClassError,) + exc.NO_STATE:
451 return None
454def _class_to_mapper(
455 class_or_mapper: Union[Mapper[_T], Type[_T]],
456) -> Mapper[_T]:
457 # can't get mypy to see an overload for this
458 insp = inspection.inspect(class_or_mapper, False)
459 if insp is not None:
460 return insp.mapper # type: ignore[no-any-return]
461 else:
462 assert isinstance(class_or_mapper, type)
463 raise exc.UnmappedClassError(class_or_mapper)
466def _mapper_or_none(
467 entity: Union[Type[_T], _InternalEntityType[_T]],
468) -> Optional[Mapper[_T]]:
469 """Return the :class:`_orm.Mapper` for the given class or None if the
470 class is not mapped.
471 """
473 # can't get mypy to see an overload for this
474 insp = inspection.inspect(entity, False)
475 if insp is not None:
476 return insp.mapper # type: ignore[no-any-return]
477 else:
478 return None
481def _is_mapped_class(entity: Any) -> bool:
482 """Return True if the given object is a mapped class,
483 :class:`_orm.Mapper`, or :class:`.AliasedClass`.
484 """
486 insp = inspection.inspect(entity, False)
487 return (
488 insp is not None
489 and not insp.is_clause_element
490 and (insp.is_mapper or insp.is_aliased_class)
491 )
494def _is_aliased_class(entity: Any) -> bool:
495 insp = inspection.inspect(entity, False)
496 return insp is not None and getattr(insp, "is_aliased_class", False)
499@no_type_check
500def _entity_descriptor(entity: _EntityType[Any], key: str) -> Any:
501 """Return a class attribute given an entity and string name.
503 May return :class:`.InstrumentedAttribute` or user-defined
504 attribute.
506 """
507 insp = inspection.inspect(entity)
508 if insp.is_selectable:
509 description = entity
510 entity = insp.c
511 elif insp.is_aliased_class:
512 entity = insp.entity
513 description = entity
514 elif hasattr(insp, "mapper"):
515 description = entity = insp.mapper.class_
516 else:
517 description = entity
519 try:
520 return getattr(entity, key)
521 except AttributeError as err:
522 raise sa_exc.InvalidRequestError(
523 "Entity '%s' has no property '%s'" % (description, key)
524 ) from err
527if TYPE_CHECKING:
529 def _state_mapper(state: InstanceState[_O]) -> Mapper[_O]: ...
531else:
532 _state_mapper = util.dottedgetter("manager.mapper")
535def _inspect_mapped_class(
536 class_: Type[_O], configure: bool = False
537) -> Optional[Mapper[_O]]:
538 try:
539 class_manager = opt_manager_of_class(class_)
540 if class_manager is None or not class_manager.is_mapped:
541 return None
542 mapper = class_manager.mapper
543 except exc.NO_STATE:
544 return None
545 else:
546 if configure:
547 mapper._check_configure()
548 return mapper
551def _parse_mapper_argument(arg: Union[Mapper[_O], Type[_O]]) -> Mapper[_O]:
552 insp = inspection.inspect(arg, raiseerr=False)
553 if insp_is_mapper(insp):
554 return insp
556 raise sa_exc.ArgumentError(f"Mapper or mapped class expected, got {arg!r}")
559def class_mapper(class_: Type[_O], configure: bool = True) -> Mapper[_O]:
560 """Given a class, return the primary :class:`_orm.Mapper` associated
561 with the key.
563 Raises :exc:`.UnmappedClassError` if no mapping is configured
564 on the given class, or :exc:`.ArgumentError` if a non-class
565 object is passed.
567 Equivalent functionality is available via the :func:`_sa.inspect`
568 function as::
570 inspect(some_mapped_class)
572 Using the inspection system will raise
573 :class:`sqlalchemy.exc.NoInspectionAvailable` if the class is not mapped.
575 """
576 mapper = _inspect_mapped_class(class_, configure=configure)
577 if mapper is None:
578 if not isinstance(class_, type):
579 raise sa_exc.ArgumentError(
580 "Class object expected, got '%r'." % (class_,)
581 )
582 raise exc.UnmappedClassError(class_)
583 else:
584 return mapper
587class InspectionAttr:
588 """A base class applied to all ORM objects and attributes that are
589 related to things that can be returned by the :func:`_sa.inspect` function.
591 The attributes defined here allow the usage of simple boolean
592 checks to test basic facts about the object returned.
594 While the boolean checks here are basically the same as using
595 the Python isinstance() function, the flags here can be used without
596 the need to import all of these classes, and also such that
597 the SQLAlchemy class system can change while leaving the flags
598 here intact for forwards-compatibility.
600 """
602 __slots__: Tuple[str, ...] = ()
604 is_selectable = False
605 """Return True if this object is an instance of
606 :class:`_expression.Selectable`."""
608 is_aliased_class = False
609 """True if this object is an instance of :class:`.AliasedClass`."""
611 is_instance = False
612 """True if this object is an instance of :class:`.InstanceState`."""
614 is_mapper = False
615 """True if this object is an instance of :class:`_orm.Mapper`."""
617 is_bundle = False
618 """True if this object is an instance of :class:`.Bundle`."""
620 is_property = False
621 """True if this object is an instance of :class:`.MapperProperty`."""
623 is_attribute = False
624 """True if this object is a Python :term:`descriptor`.
626 This can refer to one of many types. Usually a
627 :class:`.QueryableAttribute` which handles attributes events on behalf
628 of a :class:`.MapperProperty`. But can also be an extension type
629 such as :class:`.AssociationProxy` or :class:`.hybrid_property`.
630 The :attr:`.InspectionAttr.extension_type` will refer to a constant
631 identifying the specific subtype.
633 .. seealso::
635 :attr:`_orm.Mapper.all_orm_descriptors`
637 """
639 _is_internal_proxy = False
640 """True if this object is an internal proxy object."""
642 is_clause_element = False
643 """True if this object is an instance of
644 :class:`_expression.ClauseElement`."""
646 extension_type: InspectionAttrExtensionType = NotExtension.NOT_EXTENSION
647 """The extension type, if any.
648 Defaults to :attr:`.interfaces.NotExtension.NOT_EXTENSION`
650 .. seealso::
652 :class:`.HybridExtensionType`
654 :class:`.AssociationProxyExtensionType`
656 """
659class InspectionAttrInfo(InspectionAttr):
660 """Adds the ``.info`` attribute to :class:`.InspectionAttr`.
662 The rationale for :class:`.InspectionAttr` vs. :class:`.InspectionAttrInfo`
663 is that the former is compatible as a mixin for classes that specify
664 ``__slots__``; this is essentially an implementation artifact.
666 """
668 __slots__ = ()
670 @util.ro_memoized_property
671 def info(self) -> _InfoType:
672 """Info dictionary associated with the object, allowing user-defined
673 data to be associated with this :class:`.InspectionAttr`.
675 The dictionary is generated when first accessed. Alternatively,
676 it can be specified as a constructor argument to the
677 :func:`.column_property`, :func:`_orm.relationship`, or
678 :func:`.composite`
679 functions.
681 .. seealso::
683 :attr:`.QueryableAttribute.info`
685 :attr:`.SchemaItem.info`
687 """
688 return {}
691class SQLORMOperations(SQLCoreOperations[_T_co], TypingOnly):
692 __slots__ = ()
694 if typing.TYPE_CHECKING:
696 def of_type(
697 self, class_: _EntityType[Any]
698 ) -> PropComparator[_T_co]: ...
700 def and_(
701 self, *criteria: _ColumnExpressionArgument[bool]
702 ) -> PropComparator[bool]: ...
704 def any( # noqa: A001
705 self,
706 criterion: Optional[_ColumnExpressionArgument[bool]] = None,
707 **kwargs: Any,
708 ) -> ColumnElement[bool]: ...
710 def has(
711 self,
712 criterion: Optional[_ColumnExpressionArgument[bool]] = None,
713 **kwargs: Any,
714 ) -> ColumnElement[bool]: ...
717class ORMDescriptor(Generic[_T_co], TypingOnly):
718 """Represent any Python descriptor that provides a SQL expression
719 construct at the class level."""
721 __slots__ = ()
723 if typing.TYPE_CHECKING:
725 @overload
726 def __get__(
727 self, instance: Any, owner: Literal[None]
728 ) -> ORMDescriptor[_T_co]: ...
730 @overload
731 def __get__(
732 self, instance: Literal[None], owner: Any
733 ) -> SQLCoreOperations[_T_co]: ...
735 @overload
736 def __get__(self, instance: object, owner: Any) -> _T_co: ...
738 def __get__(
739 self, instance: object, owner: Any
740 ) -> Union[ORMDescriptor[_T_co], SQLCoreOperations[_T_co], _T_co]: ...
743class _MappedAnnotationBase(Generic[_T_co], TypingOnly):
744 """common class for Mapped and similar ORM container classes.
746 these are classes that can appear on the left side of an ORM declarative
747 mapping, containing a mapped class or in some cases a collection
748 surrounding a mapped class.
750 """
752 __slots__ = ()
755class SQLORMExpression(
756 SQLORMOperations[_T_co], SQLColumnExpression[_T_co], TypingOnly
757):
758 """A type that may be used to indicate any ORM-level attribute or
759 object that acts in place of one, in the context of SQL expression
760 construction.
762 :class:`.SQLORMExpression` extends from the Core
763 :class:`.SQLColumnExpression` to add additional SQL methods that are ORM
764 specific, such as :meth:`.PropComparator.of_type`, and is part of the bases
765 for :class:`.InstrumentedAttribute`. It may be used in :pep:`484` typing to
766 indicate arguments or return values that should behave as ORM-level
767 attribute expressions.
769 .. versionadded:: 2.0.0b4
772 """
774 __slots__ = ()
777class Mapped(
778 SQLORMExpression[_T_co],
779 ORMDescriptor[_T_co],
780 _MappedAnnotationBase[_T_co],
781 roles.DDLConstraintColumnRole,
782):
783 """Represent an ORM mapped attribute on a mapped class.
785 This class represents the complete descriptor interface for any class
786 attribute that will have been :term:`instrumented` by the ORM
787 :class:`_orm.Mapper` class. Provides appropriate information to type
788 checkers such as pylance and mypy so that ORM-mapped attributes
789 are correctly typed.
791 The most prominent use of :class:`_orm.Mapped` is in
792 the :ref:`Declarative Mapping <orm_explicit_declarative_base>` form
793 of :class:`_orm.Mapper` configuration, where used explicitly it drives
794 the configuration of ORM attributes such as :func:`_orm.mapped_class`
795 and :func:`_orm.relationship`.
797 .. seealso::
799 :ref:`orm_explicit_declarative_base`
801 :ref:`orm_declarative_table`
803 .. tip::
805 The :class:`_orm.Mapped` class represents attributes that are handled
806 directly by the :class:`_orm.Mapper` class. It does not include other
807 Python descriptor classes that are provided as extensions, including
808 :ref:`hybrids_toplevel` and the :ref:`associationproxy_toplevel`.
809 While these systems still make use of ORM-specific superclasses
810 and structures, they are not :term:`instrumented` by the
811 :class:`_orm.Mapper` and instead provide their own functionality
812 when they are accessed on a class.
814 .. versionadded:: 1.4
817 """
819 __slots__ = ()
821 if typing.TYPE_CHECKING:
823 @overload
824 def __get__( # type: ignore[misc]
825 self: MappedColumn[_T_co], instance: TypedColumns, owner: Any
826 ) -> Column[_T_co]: ...
828 @overload
829 def __get__(
830 self, instance: None, owner: Any
831 ) -> InstrumentedAttribute[_T_co]: ...
833 @overload
834 def __get__(self, instance: object, owner: Any) -> _T_co: ...
836 def __get__(
837 self, instance: Optional[object], owner: Any
838 ) -> Union[InstrumentedAttribute[_T_co], Column[_T_co], _T_co]: ...
840 @classmethod
841 def _empty_constructor(cls, arg1: Any) -> Mapped[_T_co]: ...
843 def __set__(
844 self, instance: Any, value: Union[SQLCoreOperations[_T_co], _T_co]
845 ) -> None: ...
847 def __delete__(self, instance: Any) -> None: ...
850class _MappedAttribute(Generic[_T_co], TypingOnly):
851 """Mixin for attributes which should be replaced by mapper-assigned
852 attributes.
854 """
856 __slots__ = ()
859class _DeclarativeMapped(Mapped[_T_co], _MappedAttribute[_T_co]):
860 """Mixin for :class:`.MapperProperty` subclasses that allows them to
861 be compatible with ORM-annotated declarative mappings.
863 """
865 __slots__ = ()
867 # MappedSQLExpression, Relationship, Composite etc. dont actually do
868 # SQL expression behavior. yet there is code that compares them with
869 # __eq__(), __ne__(), etc. Since #8847 made Mapped even more full
870 # featured including ColumnOperators, we need to have those methods
871 # be no-ops for these objects, so return NotImplemented to fall back
872 # to normal comparison behavior.
873 def operate(self, op: OperatorType, *other: Any, **kwargs: Any) -> Any:
874 return NotImplemented
876 __sa_operate__ = operate
878 def reverse_operate(
879 self, op: OperatorType, other: Any, **kwargs: Any
880 ) -> Any:
881 return NotImplemented
884class DynamicMapped(_MappedAnnotationBase[_T_co]):
885 """Represent the ORM mapped attribute type for a "dynamic" relationship.
887 The :class:`_orm.DynamicMapped` type annotation may be used in an
888 :ref:`Annotated Declarative Table <orm_declarative_mapped_column>` mapping
889 to indicate that the ``lazy="dynamic"`` loader strategy should be used
890 for a particular :func:`_orm.relationship`.
892 .. legacy:: The "dynamic" lazy loader strategy is the legacy form of what
893 is now the "write_only" strategy described in the section
894 :ref:`write_only_relationship`.
896 E.g.::
898 class User(Base):
899 __tablename__ = "user"
900 id: Mapped[int] = mapped_column(primary_key=True)
901 addresses: DynamicMapped[Address] = relationship(
902 cascade="all,delete-orphan"
903 )
905 See the section :ref:`dynamic_relationship` for background.
907 .. versionadded:: 2.0
909 .. seealso::
911 :ref:`dynamic_relationship` - complete background
913 :class:`.WriteOnlyMapped` - fully 2.0 style version
915 """
917 __slots__ = ()
919 if TYPE_CHECKING:
921 @overload
922 def __get__(
923 self, instance: None, owner: Any
924 ) -> InstrumentedAttribute[_T_co]: ...
926 @overload
927 def __get__(
928 self, instance: object, owner: Any
929 ) -> AppenderQuery[_T_co]: ...
931 def __get__(
932 self, instance: Optional[object], owner: Any
933 ) -> Union[InstrumentedAttribute[_T_co], AppenderQuery[_T_co]]: ...
935 def __set__(
936 self, instance: Any, value: typing.Collection[_T_co]
937 ) -> None: ...
940class WriteOnlyMapped(_MappedAnnotationBase[_T_co]):
941 """Represent the ORM mapped attribute type for a "write only" relationship.
943 The :class:`_orm.WriteOnlyMapped` type annotation may be used in an
944 :ref:`Annotated Declarative Table <orm_declarative_mapped_column>` mapping
945 to indicate that the ``lazy="write_only"`` loader strategy should be used
946 for a particular :func:`_orm.relationship`.
948 E.g.::
950 class User(Base):
951 __tablename__ = "user"
952 id: Mapped[int] = mapped_column(primary_key=True)
953 addresses: WriteOnlyMapped[Address] = relationship(
954 cascade="all,delete-orphan"
955 )
957 See the section :ref:`write_only_relationship` for background.
959 .. versionadded:: 2.0
961 .. seealso::
963 :ref:`write_only_relationship` - complete background
965 :class:`.DynamicMapped` - includes legacy :class:`_orm.Query` support
967 """
969 __slots__ = ()
971 if TYPE_CHECKING:
973 @overload
974 def __get__(
975 self, instance: None, owner: Any
976 ) -> InstrumentedAttribute[_T_co]: ...
978 @overload
979 def __get__(
980 self, instance: object, owner: Any
981 ) -> WriteOnlyCollection[_T_co]: ...
983 def __get__(
984 self, instance: Optional[object], owner: Any
985 ) -> Union[
986 InstrumentedAttribute[_T_co], WriteOnlyCollection[_T_co]
987 ]: ...
989 def __set__(
990 self, instance: Any, value: typing.Collection[_T_co]
991 ) -> None: ...