1# orm/decl_api.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
7
8"""Public API functions and helpers for declarative."""
9
10from __future__ import annotations
11
12import itertools
13import re
14import typing
15from typing import Any
16from typing import Callable
17from typing import ClassVar
18from typing import Dict
19from typing import FrozenSet
20from typing import Generic
21from typing import Iterable
22from typing import Iterator
23from typing import Mapping
24from typing import Optional
25from typing import overload
26from typing import Set
27from typing import Tuple
28from typing import Type
29from typing import TYPE_CHECKING
30from typing import TypeVar
31from typing import Union
32import weakref
33
34from . import attributes
35from . import clsregistry
36from . import instrumentation
37from . import interfaces
38from . import mapperlib
39from ._orm_constructors import composite
40from ._orm_constructors import deferred
41from ._orm_constructors import mapped_column
42from ._orm_constructors import relationship
43from ._orm_constructors import synonym
44from .attributes import InstrumentedAttribute
45from .base import _inspect_mapped_class
46from .base import _is_mapped_class
47from .base import Mapped
48from .base import ORMDescriptor
49from .decl_base import _add_attribute
50from .decl_base import _as_declarative
51from .decl_base import _ClassScanMapperConfig
52from .decl_base import _declarative_constructor
53from .decl_base import _DeferredMapperConfig
54from .decl_base import _del_attribute
55from .decl_base import _mapper
56from .descriptor_props import Composite
57from .descriptor_props import Synonym
58from .descriptor_props import Synonym as _orm_synonym
59from .mapper import Mapper
60from .properties import MappedColumn
61from .relationships import RelationshipProperty
62from .state import InstanceState
63from .. import exc
64from .. import inspection
65from .. import util
66from ..sql import sqltypes
67from ..sql.base import _NoArg
68from ..sql.elements import SQLCoreOperations
69from ..sql.schema import MetaData
70from ..sql.selectable import FromClause
71from ..util import hybridmethod
72from ..util import hybridproperty
73from ..util import typing as compat_typing
74from ..util import warn_deprecated
75from ..util.typing import CallableReference
76from ..util.typing import de_optionalize_union_types
77from ..util.typing import flatten_newtype
78from ..util.typing import is_generic
79from ..util.typing import is_literal
80from ..util.typing import is_newtype
81from ..util.typing import is_pep593
82from ..util.typing import is_pep695
83from ..util.typing import Literal
84from ..util.typing import LITERAL_TYPES
85from ..util.typing import Self
86
87if TYPE_CHECKING:
88 from ._typing import _O
89 from ._typing import _RegistryType
90 from .decl_base import _DataclassArguments
91 from .instrumentation import ClassManager
92 from .interfaces import MapperProperty
93 from .state import InstanceState # noqa
94 from ..sql._typing import _TypeEngineArgument
95 from ..sql.type_api import _MatchedOnType
96
97_T = TypeVar("_T", bound=Any)
98_T_co = TypeVar("_T_co", bound=Any, covariant=True)
99
100_TT = TypeVar("_TT", bound=Any)
101
102# it's not clear how to have Annotated, Union objects etc. as keys here
103# from a typing perspective so just leave it open ended for now
104_TypeAnnotationMapType = Mapping[Any, "_TypeEngineArgument[Any]"]
105_MutableTypeAnnotationMapType = Dict[Any, "_TypeEngineArgument[Any]"]
106
107_DeclaredAttrDecorated = Callable[
108 ..., Union[Mapped[_T_co], ORMDescriptor[_T_co], SQLCoreOperations[_T_co]]
109]
110
111
112def has_inherited_table(cls: Type[_O]) -> bool:
113 """Given a class, return True if any of the classes it inherits from has a
114 mapped table, otherwise return False.
115
116 This is used in declarative mixins to build attributes that behave
117 differently for the base class vs. a subclass in an inheritance
118 hierarchy.
119
120 .. seealso::
121
122 :ref:`decl_mixin_inheritance`
123
124 """
125 for class_ in cls.__mro__[1:]:
126 if getattr(class_, "__table__", None) is not None:
127 return True
128 return False
129
130
131class _DynamicAttributesType(type):
132 def __setattr__(cls, key: str, value: Any) -> None:
133 if "__mapper__" in cls.__dict__:
134 _add_attribute(cls, key, value)
135 else:
136 type.__setattr__(cls, key, value)
137
138 def __delattr__(cls, key: str) -> None:
139 if "__mapper__" in cls.__dict__:
140 _del_attribute(cls, key)
141 else:
142 type.__delattr__(cls, key)
143
144
145class DeclarativeAttributeIntercept(
146 _DynamicAttributesType,
147 # Inspectable is used only by the mypy plugin
148 inspection.Inspectable[Mapper[Any]],
149):
150 """Metaclass that may be used in conjunction with the
151 :class:`_orm.DeclarativeBase` class to support addition of class
152 attributes dynamically.
153
154 """
155
156
157@compat_typing.dataclass_transform(
158 field_specifiers=(
159 MappedColumn,
160 RelationshipProperty,
161 Composite,
162 Synonym,
163 mapped_column,
164 relationship,
165 composite,
166 synonym,
167 deferred,
168 ),
169)
170class DCTransformDeclarative(DeclarativeAttributeIntercept):
171 """metaclass that includes @dataclass_transforms"""
172
173
174class DeclarativeMeta(DeclarativeAttributeIntercept):
175 metadata: MetaData
176 registry: RegistryType
177
178 def __init__(
179 cls, classname: Any, bases: Any, dict_: Any, **kw: Any
180 ) -> None:
181 # use cls.__dict__, which can be modified by an
182 # __init_subclass__() method (#7900)
183 dict_ = cls.__dict__
184
185 # early-consume registry from the initial declarative base,
186 # assign privately to not conflict with subclass attributes named
187 # "registry"
188 reg = getattr(cls, "_sa_registry", None)
189 if reg is None:
190 reg = dict_.get("registry", None)
191 if not isinstance(reg, registry):
192 raise exc.InvalidRequestError(
193 "Declarative base class has no 'registry' attribute, "
194 "or registry is not a sqlalchemy.orm.registry() object"
195 )
196 else:
197 cls._sa_registry = reg
198
199 if not cls.__dict__.get("__abstract__", False):
200 _as_declarative(reg, cls, dict_)
201 type.__init__(cls, classname, bases, dict_)
202
203
204def synonym_for(
205 name: str, map_column: bool = False
206) -> Callable[[Callable[..., Any]], Synonym[Any]]:
207 """Decorator that produces an :func:`_orm.synonym`
208 attribute in conjunction with a Python descriptor.
209
210 The function being decorated is passed to :func:`_orm.synonym` as the
211 :paramref:`.orm.synonym.descriptor` parameter::
212
213 class MyClass(Base):
214 __tablename__ = "my_table"
215
216 id = Column(Integer, primary_key=True)
217 _job_status = Column("job_status", String(50))
218
219 @synonym_for("job_status")
220 @property
221 def job_status(self):
222 return "Status: %s" % self._job_status
223
224 The :ref:`hybrid properties <mapper_hybrids>` feature of SQLAlchemy
225 is typically preferred instead of synonyms, which is a more legacy
226 feature.
227
228 .. seealso::
229
230 :ref:`synonyms` - Overview of synonyms
231
232 :func:`_orm.synonym` - the mapper-level function
233
234 :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
235 updated approach to augmenting attribute behavior more flexibly than
236 can be achieved with synonyms.
237
238 """
239
240 def decorate(fn: Callable[..., Any]) -> Synonym[Any]:
241 return _orm_synonym(name, map_column=map_column, descriptor=fn)
242
243 return decorate
244
245
246class _declared_attr_common:
247 def __init__(
248 self,
249 fn: Callable[..., Any],
250 cascading: bool = False,
251 quiet: bool = False,
252 ):
253 # support
254 # @declared_attr
255 # @classmethod
256 # def foo(cls) -> Mapped[thing]:
257 # ...
258 # which seems to help typing tools interpret the fn as a classmethod
259 # for situations where needed
260 if isinstance(fn, classmethod):
261 fn = fn.__func__
262
263 self.fget = fn
264 self._cascading = cascading
265 self._quiet = quiet
266 self.__doc__ = fn.__doc__
267
268 def _collect_return_annotation(self) -> Optional[Type[Any]]:
269 return util.get_annotations(self.fget).get("return")
270
271 def __get__(self, instance: Optional[object], owner: Any) -> Any:
272 # the declared_attr needs to make use of a cache that exists
273 # for the span of the declarative scan_attributes() phase.
274 # to achieve this we look at the class manager that's configured.
275
276 # note this method should not be called outside of the declarative
277 # setup phase
278
279 cls = owner
280 manager = attributes.opt_manager_of_class(cls)
281 if manager is None:
282 if not re.match(r"^__.+__$", self.fget.__name__):
283 # if there is no manager at all, then this class hasn't been
284 # run through declarative or mapper() at all, emit a warning.
285 util.warn(
286 "Unmanaged access of declarative attribute %s from "
287 "non-mapped class %s" % (self.fget.__name__, cls.__name__)
288 )
289 return self.fget(cls)
290 elif manager.is_mapped:
291 # the class is mapped, which means we're outside of the declarative
292 # scan setup, just run the function.
293 return self.fget(cls)
294
295 # here, we are inside of the declarative scan. use the registry
296 # that is tracking the values of these attributes.
297 declarative_scan = manager.declarative_scan()
298
299 # assert that we are in fact in the declarative scan
300 assert declarative_scan is not None
301
302 reg = declarative_scan.declared_attr_reg
303
304 if self in reg:
305 return reg[self]
306 else:
307 reg[self] = obj = self.fget(cls)
308 return obj
309
310
311class _declared_directive(_declared_attr_common, Generic[_T]):
312 # see mapping_api.rst for docstring
313
314 if typing.TYPE_CHECKING:
315
316 def __init__(
317 self,
318 fn: Callable[..., _T],
319 cascading: bool = False,
320 ): ...
321
322 def __get__(self, instance: Optional[object], owner: Any) -> _T: ...
323
324 def __set__(self, instance: Any, value: Any) -> None: ...
325
326 def __delete__(self, instance: Any) -> None: ...
327
328 def __call__(self, fn: Callable[..., _TT]) -> _declared_directive[_TT]:
329 # extensive fooling of mypy underway...
330 ...
331
332
333class declared_attr(interfaces._MappedAttribute[_T_co], _declared_attr_common):
334 """Mark a class-level method as representing the definition of
335 a mapped property or Declarative directive.
336
337 :class:`_orm.declared_attr` is typically applied as a decorator to a class
338 level method, turning the attribute into a scalar-like property that can be
339 invoked from the uninstantiated class. The Declarative mapping process
340 looks for these :class:`_orm.declared_attr` callables as it scans classes,
341 and assumes any attribute marked with :class:`_orm.declared_attr` will be a
342 callable that will produce an object specific to the Declarative mapping or
343 table configuration.
344
345 :class:`_orm.declared_attr` is usually applicable to
346 :ref:`mixins <orm_mixins_toplevel>`, to define relationships that are to be
347 applied to different implementors of the class. It may also be used to
348 define dynamically generated column expressions and other Declarative
349 attributes.
350
351 Example::
352
353 class ProvidesUserMixin:
354 "A mixin that adds a 'user' relationship to classes."
355
356 user_id: Mapped[int] = mapped_column(ForeignKey("user_table.id"))
357
358 @declared_attr
359 def user(cls) -> Mapped["User"]:
360 return relationship("User")
361
362 When used with Declarative directives such as ``__tablename__``, the
363 :meth:`_orm.declared_attr.directive` modifier may be used which indicates
364 to :pep:`484` typing tools that the given method is not dealing with
365 :class:`_orm.Mapped` attributes::
366
367 class CreateTableName:
368 @declared_attr.directive
369 def __tablename__(cls) -> str:
370 return cls.__name__.lower()
371
372 :class:`_orm.declared_attr` can also be applied directly to mapped
373 classes, to allow for attributes that dynamically configure themselves
374 on subclasses when using mapped inheritance schemes. Below
375 illustrates :class:`_orm.declared_attr` to create a dynamic scheme
376 for generating the :paramref:`_orm.Mapper.polymorphic_identity` parameter
377 for subclasses::
378
379 class Employee(Base):
380 __tablename__ = "employee"
381
382 id: Mapped[int] = mapped_column(primary_key=True)
383 type: Mapped[str] = mapped_column(String(50))
384
385 @declared_attr.directive
386 def __mapper_args__(cls) -> Dict[str, Any]:
387 if cls.__name__ == "Employee":
388 return {
389 "polymorphic_on": cls.type,
390 "polymorphic_identity": "Employee",
391 }
392 else:
393 return {"polymorphic_identity": cls.__name__}
394
395
396 class Engineer(Employee):
397 pass
398
399 :class:`_orm.declared_attr` supports decorating functions that are
400 explicitly decorated with ``@classmethod``. This is never necessary from a
401 runtime perspective, however may be needed in order to support :pep:`484`
402 typing tools that don't otherwise recognize the decorated function as
403 having class-level behaviors for the ``cls`` parameter::
404
405 class SomethingMixin:
406 x: Mapped[int]
407 y: Mapped[int]
408
409 @declared_attr
410 @classmethod
411 def x_plus_y(cls) -> Mapped[int]:
412 return column_property(cls.x + cls.y)
413
414 .. versionadded:: 2.0 - :class:`_orm.declared_attr` can accommodate a
415 function decorated with ``@classmethod`` to help with :pep:`484`
416 integration where needed.
417
418
419 .. seealso::
420
421 :ref:`orm_mixins_toplevel` - Declarative Mixin documentation with
422 background on use patterns for :class:`_orm.declared_attr`.
423
424 """ # noqa: E501
425
426 if typing.TYPE_CHECKING:
427
428 def __init__(
429 self,
430 fn: _DeclaredAttrDecorated[_T_co],
431 cascading: bool = False,
432 ): ...
433
434 def __set__(self, instance: Any, value: Any) -> None: ...
435
436 def __delete__(self, instance: Any) -> None: ...
437
438 # this is the Mapped[] API where at class descriptor get time we want
439 # the type checker to see InstrumentedAttribute[_T]. However the
440 # callable function prior to mapping in fact calls the given
441 # declarative function that does not return InstrumentedAttribute
442 @overload
443 def __get__(
444 self, instance: None, owner: Any
445 ) -> InstrumentedAttribute[_T_co]: ...
446
447 @overload
448 def __get__(self, instance: object, owner: Any) -> _T_co: ...
449
450 def __get__(
451 self, instance: Optional[object], owner: Any
452 ) -> Union[InstrumentedAttribute[_T_co], _T_co]: ...
453
454 @hybridmethod
455 def _stateful(cls, **kw: Any) -> _stateful_declared_attr[_T_co]:
456 return _stateful_declared_attr(**kw)
457
458 @hybridproperty
459 def directive(cls) -> _declared_directive[Any]:
460 # see mapping_api.rst for docstring
461 return _declared_directive # type: ignore
462
463 @hybridproperty
464 def cascading(cls) -> _stateful_declared_attr[_T_co]:
465 # see mapping_api.rst for docstring
466 return cls._stateful(cascading=True)
467
468
469class _stateful_declared_attr(declared_attr[_T_co]):
470 kw: Dict[str, Any]
471
472 def __init__(self, **kw: Any):
473 self.kw = kw
474
475 @hybridmethod
476 def _stateful(self, **kw: Any) -> _stateful_declared_attr[_T_co]:
477 new_kw = self.kw.copy()
478 new_kw.update(kw)
479 return _stateful_declared_attr(**new_kw)
480
481 def __call__(
482 self, fn: _DeclaredAttrDecorated[_T_co]
483 ) -> declared_attr[_T_co]:
484 return declared_attr(fn, **self.kw)
485
486
487def declarative_mixin(cls: Type[_T]) -> Type[_T]:
488 """Mark a class as providing the feature of "declarative mixin".
489
490 E.g.::
491
492 from sqlalchemy.orm import declared_attr
493 from sqlalchemy.orm import declarative_mixin
494
495
496 @declarative_mixin
497 class MyMixin:
498
499 @declared_attr
500 def __tablename__(cls):
501 return cls.__name__.lower()
502
503 __table_args__ = {"mysql_engine": "InnoDB"}
504 __mapper_args__ = {"always_refresh": True}
505
506 id = Column(Integer, primary_key=True)
507
508
509 class MyModel(MyMixin, Base):
510 name = Column(String(1000))
511
512 The :func:`_orm.declarative_mixin` decorator currently does not modify
513 the given class in any way; it's current purpose is strictly to assist
514 the :ref:`Mypy plugin <mypy_toplevel>` in being able to identify
515 SQLAlchemy declarative mixin classes when no other context is present.
516
517 .. versionadded:: 1.4.6
518
519 .. legacy:: This api is considered legacy and will be deprecated in the next
520 SQLAlchemy version.
521
522 .. seealso::
523
524 :ref:`orm_mixins_toplevel`
525
526 :ref:`mypy_declarative_mixins` - in the
527 :ref:`Mypy plugin documentation <mypy_toplevel>`
528
529 """ # noqa: E501
530
531 return cls
532
533
534def _setup_declarative_base(cls: Type[Any]) -> None:
535 if "metadata" in cls.__dict__:
536 metadata = cls.__dict__["metadata"]
537 else:
538 metadata = None
539
540 if "type_annotation_map" in cls.__dict__:
541 type_annotation_map = cls.__dict__["type_annotation_map"]
542 else:
543 type_annotation_map = None
544
545 reg = cls.__dict__.get("registry", None)
546 if reg is not None:
547 if not isinstance(reg, registry):
548 raise exc.InvalidRequestError(
549 "Declarative base class has a 'registry' attribute that is "
550 "not an instance of sqlalchemy.orm.registry()"
551 )
552 elif type_annotation_map is not None:
553 raise exc.InvalidRequestError(
554 "Declarative base class has both a 'registry' attribute and a "
555 "type_annotation_map entry. Per-base type_annotation_maps "
556 "are not supported. Please apply the type_annotation_map "
557 "to this registry directly."
558 )
559
560 else:
561 reg = registry(
562 metadata=metadata, type_annotation_map=type_annotation_map
563 )
564 cls.registry = reg
565
566 cls._sa_registry = reg
567
568 if "metadata" not in cls.__dict__:
569 cls.metadata = cls.registry.metadata
570
571 if getattr(cls, "__init__", object.__init__) is object.__init__:
572 cls.__init__ = cls.registry.constructor
573
574
575class MappedAsDataclass(metaclass=DCTransformDeclarative):
576 """Mixin class to indicate when mapping this class, also convert it to be
577 a dataclass.
578
579 .. seealso::
580
581 :ref:`orm_declarative_native_dataclasses` - complete background
582 on SQLAlchemy native dataclass mapping
583
584 .. versionadded:: 2.0
585
586 """
587
588 def __init_subclass__(
589 cls,
590 init: Union[_NoArg, bool] = _NoArg.NO_ARG,
591 repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
592 eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
593 order: Union[_NoArg, bool] = _NoArg.NO_ARG,
594 unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
595 match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
596 kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
597 dataclass_callable: Union[
598 _NoArg, Callable[..., Type[Any]]
599 ] = _NoArg.NO_ARG,
600 **kw: Any,
601 ) -> None:
602 apply_dc_transforms: _DataclassArguments = {
603 "init": init,
604 "repr": repr,
605 "eq": eq,
606 "order": order,
607 "unsafe_hash": unsafe_hash,
608 "match_args": match_args,
609 "kw_only": kw_only,
610 "dataclass_callable": dataclass_callable,
611 }
612
613 current_transforms: _DataclassArguments
614
615 if hasattr(cls, "_sa_apply_dc_transforms"):
616 current = cls._sa_apply_dc_transforms
617
618 _ClassScanMapperConfig._assert_dc_arguments(current)
619
620 cls._sa_apply_dc_transforms = current_transforms = { # type: ignore # noqa: E501
621 k: current.get(k, _NoArg.NO_ARG) if v is _NoArg.NO_ARG else v
622 for k, v in apply_dc_transforms.items()
623 }
624 else:
625 cls._sa_apply_dc_transforms = current_transforms = (
626 apply_dc_transforms
627 )
628
629 super().__init_subclass__(**kw)
630
631 if not _is_mapped_class(cls):
632 new_anno = (
633 _ClassScanMapperConfig._update_annotations_for_non_mapped_class
634 )(cls)
635 _ClassScanMapperConfig._apply_dataclasses_to_any_class(
636 current_transforms, cls, new_anno
637 )
638
639
640class DeclarativeBase(
641 # Inspectable is used only by the mypy plugin
642 inspection.Inspectable[InstanceState[Any]],
643 metaclass=DeclarativeAttributeIntercept,
644):
645 """Base class used for declarative class definitions.
646
647 The :class:`_orm.DeclarativeBase` allows for the creation of new
648 declarative bases in such a way that is compatible with type checkers::
649
650
651 from sqlalchemy.orm import DeclarativeBase
652
653
654 class Base(DeclarativeBase):
655 pass
656
657 The above ``Base`` class is now usable as the base for new declarative
658 mappings. The superclass makes use of the ``__init_subclass__()``
659 method to set up new classes and metaclasses aren't used.
660
661 When first used, the :class:`_orm.DeclarativeBase` class instantiates a new
662 :class:`_orm.registry` to be used with the base, assuming one was not
663 provided explicitly. The :class:`_orm.DeclarativeBase` class supports
664 class-level attributes which act as parameters for the construction of this
665 registry; such as to indicate a specific :class:`_schema.MetaData`
666 collection as well as a specific value for
667 :paramref:`_orm.registry.type_annotation_map`::
668
669 from typing_extensions import Annotated
670
671 from sqlalchemy import BigInteger
672 from sqlalchemy import MetaData
673 from sqlalchemy import String
674 from sqlalchemy.orm import DeclarativeBase
675
676 bigint = Annotated[int, "bigint"]
677 my_metadata = MetaData()
678
679
680 class Base(DeclarativeBase):
681 metadata = my_metadata
682 type_annotation_map = {
683 str: String().with_variant(String(255), "mysql", "mariadb"),
684 bigint: BigInteger(),
685 }
686
687 Class-level attributes which may be specified include:
688
689 :param metadata: optional :class:`_schema.MetaData` collection.
690 If a :class:`_orm.registry` is constructed automatically, this
691 :class:`_schema.MetaData` collection will be used to construct it.
692 Otherwise, the local :class:`_schema.MetaData` collection will supersede
693 that used by an existing :class:`_orm.registry` passed using the
694 :paramref:`_orm.DeclarativeBase.registry` parameter.
695 :param type_annotation_map: optional type annotation map that will be
696 passed to the :class:`_orm.registry` as
697 :paramref:`_orm.registry.type_annotation_map`.
698 :param registry: supply a pre-existing :class:`_orm.registry` directly.
699
700 .. versionadded:: 2.0 Added :class:`.DeclarativeBase`, so that declarative
701 base classes may be constructed in such a way that is also recognized
702 by :pep:`484` type checkers. As a result, :class:`.DeclarativeBase`
703 and other subclassing-oriented APIs should be seen as
704 superseding previous "class returned by a function" APIs, namely
705 :func:`_orm.declarative_base` and :meth:`_orm.registry.generate_base`,
706 where the base class returned cannot be recognized by type checkers
707 without using plugins.
708
709 **__init__ behavior**
710
711 In a plain Python class, the base-most ``__init__()`` method in the class
712 hierarchy is ``object.__init__()``, which accepts no arguments. However,
713 when the :class:`_orm.DeclarativeBase` subclass is first declared, the
714 class is given an ``__init__()`` method that links to the
715 :paramref:`_orm.registry.constructor` constructor function, if no
716 ``__init__()`` method is already present; this is the usual declarative
717 constructor that will assign keyword arguments as attributes on the
718 instance, assuming those attributes are established at the class level
719 (i.e. are mapped, or are linked to a descriptor). This constructor is
720 **never accessed by a mapped class without being called explicitly via
721 super()**, as mapped classes are themselves given an ``__init__()`` method
722 directly which calls :paramref:`_orm.registry.constructor`, so in the
723 default case works independently of what the base-most ``__init__()``
724 method does.
725
726 .. versionchanged:: 2.0.1 :class:`_orm.DeclarativeBase` has a default
727 constructor that links to :paramref:`_orm.registry.constructor` by
728 default, so that calls to ``super().__init__()`` can access this
729 constructor. Previously, due to an implementation mistake, this default
730 constructor was missing, and calling ``super().__init__()`` would invoke
731 ``object.__init__()``.
732
733 The :class:`_orm.DeclarativeBase` subclass may also declare an explicit
734 ``__init__()`` method which will replace the use of the
735 :paramref:`_orm.registry.constructor` function at this level::
736
737 class Base(DeclarativeBase):
738 def __init__(self, id=None):
739 self.id = id
740
741 Mapped classes still will not invoke this constructor implicitly; it
742 remains only accessible by calling ``super().__init__()``::
743
744 class MyClass(Base):
745 def __init__(self, id=None, name=None):
746 self.name = name
747 super().__init__(id=id)
748
749 Note that this is a different behavior from what functions like the legacy
750 :func:`_orm.declarative_base` would do; the base created by those functions
751 would always install :paramref:`_orm.registry.constructor` for
752 ``__init__()``.
753
754
755 """
756
757 if typing.TYPE_CHECKING:
758
759 def _sa_inspect_type(self) -> Mapper[Self]: ...
760
761 def _sa_inspect_instance(self) -> InstanceState[Self]: ...
762
763 _sa_registry: ClassVar[_RegistryType]
764
765 registry: ClassVar[_RegistryType]
766 """Refers to the :class:`_orm.registry` in use where new
767 :class:`_orm.Mapper` objects will be associated."""
768
769 metadata: ClassVar[MetaData]
770 """Refers to the :class:`_schema.MetaData` collection that will be used
771 for new :class:`_schema.Table` objects.
772
773 .. seealso::
774
775 :ref:`orm_declarative_metadata`
776
777 """
778
779 __name__: ClassVar[str]
780
781 # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not
782 # like it, and breaks the declared_attr_one test. Pyright/pylance is
783 # ok with it.
784 __mapper__: ClassVar[Mapper[Any]]
785 """The :class:`_orm.Mapper` object to which a particular class is
786 mapped.
787
788 May also be acquired using :func:`_sa.inspect`, e.g.
789 ``inspect(klass)``.
790
791 """
792
793 __table__: ClassVar[FromClause]
794 """The :class:`_sql.FromClause` to which a particular subclass is
795 mapped.
796
797 This is usually an instance of :class:`_schema.Table` but may also
798 refer to other kinds of :class:`_sql.FromClause` such as
799 :class:`_sql.Subquery`, depending on how the class is mapped.
800
801 .. seealso::
802
803 :ref:`orm_declarative_metadata`
804
805 """
806
807 # pyright/pylance do not consider a classmethod a ClassVar so use Any
808 # https://github.com/microsoft/pylance-release/issues/3484
809 __tablename__: Any
810 """String name to assign to the generated
811 :class:`_schema.Table` object, if not specified directly via
812 :attr:`_orm.DeclarativeBase.__table__`.
813
814 .. seealso::
815
816 :ref:`orm_declarative_table`
817
818 """
819
820 __mapper_args__: Any
821 """Dictionary of arguments which will be passed to the
822 :class:`_orm.Mapper` constructor.
823
824 .. seealso::
825
826 :ref:`orm_declarative_mapper_options`
827
828 """
829
830 __table_args__: Any
831 """A dictionary or tuple of arguments that will be passed to the
832 :class:`_schema.Table` constructor. See
833 :ref:`orm_declarative_table_configuration`
834 for background on the specific structure of this collection.
835
836 .. seealso::
837
838 :ref:`orm_declarative_table_configuration`
839
840 """
841
842 def __init__(self, **kw: Any): ...
843
844 def __init_subclass__(cls, **kw: Any) -> None:
845 if DeclarativeBase in cls.__bases__:
846 _check_not_declarative(cls, DeclarativeBase)
847 _setup_declarative_base(cls)
848 else:
849 _as_declarative(cls._sa_registry, cls, cls.__dict__)
850 super().__init_subclass__(**kw)
851
852
853def _check_not_declarative(cls: Type[Any], base: Type[Any]) -> None:
854 cls_dict = cls.__dict__
855 if (
856 "__table__" in cls_dict
857 and not (
858 callable(cls_dict["__table__"])
859 or hasattr(cls_dict["__table__"], "__get__")
860 )
861 ) or isinstance(cls_dict.get("__tablename__", None), str):
862 raise exc.InvalidRequestError(
863 f"Cannot use {base.__name__!r} directly as a declarative base "
864 "class. Create a Base by creating a subclass of it."
865 )
866
867
868class DeclarativeBaseNoMeta(
869 # Inspectable is used only by the mypy plugin
870 inspection.Inspectable[InstanceState[Any]]
871):
872 """Same as :class:`_orm.DeclarativeBase`, but does not use a metaclass
873 to intercept new attributes.
874
875 The :class:`_orm.DeclarativeBaseNoMeta` base may be used when use of
876 custom metaclasses is desirable.
877
878 .. versionadded:: 2.0
879
880
881 """
882
883 _sa_registry: ClassVar[_RegistryType]
884
885 registry: ClassVar[_RegistryType]
886 """Refers to the :class:`_orm.registry` in use where new
887 :class:`_orm.Mapper` objects will be associated."""
888
889 metadata: ClassVar[MetaData]
890 """Refers to the :class:`_schema.MetaData` collection that will be used
891 for new :class:`_schema.Table` objects.
892
893 .. seealso::
894
895 :ref:`orm_declarative_metadata`
896
897 """
898
899 # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not
900 # like it, and breaks the declared_attr_one test. Pyright/pylance is
901 # ok with it.
902 __mapper__: ClassVar[Mapper[Any]]
903 """The :class:`_orm.Mapper` object to which a particular class is
904 mapped.
905
906 May also be acquired using :func:`_sa.inspect`, e.g.
907 ``inspect(klass)``.
908
909 """
910
911 __table__: Optional[FromClause]
912 """The :class:`_sql.FromClause` to which a particular subclass is
913 mapped.
914
915 This is usually an instance of :class:`_schema.Table` but may also
916 refer to other kinds of :class:`_sql.FromClause` such as
917 :class:`_sql.Subquery`, depending on how the class is mapped.
918
919 .. seealso::
920
921 :ref:`orm_declarative_metadata`
922
923 """
924
925 if typing.TYPE_CHECKING:
926
927 def _sa_inspect_type(self) -> Mapper[Self]: ...
928
929 def _sa_inspect_instance(self) -> InstanceState[Self]: ...
930
931 __tablename__: Any
932 """String name to assign to the generated
933 :class:`_schema.Table` object, if not specified directly via
934 :attr:`_orm.DeclarativeBase.__table__`.
935
936 .. seealso::
937
938 :ref:`orm_declarative_table`
939
940 """
941
942 __mapper_args__: Any
943 """Dictionary of arguments which will be passed to the
944 :class:`_orm.Mapper` constructor.
945
946 .. seealso::
947
948 :ref:`orm_declarative_mapper_options`
949
950 """
951
952 __table_args__: Any
953 """A dictionary or tuple of arguments that will be passed to the
954 :class:`_schema.Table` constructor. See
955 :ref:`orm_declarative_table_configuration`
956 for background on the specific structure of this collection.
957
958 .. seealso::
959
960 :ref:`orm_declarative_table_configuration`
961
962 """
963
964 def __init__(self, **kw: Any): ...
965
966 def __init_subclass__(cls, **kw: Any) -> None:
967 if DeclarativeBaseNoMeta in cls.__bases__:
968 _check_not_declarative(cls, DeclarativeBaseNoMeta)
969 _setup_declarative_base(cls)
970 else:
971 _as_declarative(cls._sa_registry, cls, cls.__dict__)
972 super().__init_subclass__(**kw)
973
974
975def add_mapped_attribute(
976 target: Type[_O], key: str, attr: MapperProperty[Any]
977) -> None:
978 """Add a new mapped attribute to an ORM mapped class.
979
980 E.g.::
981
982 add_mapped_attribute(User, "addresses", relationship(Address))
983
984 This may be used for ORM mappings that aren't using a declarative
985 metaclass that intercepts attribute set operations.
986
987 .. versionadded:: 2.0
988
989
990 """
991 _add_attribute(target, key, attr)
992
993
994def declarative_base(
995 *,
996 metadata: Optional[MetaData] = None,
997 mapper: Optional[Callable[..., Mapper[Any]]] = None,
998 cls: Type[Any] = object,
999 name: str = "Base",
1000 class_registry: Optional[clsregistry._ClsRegistryType] = None,
1001 type_annotation_map: Optional[_TypeAnnotationMapType] = None,
1002 constructor: Callable[..., None] = _declarative_constructor,
1003 metaclass: Type[Any] = DeclarativeMeta,
1004) -> Any:
1005 r"""Construct a base class for declarative class definitions.
1006
1007 The new base class will be given a metaclass that produces
1008 appropriate :class:`~sqlalchemy.schema.Table` objects and makes
1009 the appropriate :class:`_orm.Mapper` calls based on the
1010 information provided declaratively in the class and any subclasses
1011 of the class.
1012
1013 .. versionchanged:: 2.0 Note that the :func:`_orm.declarative_base`
1014 function is superseded by the new :class:`_orm.DeclarativeBase` class,
1015 which generates a new "base" class using subclassing, rather than
1016 return value of a function. This allows an approach that is compatible
1017 with :pep:`484` typing tools.
1018
1019 The :func:`_orm.declarative_base` function is a shorthand version
1020 of using the :meth:`_orm.registry.generate_base`
1021 method. That is, the following::
1022
1023 from sqlalchemy.orm import declarative_base
1024
1025 Base = declarative_base()
1026
1027 Is equivalent to::
1028
1029 from sqlalchemy.orm import registry
1030
1031 mapper_registry = registry()
1032 Base = mapper_registry.generate_base()
1033
1034 See the docstring for :class:`_orm.registry`
1035 and :meth:`_orm.registry.generate_base`
1036 for more details.
1037
1038 .. versionchanged:: 1.4 The :func:`_orm.declarative_base`
1039 function is now a specialization of the more generic
1040 :class:`_orm.registry` class. The function also moves to the
1041 ``sqlalchemy.orm`` package from the ``declarative.ext`` package.
1042
1043
1044 :param metadata:
1045 An optional :class:`~sqlalchemy.schema.MetaData` instance. All
1046 :class:`~sqlalchemy.schema.Table` objects implicitly declared by
1047 subclasses of the base will share this MetaData. A MetaData instance
1048 will be created if none is provided. The
1049 :class:`~sqlalchemy.schema.MetaData` instance will be available via the
1050 ``metadata`` attribute of the generated declarative base class.
1051
1052 :param mapper:
1053 An optional callable, defaults to :class:`_orm.Mapper`. Will
1054 be used to map subclasses to their Tables.
1055
1056 :param cls:
1057 Defaults to :class:`object`. A type to use as the base for the generated
1058 declarative base class. May be a class or tuple of classes.
1059
1060 :param name:
1061 Defaults to ``Base``. The display name for the generated
1062 class. Customizing this is not required, but can improve clarity in
1063 tracebacks and debugging.
1064
1065 :param constructor:
1066 Specify the implementation for the ``__init__`` function on a mapped
1067 class that has no ``__init__`` of its own. Defaults to an
1068 implementation that assigns \**kwargs for declared
1069 fields and relationships to an instance. If ``None`` is supplied,
1070 no __init__ will be provided and construction will fall back to
1071 cls.__init__ by way of the normal Python semantics.
1072
1073 :param class_registry: optional dictionary that will serve as the
1074 registry of class names-> mapped classes when string names
1075 are used to identify classes inside of :func:`_orm.relationship`
1076 and others. Allows two or more declarative base classes
1077 to share the same registry of class names for simplified
1078 inter-base relationships.
1079
1080 :param type_annotation_map: optional dictionary of Python types to
1081 SQLAlchemy :class:`_types.TypeEngine` classes or instances. This
1082 is used exclusively by the :class:`_orm.MappedColumn` construct
1083 to produce column types based on annotations within the
1084 :class:`_orm.Mapped` type.
1085
1086
1087 .. versionadded:: 2.0
1088
1089 .. seealso::
1090
1091 :ref:`orm_declarative_mapped_column_type_map`
1092
1093 :param metaclass:
1094 Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__
1095 compatible callable to use as the meta type of the generated
1096 declarative base class.
1097
1098 .. seealso::
1099
1100 :class:`_orm.registry`
1101
1102 """
1103
1104 return registry(
1105 metadata=metadata,
1106 class_registry=class_registry,
1107 constructor=constructor,
1108 type_annotation_map=type_annotation_map,
1109 ).generate_base(
1110 mapper=mapper,
1111 cls=cls,
1112 name=name,
1113 metaclass=metaclass,
1114 )
1115
1116
1117class registry:
1118 """Generalized registry for mapping classes.
1119
1120 The :class:`_orm.registry` serves as the basis for maintaining a collection
1121 of mappings, and provides configurational hooks used to map classes.
1122
1123 The three general kinds of mappings supported are Declarative Base,
1124 Declarative Decorator, and Imperative Mapping. All of these mapping
1125 styles may be used interchangeably:
1126
1127 * :meth:`_orm.registry.generate_base` returns a new declarative base
1128 class, and is the underlying implementation of the
1129 :func:`_orm.declarative_base` function.
1130
1131 * :meth:`_orm.registry.mapped` provides a class decorator that will
1132 apply declarative mapping to a class without the use of a declarative
1133 base class.
1134
1135 * :meth:`_orm.registry.map_imperatively` will produce a
1136 :class:`_orm.Mapper` for a class without scanning the class for
1137 declarative class attributes. This method suits the use case historically
1138 provided by the ``sqlalchemy.orm.mapper()`` classical mapping function,
1139 which is removed as of SQLAlchemy 2.0.
1140
1141 .. versionadded:: 1.4
1142
1143 .. seealso::
1144
1145 :ref:`orm_mapping_classes_toplevel` - overview of class mapping
1146 styles.
1147
1148 """
1149
1150 _class_registry: clsregistry._ClsRegistryType
1151 _managers: weakref.WeakKeyDictionary[ClassManager[Any], Literal[True]]
1152 _non_primary_mappers: weakref.WeakKeyDictionary[Mapper[Any], Literal[True]]
1153 metadata: MetaData
1154 constructor: CallableReference[Callable[..., None]]
1155 type_annotation_map: _MutableTypeAnnotationMapType
1156 _dependents: Set[_RegistryType]
1157 _dependencies: Set[_RegistryType]
1158 _new_mappers: bool
1159
1160 def __init__(
1161 self,
1162 *,
1163 metadata: Optional[MetaData] = None,
1164 class_registry: Optional[clsregistry._ClsRegistryType] = None,
1165 type_annotation_map: Optional[_TypeAnnotationMapType] = None,
1166 constructor: Callable[..., None] = _declarative_constructor,
1167 ):
1168 r"""Construct a new :class:`_orm.registry`
1169
1170 :param metadata:
1171 An optional :class:`_schema.MetaData` instance. All
1172 :class:`_schema.Table` objects generated using declarative
1173 table mapping will make use of this :class:`_schema.MetaData`
1174 collection. If this argument is left at its default of ``None``,
1175 a blank :class:`_schema.MetaData` collection is created.
1176
1177 :param constructor:
1178 Specify the implementation for the ``__init__`` function on a mapped
1179 class that has no ``__init__`` of its own. Defaults to an
1180 implementation that assigns \**kwargs for declared
1181 fields and relationships to an instance. If ``None`` is supplied,
1182 no __init__ will be provided and construction will fall back to
1183 cls.__init__ by way of the normal Python semantics.
1184
1185 :param class_registry: optional dictionary that will serve as the
1186 registry of class names-> mapped classes when string names
1187 are used to identify classes inside of :func:`_orm.relationship`
1188 and others. Allows two or more declarative base classes
1189 to share the same registry of class names for simplified
1190 inter-base relationships.
1191
1192 :param type_annotation_map: optional dictionary of Python types to
1193 SQLAlchemy :class:`_types.TypeEngine` classes or instances.
1194 The provided dict will update the default type mapping. This
1195 is used exclusively by the :class:`_orm.MappedColumn` construct
1196 to produce column types based on annotations within the
1197 :class:`_orm.Mapped` type.
1198
1199 .. versionadded:: 2.0
1200
1201 .. seealso::
1202
1203 :ref:`orm_declarative_mapped_column_type_map`
1204
1205
1206 """
1207 lcl_metadata = metadata or MetaData()
1208
1209 if class_registry is None:
1210 class_registry = weakref.WeakValueDictionary()
1211
1212 self._class_registry = class_registry
1213 self._managers = weakref.WeakKeyDictionary()
1214 self._non_primary_mappers = weakref.WeakKeyDictionary()
1215 self.metadata = lcl_metadata
1216 self.constructor = constructor
1217 self.type_annotation_map = {}
1218 if type_annotation_map is not None:
1219 self.update_type_annotation_map(type_annotation_map)
1220 self._dependents = set()
1221 self._dependencies = set()
1222
1223 self._new_mappers = False
1224
1225 with mapperlib._CONFIGURE_MUTEX:
1226 mapperlib._mapper_registries[self] = True
1227
1228 def update_type_annotation_map(
1229 self,
1230 type_annotation_map: _TypeAnnotationMapType,
1231 ) -> None:
1232 """update the :paramref:`_orm.registry.type_annotation_map` with new
1233 values."""
1234
1235 self.type_annotation_map.update(
1236 {
1237 de_optionalize_union_types(typ): sqltype
1238 for typ, sqltype in type_annotation_map.items()
1239 }
1240 )
1241
1242 def _resolve_type(
1243 self, python_type: _MatchedOnType, _do_fallbacks: bool = False
1244 ) -> Optional[sqltypes.TypeEngine[Any]]:
1245 python_type_type: Type[Any]
1246 search: Iterable[Tuple[_MatchedOnType, Type[Any]]]
1247
1248 if is_generic(python_type):
1249 if is_literal(python_type):
1250 python_type_type = python_type # type: ignore[assignment]
1251
1252 search = (
1253 (python_type, python_type_type),
1254 *((lt, python_type_type) for lt in LITERAL_TYPES),
1255 )
1256 else:
1257 python_type_type = python_type.__origin__
1258 search = ((python_type, python_type_type),)
1259 elif isinstance(python_type, type):
1260 python_type_type = python_type
1261 search = ((pt, pt) for pt in python_type_type.__mro__)
1262 else:
1263 python_type_type = python_type # type: ignore[assignment]
1264 search = ((python_type, python_type_type),)
1265
1266 for pt, flattened in search:
1267 # we search through full __mro__ for types. however...
1268 sql_type = self.type_annotation_map.get(pt)
1269 if sql_type is None:
1270 sql_type = sqltypes._type_map_get(pt) # type: ignore # noqa: E501
1271
1272 if sql_type is not None:
1273 sql_type_inst = sqltypes.to_instance(sql_type)
1274
1275 # ... this additional step will reject most
1276 # type -> supertype matches, such as if we had
1277 # a MyInt(int) subclass. note also we pass NewType()
1278 # here directly; these always have to be in the
1279 # type_annotation_map to be useful
1280 resolved_sql_type = sql_type_inst._resolve_for_python_type(
1281 python_type_type,
1282 pt,
1283 flattened,
1284 )
1285 if resolved_sql_type is not None:
1286 return resolved_sql_type
1287
1288 # 2.0 fallbacks
1289 if _do_fallbacks:
1290 python_type_to_check: Any = None
1291 kind = None
1292 if is_pep695(python_type):
1293 # NOTE: assume there aren't type alias types of new types.
1294 python_type_to_check = python_type
1295 while is_pep695(python_type_to_check) and not is_pep593(
1296 python_type_to_check
1297 ):
1298 python_type_to_check = python_type_to_check.__value__
1299 python_type_to_check = de_optionalize_union_types(
1300 python_type_to_check
1301 )
1302 kind = "pep-695 type"
1303 if is_newtype(python_type):
1304 python_type_to_check = flatten_newtype(python_type)
1305 kind = "NewType"
1306
1307 if python_type_to_check is not None:
1308 res_after_fallback = self._resolve_type(
1309 python_type_to_check, False
1310 )
1311 if res_after_fallback is not None:
1312 assert kind is not None
1313 if kind == "pep-695 type":
1314 warn_deprecated(
1315 f"Matching to {kind} '{python_type}' in "
1316 "a recursive "
1317 "fashion without the recursed type being present "
1318 "in the type_annotation_map is deprecated; add "
1319 "this type or its recursed value to "
1320 "the type_annotation_map to allow it to match "
1321 "explicitly.",
1322 "2.0",
1323 )
1324 else:
1325 warn_deprecated(
1326 f"Matching the provided {kind} '{python_type}' on "
1327 "its resolved value without matching it in the "
1328 "type_annotation_map is deprecated; add this "
1329 "type to "
1330 "the type_annotation_map to allow it to match "
1331 "explicitly.",
1332 "2.0",
1333 )
1334 return res_after_fallback
1335
1336 return None
1337
1338 @property
1339 def mappers(self) -> FrozenSet[Mapper[Any]]:
1340 """read only collection of all :class:`_orm.Mapper` objects."""
1341
1342 return frozenset(manager.mapper for manager in self._managers).union(
1343 self._non_primary_mappers
1344 )
1345
1346 def _set_depends_on(self, registry: RegistryType) -> None:
1347 if registry is self:
1348 return
1349 registry._dependents.add(self)
1350 self._dependencies.add(registry)
1351
1352 def _flag_new_mapper(self, mapper: Mapper[Any]) -> None:
1353 mapper._ready_for_configure = True
1354 if self._new_mappers:
1355 return
1356
1357 for reg in self._recurse_with_dependents({self}):
1358 reg._new_mappers = True
1359
1360 @classmethod
1361 def _recurse_with_dependents(
1362 cls, registries: Set[RegistryType]
1363 ) -> Iterator[RegistryType]:
1364 todo = registries
1365 done = set()
1366 while todo:
1367 reg = todo.pop()
1368 done.add(reg)
1369
1370 # if yielding would remove dependents, make sure we have
1371 # them before
1372 todo.update(reg._dependents.difference(done))
1373 yield reg
1374
1375 # if yielding would add dependents, make sure we have them
1376 # after
1377 todo.update(reg._dependents.difference(done))
1378
1379 @classmethod
1380 def _recurse_with_dependencies(
1381 cls, registries: Set[RegistryType]
1382 ) -> Iterator[RegistryType]:
1383 todo = registries
1384 done = set()
1385 while todo:
1386 reg = todo.pop()
1387 done.add(reg)
1388
1389 # if yielding would remove dependencies, make sure we have
1390 # them before
1391 todo.update(reg._dependencies.difference(done))
1392
1393 yield reg
1394
1395 # if yielding would remove dependencies, make sure we have
1396 # them before
1397 todo.update(reg._dependencies.difference(done))
1398
1399 def _mappers_to_configure(self) -> Iterator[Mapper[Any]]:
1400 return itertools.chain(
1401 (
1402 manager.mapper
1403 for manager in list(self._managers)
1404 if manager.is_mapped
1405 and not manager.mapper.configured
1406 and manager.mapper._ready_for_configure
1407 ),
1408 (
1409 npm
1410 for npm in list(self._non_primary_mappers)
1411 if not npm.configured and npm._ready_for_configure
1412 ),
1413 )
1414
1415 def _add_non_primary_mapper(self, np_mapper: Mapper[Any]) -> None:
1416 self._non_primary_mappers[np_mapper] = True
1417
1418 def _dispose_cls(self, cls: Type[_O]) -> None:
1419 clsregistry.remove_class(cls.__name__, cls, self._class_registry)
1420
1421 def _add_manager(self, manager: ClassManager[Any]) -> None:
1422 self._managers[manager] = True
1423 if manager.is_mapped:
1424 raise exc.ArgumentError(
1425 "Class '%s' already has a primary mapper defined. "
1426 % manager.class_
1427 )
1428 assert manager.registry is None
1429 manager.registry = self
1430
1431 def configure(self, cascade: bool = False) -> None:
1432 """Configure all as-yet unconfigured mappers in this
1433 :class:`_orm.registry`.
1434
1435 The configure step is used to reconcile and initialize the
1436 :func:`_orm.relationship` linkages between mapped classes, as well as
1437 to invoke configuration events such as the
1438 :meth:`_orm.MapperEvents.before_configured` and
1439 :meth:`_orm.MapperEvents.after_configured`, which may be used by ORM
1440 extensions or user-defined extension hooks.
1441
1442 If one or more mappers in this registry contain
1443 :func:`_orm.relationship` constructs that refer to mapped classes in
1444 other registries, this registry is said to be *dependent* on those
1445 registries. In order to configure those dependent registries
1446 automatically, the :paramref:`_orm.registry.configure.cascade` flag
1447 should be set to ``True``. Otherwise, if they are not configured, an
1448 exception will be raised. The rationale behind this behavior is to
1449 allow an application to programmatically invoke configuration of
1450 registries while controlling whether or not the process implicitly
1451 reaches other registries.
1452
1453 As an alternative to invoking :meth:`_orm.registry.configure`, the ORM
1454 function :func:`_orm.configure_mappers` function may be used to ensure
1455 configuration is complete for all :class:`_orm.registry` objects in
1456 memory. This is generally simpler to use and also predates the usage of
1457 :class:`_orm.registry` objects overall. However, this function will
1458 impact all mappings throughout the running Python process and may be
1459 more memory/time consuming for an application that has many registries
1460 in use for different purposes that may not be needed immediately.
1461
1462 .. seealso::
1463
1464 :func:`_orm.configure_mappers`
1465
1466
1467 .. versionadded:: 1.4.0b2
1468
1469 """
1470 mapperlib._configure_registries({self}, cascade=cascade)
1471
1472 def dispose(self, cascade: bool = False) -> None:
1473 """Dispose of all mappers in this :class:`_orm.registry`.
1474
1475 After invocation, all the classes that were mapped within this registry
1476 will no longer have class instrumentation associated with them. This
1477 method is the per-:class:`_orm.registry` analogue to the
1478 application-wide :func:`_orm.clear_mappers` function.
1479
1480 If this registry contains mappers that are dependencies of other
1481 registries, typically via :func:`_orm.relationship` links, then those
1482 registries must be disposed as well. When such registries exist in
1483 relation to this one, their :meth:`_orm.registry.dispose` method will
1484 also be called, if the :paramref:`_orm.registry.dispose.cascade` flag
1485 is set to ``True``; otherwise, an error is raised if those registries
1486 were not already disposed.
1487
1488 .. versionadded:: 1.4.0b2
1489
1490 .. seealso::
1491
1492 :func:`_orm.clear_mappers`
1493
1494 """
1495
1496 mapperlib._dispose_registries({self}, cascade=cascade)
1497
1498 def _dispose_manager_and_mapper(self, manager: ClassManager[Any]) -> None:
1499 if "mapper" in manager.__dict__:
1500 mapper = manager.mapper
1501
1502 mapper._set_dispose_flags()
1503
1504 class_ = manager.class_
1505 self._dispose_cls(class_)
1506 instrumentation._instrumentation_factory.unregister(class_)
1507
1508 def generate_base(
1509 self,
1510 mapper: Optional[Callable[..., Mapper[Any]]] = None,
1511 cls: Type[Any] = object,
1512 name: str = "Base",
1513 metaclass: Type[Any] = DeclarativeMeta,
1514 ) -> Any:
1515 """Generate a declarative base class.
1516
1517 Classes that inherit from the returned class object will be
1518 automatically mapped using declarative mapping.
1519
1520 E.g.::
1521
1522 from sqlalchemy.orm import registry
1523
1524 mapper_registry = registry()
1525
1526 Base = mapper_registry.generate_base()
1527
1528
1529 class MyClass(Base):
1530 __tablename__ = "my_table"
1531 id = Column(Integer, primary_key=True)
1532
1533 The above dynamically generated class is equivalent to the
1534 non-dynamic example below::
1535
1536 from sqlalchemy.orm import registry
1537 from sqlalchemy.orm.decl_api import DeclarativeMeta
1538
1539 mapper_registry = registry()
1540
1541
1542 class Base(metaclass=DeclarativeMeta):
1543 __abstract__ = True
1544 registry = mapper_registry
1545 metadata = mapper_registry.metadata
1546
1547 __init__ = mapper_registry.constructor
1548
1549 .. versionchanged:: 2.0 Note that the
1550 :meth:`_orm.registry.generate_base` method is superseded by the new
1551 :class:`_orm.DeclarativeBase` class, which generates a new "base"
1552 class using subclassing, rather than return value of a function.
1553 This allows an approach that is compatible with :pep:`484` typing
1554 tools.
1555
1556 The :meth:`_orm.registry.generate_base` method provides the
1557 implementation for the :func:`_orm.declarative_base` function, which
1558 creates the :class:`_orm.registry` and base class all at once.
1559
1560 See the section :ref:`orm_declarative_mapping` for background and
1561 examples.
1562
1563 :param mapper:
1564 An optional callable, defaults to :class:`_orm.Mapper`.
1565 This function is used to generate new :class:`_orm.Mapper` objects.
1566
1567 :param cls:
1568 Defaults to :class:`object`. A type to use as the base for the
1569 generated declarative base class. May be a class or tuple of classes.
1570
1571 :param name:
1572 Defaults to ``Base``. The display name for the generated
1573 class. Customizing this is not required, but can improve clarity in
1574 tracebacks and debugging.
1575
1576 :param metaclass:
1577 Defaults to :class:`.DeclarativeMeta`. A metaclass or __metaclass__
1578 compatible callable to use as the meta type of the generated
1579 declarative base class.
1580
1581 .. seealso::
1582
1583 :ref:`orm_declarative_mapping`
1584
1585 :func:`_orm.declarative_base`
1586
1587 """
1588 metadata = self.metadata
1589
1590 bases = not isinstance(cls, tuple) and (cls,) or cls
1591
1592 class_dict: Dict[str, Any] = dict(registry=self, metadata=metadata)
1593 if isinstance(cls, type):
1594 class_dict["__doc__"] = cls.__doc__
1595
1596 if self.constructor is not None:
1597 class_dict["__init__"] = self.constructor
1598
1599 class_dict["__abstract__"] = True
1600 if mapper:
1601 class_dict["__mapper_cls__"] = mapper
1602
1603 if hasattr(cls, "__class_getitem__"):
1604
1605 def __class_getitem__(cls: Type[_T], key: Any) -> Type[_T]:
1606 # allow generic classes in py3.9+
1607 return cls
1608
1609 class_dict["__class_getitem__"] = __class_getitem__
1610
1611 return metaclass(name, bases, class_dict)
1612
1613 @compat_typing.dataclass_transform(
1614 field_specifiers=(
1615 MappedColumn,
1616 RelationshipProperty,
1617 Composite,
1618 Synonym,
1619 mapped_column,
1620 relationship,
1621 composite,
1622 synonym,
1623 deferred,
1624 ),
1625 )
1626 @overload
1627 def mapped_as_dataclass(self, __cls: Type[_O]) -> Type[_O]: ...
1628
1629 @overload
1630 def mapped_as_dataclass(
1631 self,
1632 __cls: Literal[None] = ...,
1633 *,
1634 init: Union[_NoArg, bool] = ...,
1635 repr: Union[_NoArg, bool] = ..., # noqa: A002
1636 eq: Union[_NoArg, bool] = ...,
1637 order: Union[_NoArg, bool] = ...,
1638 unsafe_hash: Union[_NoArg, bool] = ...,
1639 match_args: Union[_NoArg, bool] = ...,
1640 kw_only: Union[_NoArg, bool] = ...,
1641 dataclass_callable: Union[_NoArg, Callable[..., Type[Any]]] = ...,
1642 ) -> Callable[[Type[_O]], Type[_O]]: ...
1643
1644 def mapped_as_dataclass(
1645 self,
1646 __cls: Optional[Type[_O]] = None,
1647 *,
1648 init: Union[_NoArg, bool] = _NoArg.NO_ARG,
1649 repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
1650 eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
1651 order: Union[_NoArg, bool] = _NoArg.NO_ARG,
1652 unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
1653 match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
1654 kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
1655 dataclass_callable: Union[
1656 _NoArg, Callable[..., Type[Any]]
1657 ] = _NoArg.NO_ARG,
1658 ) -> Union[Type[_O], Callable[[Type[_O]], Type[_O]]]:
1659 """Class decorator that will apply the Declarative mapping process
1660 to a given class, and additionally convert the class to be a
1661 Python dataclass.
1662
1663 .. seealso::
1664
1665 :ref:`orm_declarative_native_dataclasses` - complete background
1666 on SQLAlchemy native dataclass mapping
1667
1668 :func:`_orm.mapped_as_dataclass` - functional version that may
1669 provide better compatibility with mypy
1670
1671 .. versionadded:: 2.0
1672
1673
1674 """
1675
1676 def decorate(cls: Type[_O]) -> Type[_O]:
1677 setattr(
1678 cls,
1679 "_sa_apply_dc_transforms",
1680 {
1681 "init": init,
1682 "repr": repr,
1683 "eq": eq,
1684 "order": order,
1685 "unsafe_hash": unsafe_hash,
1686 "match_args": match_args,
1687 "kw_only": kw_only,
1688 "dataclass_callable": dataclass_callable,
1689 },
1690 )
1691 _as_declarative(self, cls, cls.__dict__)
1692 return cls
1693
1694 if __cls:
1695 return decorate(__cls)
1696 else:
1697 return decorate
1698
1699 def mapped(self, cls: Type[_O]) -> Type[_O]:
1700 """Class decorator that will apply the Declarative mapping process
1701 to a given class.
1702
1703 E.g.::
1704
1705 from sqlalchemy.orm import registry
1706
1707 mapper_registry = registry()
1708
1709
1710 @mapper_registry.mapped
1711 class Foo:
1712 __tablename__ = "some_table"
1713
1714 id = Column(Integer, primary_key=True)
1715 name = Column(String)
1716
1717 See the section :ref:`orm_declarative_mapping` for complete
1718 details and examples.
1719
1720 :param cls: class to be mapped.
1721
1722 :return: the class that was passed.
1723
1724 .. seealso::
1725
1726 :ref:`orm_declarative_mapping`
1727
1728 :meth:`_orm.registry.generate_base` - generates a base class
1729 that will apply Declarative mapping to subclasses automatically
1730 using a Python metaclass.
1731
1732 .. seealso::
1733
1734 :meth:`_orm.registry.mapped_as_dataclass`
1735
1736 """
1737 _as_declarative(self, cls, cls.__dict__)
1738 return cls
1739
1740 def as_declarative_base(self, **kw: Any) -> Callable[[Type[_T]], Type[_T]]:
1741 """
1742 Class decorator which will invoke
1743 :meth:`_orm.registry.generate_base`
1744 for a given base class.
1745
1746 E.g.::
1747
1748 from sqlalchemy.orm import registry
1749
1750 mapper_registry = registry()
1751
1752
1753 @mapper_registry.as_declarative_base()
1754 class Base:
1755 @declared_attr
1756 def __tablename__(cls):
1757 return cls.__name__.lower()
1758
1759 id = Column(Integer, primary_key=True)
1760
1761
1762 class MyMappedClass(Base): ...
1763
1764 All keyword arguments passed to
1765 :meth:`_orm.registry.as_declarative_base` are passed
1766 along to :meth:`_orm.registry.generate_base`.
1767
1768 """
1769
1770 def decorate(cls: Type[_T]) -> Type[_T]:
1771 kw["cls"] = cls
1772 kw["name"] = cls.__name__
1773 return self.generate_base(**kw) # type: ignore
1774
1775 return decorate
1776
1777 def map_declaratively(self, cls: Type[_O]) -> Mapper[_O]:
1778 """Map a class declaratively.
1779
1780 In this form of mapping, the class is scanned for mapping information,
1781 including for columns to be associated with a table, and/or an
1782 actual table object.
1783
1784 Returns the :class:`_orm.Mapper` object.
1785
1786 E.g.::
1787
1788 from sqlalchemy.orm import registry
1789
1790 mapper_registry = registry()
1791
1792
1793 class Foo:
1794 __tablename__ = "some_table"
1795
1796 id = Column(Integer, primary_key=True)
1797 name = Column(String)
1798
1799
1800 mapper = mapper_registry.map_declaratively(Foo)
1801
1802 This function is more conveniently invoked indirectly via either the
1803 :meth:`_orm.registry.mapped` class decorator or by subclassing a
1804 declarative metaclass generated from
1805 :meth:`_orm.registry.generate_base`.
1806
1807 See the section :ref:`orm_declarative_mapping` for complete
1808 details and examples.
1809
1810 :param cls: class to be mapped.
1811
1812 :return: a :class:`_orm.Mapper` object.
1813
1814 .. seealso::
1815
1816 :ref:`orm_declarative_mapping`
1817
1818 :meth:`_orm.registry.mapped` - more common decorator interface
1819 to this function.
1820
1821 :meth:`_orm.registry.map_imperatively`
1822
1823 """
1824 _as_declarative(self, cls, cls.__dict__)
1825 return cls.__mapper__ # type: ignore
1826
1827 def map_imperatively(
1828 self,
1829 class_: Type[_O],
1830 local_table: Optional[FromClause] = None,
1831 **kw: Any,
1832 ) -> Mapper[_O]:
1833 r"""Map a class imperatively.
1834
1835 In this form of mapping, the class is not scanned for any mapping
1836 information. Instead, all mapping constructs are passed as
1837 arguments.
1838
1839 This method is intended to be fully equivalent to the now-removed
1840 SQLAlchemy ``mapper()`` function, except that it's in terms of
1841 a particular registry.
1842
1843 E.g.::
1844
1845 from sqlalchemy.orm import registry
1846
1847 mapper_registry = registry()
1848
1849 my_table = Table(
1850 "my_table",
1851 mapper_registry.metadata,
1852 Column("id", Integer, primary_key=True),
1853 )
1854
1855
1856 class MyClass:
1857 pass
1858
1859
1860 mapper_registry.map_imperatively(MyClass, my_table)
1861
1862 See the section :ref:`orm_imperative_mapping` for complete background
1863 and usage examples.
1864
1865 :param class\_: The class to be mapped. Corresponds to the
1866 :paramref:`_orm.Mapper.class_` parameter.
1867
1868 :param local_table: the :class:`_schema.Table` or other
1869 :class:`_sql.FromClause` object that is the subject of the mapping.
1870 Corresponds to the
1871 :paramref:`_orm.Mapper.local_table` parameter.
1872
1873 :param \**kw: all other keyword arguments are passed to the
1874 :class:`_orm.Mapper` constructor directly.
1875
1876 .. seealso::
1877
1878 :ref:`orm_imperative_mapping`
1879
1880 :ref:`orm_declarative_mapping`
1881
1882 """
1883 return _mapper(self, class_, local_table, kw)
1884
1885
1886RegistryType = registry
1887
1888if not TYPE_CHECKING:
1889 # allow for runtime type resolution of ``ClassVar[_RegistryType]``
1890 _RegistryType = registry # noqa
1891
1892
1893def as_declarative(**kw: Any) -> Callable[[Type[_T]], Type[_T]]:
1894 """
1895 Class decorator which will adapt a given class into a
1896 :func:`_orm.declarative_base`.
1897
1898 This function makes use of the :meth:`_orm.registry.as_declarative_base`
1899 method, by first creating a :class:`_orm.registry` automatically
1900 and then invoking the decorator.
1901
1902 E.g.::
1903
1904 from sqlalchemy.orm import as_declarative
1905
1906
1907 @as_declarative()
1908 class Base:
1909 @declared_attr
1910 def __tablename__(cls):
1911 return cls.__name__.lower()
1912
1913 id = Column(Integer, primary_key=True)
1914
1915
1916 class MyMappedClass(Base): ...
1917
1918 .. seealso::
1919
1920 :meth:`_orm.registry.as_declarative_base`
1921
1922 """
1923 metadata, class_registry = (
1924 kw.pop("metadata", None),
1925 kw.pop("class_registry", None),
1926 )
1927
1928 return registry(
1929 metadata=metadata, class_registry=class_registry
1930 ).as_declarative_base(**kw)
1931
1932
1933@compat_typing.dataclass_transform(
1934 field_specifiers=(
1935 MappedColumn,
1936 RelationshipProperty,
1937 Composite,
1938 Synonym,
1939 mapped_column,
1940 relationship,
1941 composite,
1942 synonym,
1943 deferred,
1944 ),
1945)
1946def mapped_as_dataclass(
1947 registry: RegistryType,
1948 *,
1949 init: Union[_NoArg, bool] = _NoArg.NO_ARG,
1950 repr: Union[_NoArg, bool] = _NoArg.NO_ARG, # noqa: A002
1951 eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
1952 order: Union[_NoArg, bool] = _NoArg.NO_ARG,
1953 unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
1954 match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
1955 kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
1956 dataclass_callable: Union[
1957 _NoArg, Callable[..., Type[Any]]
1958 ] = _NoArg.NO_ARG,
1959) -> Callable[[Type[_O]], Type[_O]]:
1960 """Standalone function form of :meth:`_orm.registry.mapped_as_dataclass`
1961 which may have better compatibility with mypy.
1962
1963 The :class:`_orm.registry` is passed as the first argument to the
1964 decorator.
1965
1966 e.g.::
1967
1968 from sqlalchemy.orm import Mapped
1969 from sqlalchemy.orm import mapped_as_dataclass
1970 from sqlalchemy.orm import mapped_column
1971 from sqlalchemy.orm import registry
1972
1973 some_registry = registry()
1974
1975
1976 @mapped_as_dataclass(some_registry)
1977 class Relationships:
1978 __tablename__ = "relationships"
1979
1980 entity_id1: Mapped[int] = mapped_column(primary_key=True)
1981 entity_id2: Mapped[int] = mapped_column(primary_key=True)
1982 level: Mapped[int] = mapped_column(Integer)
1983
1984 .. versionadded:: 2.0.44
1985
1986 """
1987 return registry.mapped_as_dataclass(
1988 init=init,
1989 repr=repr,
1990 eq=eq,
1991 order=order,
1992 unsafe_hash=unsafe_hash,
1993 match_args=match_args,
1994 kw_only=kw_only,
1995 dataclass_callable=dataclass_callable,
1996 )
1997
1998
1999@inspection._inspects(
2000 DeclarativeMeta, DeclarativeBase, DeclarativeAttributeIntercept
2001)
2002def _inspect_decl_meta(cls: Type[Any]) -> Optional[Mapper[Any]]:
2003 mp: Optional[Mapper[Any]] = _inspect_mapped_class(cls)
2004 if mp is None:
2005 if _DeferredMapperConfig.has_cls(cls):
2006 _DeferredMapperConfig.raise_unmapped_for_cls(cls)
2007 return mp