Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
decl_api.py2005 linesDownload Raw Back to orm
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
99_TT = TypeVar("_TT", bound=Any)
100
101# it's not clear how to have Annotated, Union objects etc. as keys here
102# from a typing perspective so just leave it open ended for now
103_TypeAnnotationMapType = Mapping[Any, "_TypeEngineArgument[Any]"]
104_MutableTypeAnnotationMapType = Dict[Any, "_TypeEngineArgument[Any]"]
105
106_DeclaredAttrDecorated = Callable[
107    ..., Union[Mapped[_T], ORMDescriptor[_T], SQLCoreOperations[_T]]
108]
109
110
111def has_inherited_table(cls: Type[_O]) -> bool:
112    """Given a class, return True if any of the classes it inherits from has a
113    mapped table, otherwise return False.
114
115    This is used in declarative mixins to build attributes that behave
116    differently for the base class vs. a subclass in an inheritance
117    hierarchy.
118
119    .. seealso::
120
121        :ref:`decl_mixin_inheritance`
122
123    """
124    for class_ in cls.__mro__[1:]:
125        if getattr(class_, "__table__", None) is not None:
126            return True
127    return False
128
129
130class _DynamicAttributesType(type):
131    def __setattr__(cls, key: str, value: Any) -> None:
132        if "__mapper__" in cls.__dict__:
133            _add_attribute(cls, key, value)
134        else:
135            type.__setattr__(cls, key, value)
136
137    def __delattr__(cls, key: str) -> None:
138        if "__mapper__" in cls.__dict__:
139            _del_attribute(cls, key)
140        else:
141            type.__delattr__(cls, key)
142
143
144class DeclarativeAttributeIntercept(
145    _DynamicAttributesType,
146    # Inspectable is used only by the mypy plugin
147    inspection.Inspectable[Mapper[Any]],
148):
149    """Metaclass that may be used in conjunction with the
150    :class:`_orm.DeclarativeBase` class to support addition of class
151    attributes dynamically.
152
153    """
154
155
156@compat_typing.dataclass_transform(
157    field_specifiers=(
158        MappedColumn,
159        RelationshipProperty,
160        Composite,
161        Synonym,
162        mapped_column,
163        relationship,
164        composite,
165        synonym,
166        deferred,
167    ),
168)
169class DCTransformDeclarative(DeclarativeAttributeIntercept):
170    """metaclass that includes @dataclass_transforms"""
171
172
173class DeclarativeMeta(DeclarativeAttributeIntercept):
174    metadata: MetaData
175    registry: RegistryType
176
177    def __init__(
178        cls, classname: Any, bases: Any, dict_: Any, **kw: Any
179    ) -> None:
180        # use cls.__dict__, which can be modified by an
181        # __init_subclass__() method (#7900)
182        dict_ = cls.__dict__
183
184        # early-consume registry from the initial declarative base,
185        # assign privately to not conflict with subclass attributes named
186        # "registry"
187        reg = getattr(cls, "_sa_registry", None)
188        if reg is None:
189            reg = dict_.get("registry", None)
190            if not isinstance(reg, registry):
191                raise exc.InvalidRequestError(
192                    "Declarative base class has no 'registry' attribute, "
193                    "or registry is not a sqlalchemy.orm.registry() object"
194                )
195            else:
196                cls._sa_registry = reg
197
198        if not cls.__dict__.get("__abstract__", False):
199            _as_declarative(reg, cls, dict_)
200        type.__init__(cls, classname, bases, dict_)
201
202
203def synonym_for(
204    name: str, map_column: bool = False
205) -> Callable[[Callable[..., Any]], Synonym[Any]]:
206    """Decorator that produces an :func:`_orm.synonym`
207    attribute in conjunction with a Python descriptor.
208
209    The function being decorated is passed to :func:`_orm.synonym` as the
210    :paramref:`.orm.synonym.descriptor` parameter::
211
212        class MyClass(Base):
213            __tablename__ = "my_table"
214
215            id = Column(Integer, primary_key=True)
216            _job_status = Column("job_status", String(50))
217
218            @synonym_for("job_status")
219            @property
220            def job_status(self):
221                return "Status: %s" % self._job_status
222
223    The :ref:`hybrid properties <mapper_hybrids>` feature of SQLAlchemy
224    is typically preferred instead of synonyms, which is a more legacy
225    feature.
226
227    .. seealso::
228
229        :ref:`synonyms` - Overview of synonyms
230
231        :func:`_orm.synonym` - the mapper-level function
232
233        :ref:`mapper_hybrids` - The Hybrid Attribute extension provides an
234        updated approach to augmenting attribute behavior more flexibly than
235        can be achieved with synonyms.
236
237    """
238
239    def decorate(fn: Callable[..., Any]) -> Synonym[Any]:
240        return _orm_synonym(name, map_column=map_column, descriptor=fn)
241
242    return decorate
243
244
245class _declared_attr_common:
246    def __init__(
247        self,
248        fn: Callable[..., Any],
249        cascading: bool = False,
250        quiet: bool = False,
251    ):
252        # support
253        # @declared_attr
254        # @classmethod
255        # def foo(cls) -> Mapped[thing]:
256        #    ...
257        # which seems to help typing tools interpret the fn as a classmethod
258        # for situations where needed
259        if isinstance(fn, classmethod):
260            fn = fn.__func__
261
262        self.fget = fn
263        self._cascading = cascading
264        self._quiet = quiet
265        self.__doc__ = fn.__doc__
266
267    def _collect_return_annotation(self) -> Optional[Type[Any]]:
268        return util.get_annotations(self.fget).get("return")
269
270    def __get__(self, instance: Optional[object], owner: Any) -> Any:
271        # the declared_attr needs to make use of a cache that exists
272        # for the span of the declarative scan_attributes() phase.
273        # to achieve this we look at the class manager that's configured.
274
275        # note this method should not be called outside of the declarative
276        # setup phase
277
278        cls = owner
279        manager = attributes.opt_manager_of_class(cls)
280        if manager is None:
281            if not re.match(r"^__.+__$", self.fget.__name__):
282                # if there is no manager at all, then this class hasn't been
283                # run through declarative or mapper() at all, emit a warning.
284                util.warn(
285                    "Unmanaged access of declarative attribute %s from "
286                    "non-mapped class %s" % (self.fget.__name__, cls.__name__)
287                )
288            return self.fget(cls)
289        elif manager.is_mapped:
290            # the class is mapped, which means we're outside of the declarative
291            # scan setup, just run the function.
292            return self.fget(cls)
293
294        # here, we are inside of the declarative scan.  use the registry
295        # that is tracking the values of these attributes.
296        declarative_scan = manager.declarative_scan()
297
298        # assert that we are in fact in the declarative scan
299        assert declarative_scan is not None
300
301        reg = declarative_scan.declared_attr_reg
302
303        if self in reg:
304            return reg[self]
305        else:
306            reg[self] = obj = self.fget(cls)
307            return obj
308
309
310class _declared_directive(_declared_attr_common, Generic[_T]):
311    # see mapping_api.rst for docstring
312
313    if typing.TYPE_CHECKING:
314
315        def __init__(
316            self,
317            fn: Callable[..., _T],
318            cascading: bool = False,
319        ): ...
320
321        def __get__(self, instance: Optional[object], owner: Any) -> _T: ...
322
323        def __set__(self, instance: Any, value: Any) -> None: ...
324
325        def __delete__(self, instance: Any) -> None: ...
326
327        def __call__(self, fn: Callable[..., _TT]) -> _declared_directive[_TT]:
328            # extensive fooling of mypy underway...
329            ...
330
331
332class declared_attr(interfaces._MappedAttribute[_T], _declared_attr_common):
333    """Mark a class-level method as representing the definition of
334    a mapped property or Declarative directive.
335
336    :class:`_orm.declared_attr` is typically applied as a decorator to a class
337    level method, turning the attribute into a scalar-like property that can be
338    invoked from the uninstantiated class. The Declarative mapping process
339    looks for these :class:`_orm.declared_attr` callables as it scans classes,
340    and assumes any attribute marked with :class:`_orm.declared_attr` will be a
341    callable that will produce an object specific to the Declarative mapping or
342    table configuration.
343
344    :class:`_orm.declared_attr` is usually applicable to
345    :ref:`mixins <orm_mixins_toplevel>`, to define relationships that are to be
346    applied to different implementors of the class. It may also be used to
347    define dynamically generated column expressions and other Declarative
348    attributes.
349
350    Example::
351
352        class ProvidesUserMixin:
353            "A mixin that adds a 'user' relationship to classes."
354
355            user_id: Mapped[int] = mapped_column(ForeignKey("user_table.id"))
356
357            @declared_attr
358            def user(cls) -> Mapped["User"]:
359                return relationship("User")
360
361    When used with Declarative directives such as ``__tablename__``, the
362    :meth:`_orm.declared_attr.directive` modifier may be used which indicates
363    to :pep:`484` typing tools that the given method is not dealing with
364    :class:`_orm.Mapped` attributes::
365
366        class CreateTableName:
367            @declared_attr.directive
368            def __tablename__(cls) -> str:
369                return cls.__name__.lower()
370
371    :class:`_orm.declared_attr` can also be applied directly to mapped
372    classes, to allow for attributes that dynamically configure themselves
373    on subclasses when using mapped inheritance schemes.   Below
374    illustrates :class:`_orm.declared_attr` to create a dynamic scheme
375    for generating the :paramref:`_orm.Mapper.polymorphic_identity` parameter
376    for subclasses::
377
378        class Employee(Base):
379            __tablename__ = "employee"
380
381            id: Mapped[int] = mapped_column(primary_key=True)
382            type: Mapped[str] = mapped_column(String(50))
383
384            @declared_attr.directive
385            def __mapper_args__(cls) -> Dict[str, Any]:
386                if cls.__name__ == "Employee":
387                    return {
388                        "polymorphic_on": cls.type,
389                        "polymorphic_identity": "Employee",
390                    }
391                else:
392                    return {"polymorphic_identity": cls.__name__}
393
394
395        class Engineer(Employee):
396            pass
397
398    :class:`_orm.declared_attr` supports decorating functions that are
399    explicitly decorated with ``@classmethod``. This is never necessary from a
400    runtime perspective, however may be needed in order to support :pep:`484`
401    typing tools that don't otherwise recognize the decorated function as
402    having class-level behaviors for the ``cls`` parameter::
403
404        class SomethingMixin:
405            x: Mapped[int]
406            y: Mapped[int]
407
408            @declared_attr
409            @classmethod
410            def x_plus_y(cls) -> Mapped[int]:
411                return column_property(cls.x + cls.y)
412
413    .. versionadded:: 2.0 - :class:`_orm.declared_attr` can accommodate a
414       function decorated with ``@classmethod`` to help with :pep:`484`
415       integration where needed.
416
417
418    .. seealso::
419
420        :ref:`orm_mixins_toplevel` - Declarative Mixin documentation with
421        background on use patterns for :class:`_orm.declared_attr`.
422
423    """  # noqa: E501
424
425    if typing.TYPE_CHECKING:
426
427        def __init__(
428            self,
429            fn: _DeclaredAttrDecorated[_T],
430            cascading: bool = False,
431        ): ...
432
433        def __set__(self, instance: Any, value: Any) -> None: ...
434
435        def __delete__(self, instance: Any) -> None: ...
436
437        # this is the Mapped[] API where at class descriptor get time we want
438        # the type checker to see InstrumentedAttribute[_T].   However the
439        # callable function prior to mapping in fact calls the given
440        # declarative function that does not return InstrumentedAttribute
441        @overload
442        def __get__(
443            self, instance: None, owner: Any
444        ) -> InstrumentedAttribute[_T]: ...
445
446        @overload
447        def __get__(self, instance: object, owner: Any) -> _T: ...
448
449        def __get__(
450            self, instance: Optional[object], owner: Any
451        ) -> Union[InstrumentedAttribute[_T], _T]: ...
452
453    @hybridmethod
454    def _stateful(cls, **kw: Any) -> _stateful_declared_attr[_T]:
455        return _stateful_declared_attr(**kw)
456
457    @hybridproperty
458    def directive(cls) -> _declared_directive[Any]:
459        # see mapping_api.rst for docstring
460        return _declared_directive  # type: ignore
461
462    @hybridproperty
463    def cascading(cls) -> _stateful_declared_attr[_T]:
464        # see mapping_api.rst for docstring
465        return cls._stateful(cascading=True)
466
467
468class _stateful_declared_attr(declared_attr[_T]):
469    kw: Dict[str, Any]
470
471    def __init__(self, **kw: Any):
472        self.kw = kw
473
474    @hybridmethod
475    def _stateful(self, **kw: Any) -> _stateful_declared_attr[_T]:
476        new_kw = self.kw.copy()
477        new_kw.update(kw)
478        return _stateful_declared_attr(**new_kw)
479
480    def __call__(self, fn: _DeclaredAttrDecorated[_T]) -> declared_attr[_T]:
481        return declared_attr(fn, **self.kw)
482
483
484def declarative_mixin(cls: Type[_T]) -> Type[_T]:
485    """Mark a class as providing the feature of "declarative mixin".
486
487    E.g.::
488
489        from sqlalchemy.orm import declared_attr
490        from sqlalchemy.orm import declarative_mixin
491
492
493        @declarative_mixin
494        class MyMixin:
495
496            @declared_attr
497            def __tablename__(cls):
498                return cls.__name__.lower()
499
500            __table_args__ = {"mysql_engine": "InnoDB"}
501            __mapper_args__ = {"always_refresh": True}
502
503            id = Column(Integer, primary_key=True)
504
505
506        class MyModel(MyMixin, Base):
507            name = Column(String(1000))
508
509    The :func:`_orm.declarative_mixin` decorator currently does not modify
510    the given class in any way; it's current purpose is strictly to assist
511    the :ref:`Mypy plugin <mypy_toplevel>` in being able to identify
512    SQLAlchemy declarative mixin classes when no other context is present.
513
514    .. versionadded:: 1.4.6
515
516    .. legacy:: This api is considered legacy and will be deprecated in the next
517      SQLAlchemy version.
518
519    .. seealso::
520
521        :ref:`orm_mixins_toplevel`
522
523        :ref:`mypy_declarative_mixins` - in the
524        :ref:`Mypy plugin documentation <mypy_toplevel>`
525
526    """  # noqa: E501
527
528    return cls
529
530
531def _setup_declarative_base(cls: Type[Any]) -> None:
532    if "metadata" in cls.__dict__:
533        metadata = cls.__dict__["metadata"]
534    else:
535        metadata = None
536
537    if "type_annotation_map" in cls.__dict__:
538        type_annotation_map = cls.__dict__["type_annotation_map"]
539    else:
540        type_annotation_map = None
541
542    reg = cls.__dict__.get("registry", None)
543    if reg is not None:
544        if not isinstance(reg, registry):
545            raise exc.InvalidRequestError(
546                "Declarative base class has a 'registry' attribute that is "
547                "not an instance of sqlalchemy.orm.registry()"
548            )
549        elif type_annotation_map is not None:
550            raise exc.InvalidRequestError(
551                "Declarative base class has both a 'registry' attribute and a "
552                "type_annotation_map entry.  Per-base type_annotation_maps "
553                "are not supported.  Please apply the type_annotation_map "
554                "to this registry directly."
555            )
556
557    else:
558        reg = registry(
559            metadata=metadata, type_annotation_map=type_annotation_map
560        )
561        cls.registry = reg
562
563    cls._sa_registry = reg
564
565    if "metadata" not in cls.__dict__:
566        cls.metadata = cls.registry.metadata
567
568    if getattr(cls, "__init__", object.__init__) is object.__init__:
569        cls.__init__ = cls.registry.constructor
570
571
572class MappedAsDataclass(metaclass=DCTransformDeclarative):
573    """Mixin class to indicate when mapping this class, also convert it to be
574    a dataclass.
575
576    .. seealso::
577
578        :ref:`orm_declarative_native_dataclasses` - complete background
579        on SQLAlchemy native dataclass mapping
580
581    .. versionadded:: 2.0
582
583    """
584
585    def __init_subclass__(
586        cls,
587        init: Union[_NoArg, bool] = _NoArg.NO_ARG,
588        repr: Union[_NoArg, bool] = _NoArg.NO_ARG,  # noqa: A002
589        eq: Union[_NoArg, bool] = _NoArg.NO_ARG,
590        order: Union[_NoArg, bool] = _NoArg.NO_ARG,
591        unsafe_hash: Union[_NoArg, bool] = _NoArg.NO_ARG,
592        match_args: Union[_NoArg, bool] = _NoArg.NO_ARG,
593        kw_only: Union[_NoArg, bool] = _NoArg.NO_ARG,
594        dataclass_callable: Union[
595            _NoArg, Callable[..., Type[Any]]
596        ] = _NoArg.NO_ARG,
597        **kw: Any,
598    ) -> None:
599        apply_dc_transforms: _DataclassArguments = {
600            "init": init,
601            "repr": repr,
602            "eq": eq,
603            "order": order,
604            "unsafe_hash": unsafe_hash,
605            "match_args": match_args,
606            "kw_only": kw_only,
607            "dataclass_callable": dataclass_callable,
608        }
609
610        current_transforms: _DataclassArguments
611
612        if hasattr(cls, "_sa_apply_dc_transforms"):
613            current = cls._sa_apply_dc_transforms
614
615            _ClassScanMapperConfig._assert_dc_arguments(current)
616
617            cls._sa_apply_dc_transforms = current_transforms = {  # type: ignore  # noqa: E501
618                k: current.get(k, _NoArg.NO_ARG) if v is _NoArg.NO_ARG else v
619                for k, v in apply_dc_transforms.items()
620            }
621        else:
622            cls._sa_apply_dc_transforms = current_transforms = (
623                apply_dc_transforms
624            )
625
626        super().__init_subclass__(**kw)
627
628        if not _is_mapped_class(cls):
629            new_anno = (
630                _ClassScanMapperConfig._update_annotations_for_non_mapped_class
631            )(cls)
632            _ClassScanMapperConfig._apply_dataclasses_to_any_class(
633                current_transforms, cls, new_anno
634            )
635
636
637class DeclarativeBase(
638    # Inspectable is used only by the mypy plugin
639    inspection.Inspectable[InstanceState[Any]],
640    metaclass=DeclarativeAttributeIntercept,
641):
642    """Base class used for declarative class definitions.
643
644    The :class:`_orm.DeclarativeBase` allows for the creation of new
645    declarative bases in such a way that is compatible with type checkers::
646
647
648        from sqlalchemy.orm import DeclarativeBase
649
650
651        class Base(DeclarativeBase):
652            pass
653
654    The above ``Base`` class is now usable as the base for new declarative
655    mappings.  The superclass makes use of the ``__init_subclass__()``
656    method to set up new classes and metaclasses aren't used.
657
658    When first used, the :class:`_orm.DeclarativeBase` class instantiates a new
659    :class:`_orm.registry` to be used with the base, assuming one was not
660    provided explicitly. The :class:`_orm.DeclarativeBase` class supports
661    class-level attributes which act as parameters for the construction of this
662    registry; such as to indicate a specific :class:`_schema.MetaData`
663    collection as well as a specific value for
664    :paramref:`_orm.registry.type_annotation_map`::
665
666        from typing_extensions import Annotated
667
668        from sqlalchemy import BigInteger
669        from sqlalchemy import MetaData
670        from sqlalchemy import String
671        from sqlalchemy.orm import DeclarativeBase
672
673        bigint = Annotated[int, "bigint"]
674        my_metadata = MetaData()
675
676
677        class Base(DeclarativeBase):
678            metadata = my_metadata
679            type_annotation_map = {
680                str: String().with_variant(String(255), "mysql", "mariadb"),
681                bigint: BigInteger(),
682            }
683
684    Class-level attributes which may be specified include:
685
686    :param metadata: optional :class:`_schema.MetaData` collection.
687     If a :class:`_orm.registry` is constructed automatically, this
688     :class:`_schema.MetaData` collection will be used to construct it.
689     Otherwise, the local :class:`_schema.MetaData` collection will supersede
690     that used by an existing :class:`_orm.registry` passed using the
691     :paramref:`_orm.DeclarativeBase.registry` parameter.
692    :param type_annotation_map: optional type annotation map that will be
693     passed to the :class:`_orm.registry` as
694     :paramref:`_orm.registry.type_annotation_map`.
695    :param registry: supply a pre-existing :class:`_orm.registry` directly.
696
697    .. versionadded:: 2.0  Added :class:`.DeclarativeBase`, so that declarative
698       base classes may be constructed in such a way that is also recognized
699       by :pep:`484` type checkers.   As a result, :class:`.DeclarativeBase`
700       and other subclassing-oriented APIs should be seen as
701       superseding previous "class returned by a function" APIs, namely
702       :func:`_orm.declarative_base` and :meth:`_orm.registry.generate_base`,
703       where the base class returned cannot be recognized by type checkers
704       without using plugins.
705
706    **__init__ behavior**
707
708    In a plain Python class, the base-most ``__init__()`` method in the class
709    hierarchy is ``object.__init__()``, which accepts no arguments. However,
710    when the :class:`_orm.DeclarativeBase` subclass is first declared, the
711    class is given an ``__init__()`` method that links to the
712    :paramref:`_orm.registry.constructor` constructor function, if no
713    ``__init__()`` method is already present; this is the usual declarative
714    constructor that will assign keyword arguments as attributes on the
715    instance, assuming those attributes are established at the class level
716    (i.e. are mapped, or are linked to a descriptor). This constructor is
717    **never accessed by a mapped class without being called explicitly via
718    super()**, as mapped classes are themselves given an ``__init__()`` method
719    directly which calls :paramref:`_orm.registry.constructor`, so in the
720    default case works independently of what the base-most ``__init__()``
721    method does.
722
723    .. versionchanged:: 2.0.1  :class:`_orm.DeclarativeBase` has a default
724       constructor that links to :paramref:`_orm.registry.constructor` by
725       default, so that calls to ``super().__init__()`` can access this
726       constructor. Previously, due to an implementation mistake, this default
727       constructor was missing, and calling ``super().__init__()`` would invoke
728       ``object.__init__()``.
729
730    The :class:`_orm.DeclarativeBase` subclass may also declare an explicit
731    ``__init__()`` method which will replace the use of the
732    :paramref:`_orm.registry.constructor` function at this level::
733
734        class Base(DeclarativeBase):
735            def __init__(self, id=None):
736                self.id = id
737
738    Mapped classes still will not invoke this constructor implicitly; it
739    remains only accessible by calling ``super().__init__()``::
740
741        class MyClass(Base):
742            def __init__(self, id=None, name=None):
743                self.name = name
744                super().__init__(id=id)
745
746    Note that this is a different behavior from what functions like the legacy
747    :func:`_orm.declarative_base` would do; the base created by those functions
748    would always install :paramref:`_orm.registry.constructor` for
749    ``__init__()``.
750
751
752    """
753
754    if typing.TYPE_CHECKING:
755
756        def _sa_inspect_type(self) -> Mapper[Self]: ...
757
758        def _sa_inspect_instance(self) -> InstanceState[Self]: ...
759
760        _sa_registry: ClassVar[_RegistryType]
761
762        registry: ClassVar[_RegistryType]
763        """Refers to the :class:`_orm.registry` in use where new
764        :class:`_orm.Mapper` objects will be associated."""
765
766        metadata: ClassVar[MetaData]
767        """Refers to the :class:`_schema.MetaData` collection that will be used
768        for new :class:`_schema.Table` objects.
769
770        .. seealso::
771
772            :ref:`orm_declarative_metadata`
773
774        """
775
776        __name__: ClassVar[str]
777
778        # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not
779        # like it, and breaks the declared_attr_one test. Pyright/pylance is
780        # ok with it.
781        __mapper__: ClassVar[Mapper[Any]]
782        """The :class:`_orm.Mapper` object to which a particular class is
783        mapped.
784
785        May also be acquired using :func:`_sa.inspect`, e.g.
786        ``inspect(klass)``.
787
788        """
789
790        __table__: ClassVar[FromClause]
791        """The :class:`_sql.FromClause` to which a particular subclass is
792        mapped.
793
794        This is usually an instance of :class:`_schema.Table` but may also
795        refer to other kinds of :class:`_sql.FromClause` such as
796        :class:`_sql.Subquery`, depending on how the class is mapped.
797
798        .. seealso::
799
800            :ref:`orm_declarative_metadata`
801
802        """
803
804        # pyright/pylance do not consider a classmethod a ClassVar so use Any
805        # https://github.com/microsoft/pylance-release/issues/3484
806        __tablename__: Any
807        """String name to assign to the generated
808        :class:`_schema.Table` object, if not specified directly via
809        :attr:`_orm.DeclarativeBase.__table__`.
810
811        .. seealso::
812
813            :ref:`orm_declarative_table`
814
815        """
816
817        __mapper_args__: Any
818        """Dictionary of arguments which will be passed to the
819        :class:`_orm.Mapper` constructor.
820
821        .. seealso::
822
823            :ref:`orm_declarative_mapper_options`
824
825        """
826
827        __table_args__: Any
828        """A dictionary or tuple of arguments that will be passed to the
829        :class:`_schema.Table` constructor.  See
830        :ref:`orm_declarative_table_configuration`
831        for background on the specific structure of this collection.
832
833        .. seealso::
834
835            :ref:`orm_declarative_table_configuration`
836
837        """
838
839        def __init__(self, **kw: Any): ...
840
841    def __init_subclass__(cls, **kw: Any) -> None:
842        if DeclarativeBase in cls.__bases__:
843            _check_not_declarative(cls, DeclarativeBase)
844            _setup_declarative_base(cls)
845        else:
846            _as_declarative(cls._sa_registry, cls, cls.__dict__)
847        super().__init_subclass__(**kw)
848
849
850def _check_not_declarative(cls: Type[Any], base: Type[Any]) -> None:
851    cls_dict = cls.__dict__
852    if (
853        "__table__" in cls_dict
854        and not (
855            callable(cls_dict["__table__"])
856            or hasattr(cls_dict["__table__"], "__get__")
857        )
858    ) or isinstance(cls_dict.get("__tablename__", None), str):
859        raise exc.InvalidRequestError(
860            f"Cannot use {base.__name__!r} directly as a declarative base "
861            "class. Create a Base by creating a subclass of it."
862        )
863
864
865class DeclarativeBaseNoMeta(
866    # Inspectable is used only by the mypy plugin
867    inspection.Inspectable[InstanceState[Any]]
868):
869    """Same as :class:`_orm.DeclarativeBase`, but does not use a metaclass
870    to intercept new attributes.
871
872    The :class:`_orm.DeclarativeBaseNoMeta` base may be used when use of
873    custom metaclasses is desirable.
874
875    .. versionadded:: 2.0
876
877
878    """
879
880    _sa_registry: ClassVar[_RegistryType]
881
882    registry: ClassVar[_RegistryType]
883    """Refers to the :class:`_orm.registry` in use where new
884    :class:`_orm.Mapper` objects will be associated."""
885
886    metadata: ClassVar[MetaData]
887    """Refers to the :class:`_schema.MetaData` collection that will be used
888    for new :class:`_schema.Table` objects.
889
890    .. seealso::
891
892        :ref:`orm_declarative_metadata`
893
894    """
895
896    # this ideally should be Mapper[Self], but mypy as of 1.4.1 does not
897    # like it, and breaks the declared_attr_one test. Pyright/pylance is
898    # ok with it.
899    __mapper__: ClassVar[Mapper[Any]]
900    """The :class:`_orm.Mapper` object to which a particular class is
901    mapped.
902
903    May also be acquired using :func:`_sa.inspect`, e.g.
904    ``inspect(klass)``.
905
906    """
907
908    __table__: Optional[FromClause]
909    """The :class:`_sql.FromClause` to which a particular subclass is
910    mapped.
911
912    This is usually an instance of :class:`_schema.Table` but may also
913    refer to other kinds of :class:`_sql.FromClause` such as
914    :class:`_sql.Subquery`, depending on how the class is mapped.
915
916    .. seealso::
917
918        :ref:`orm_declarative_metadata`
919
920    """
921
922    if typing.TYPE_CHECKING:
923
924        def _sa_inspect_type(self) -> Mapper[Self]: ...
925
926        def _sa_inspect_instance(self) -> InstanceState[Self]: ...
927
928        __tablename__: Any
929        """String name to assign to the generated
930        :class:`_schema.Table` object, if not specified directly via
931        :attr:`_orm.DeclarativeBase.__table__`.
932
933        .. seealso::
934
935            :ref:`orm_declarative_table`
936
937        """
938
939        __mapper_args__: Any
940        """Dictionary of arguments which will be passed to the
941        :class:`_orm.Mapper` constructor.
942
943        .. seealso::
944
945            :ref:`orm_declarative_mapper_options`
946
947        """
948
949        __table_args__: Any
950        """A dictionary or tuple of arguments that will be passed to the
951        :class:`_schema.Table` constructor.  See
952        :ref:`orm_declarative_table_configuration`
953        for background on the specific structure of this collection.
954
955        .. seealso::
956
957            :ref:`orm_declarative_table_configuration`
958
959        """
960
961        def __init__(self, **kw: Any): ...
962
963    def __init_subclass__(cls, **kw: Any) -> None:
964        if DeclarativeBaseNoMeta in cls.__bases__:
965            _check_not_declarative(cls, DeclarativeBaseNoMeta)
966            _setup_declarative_base(cls)
967        else:
968            _as_declarative(cls._sa_registry, cls, cls.__dict__)
969        super().__init_subclass__(**kw)
970
971
972def add_mapped_attribute(
973    target: Type[_O], key: str, attr: MapperProperty[Any]
974) -> None:
975    """Add a new mapped attribute to an ORM mapped class.
976
977    E.g.::
978
979        add_mapped_attribute(User, "addresses", relationship(Address))
980
981    This may be used for ORM mappings that aren't using a declarative
982    metaclass that intercepts attribute set operations.
983
984    .. versionadded:: 2.0
985
986
987    """
988    _add_attribute(target, key, attr)
989
990
991def declarative_base(
992    *,
993    metadata: Optional[MetaData] = None,
994    mapper: Optional[Callable[..., Mapper[Any]]] = None,
995    cls: Type[Any] = object,
996    name: str = "Base",
997    class_registry: Optional[clsregistry._ClsRegistryType] = None,
998    type_annotation_map: Optional[_TypeAnnotationMapType] = None,
999    constructor: Callable[..., None] = _declarative_constructor,
1000    metaclass: Type[Any] = DeclarativeMeta,
1001) -> Any:
1002    r"""Construct a base class for declarative class definitions.
1003
1004    The new base class will be given a metaclass that produces
1005    appropriate :class:`~sqlalchemy.schema.Table` objects and makes
1006    the appropriate :class:`_orm.Mapper` calls based on the
1007    information provided declaratively in the class and any subclasses
1008    of the class.
1009
1010    .. versionchanged:: 2.0 Note that the :func:`_orm.declarative_base`
1011       function is superseded by the new :class:`_orm.DeclarativeBase` class,
1012       which generates a new "base" class using subclassing, rather than
1013       return value of a function.  This allows an approach that is compatible
1014       with :pep:`484` typing tools.
1015
1016    The :func:`_orm.declarative_base` function is a shorthand version
1017    of using the :meth:`_orm.registry.generate_base`
1018    method.  That is, the following::
1019
1020        from sqlalchemy.orm import declarative_base
1021
1022        Base = declarative_base()
1023
1024    Is equivalent to::
1025
1026        from sqlalchemy.orm import registry
1027
1028        mapper_registry = registry()
1029        Base = mapper_registry.generate_base()
1030
1031    See the docstring for :class:`_orm.registry`
1032    and :meth:`_orm.registry.generate_base`
1033    for more details.
1034
1035    .. versionchanged:: 1.4  The :func:`_orm.declarative_base`
1036       function is now a specialization of the more generic
1037       :class:`_orm.registry` class.  The function also moves to the
1038       ``sqlalchemy.orm`` package from the ``declarative.ext`` package.
1039
1040
1041    :param metadata:
1042      An optional :class:`~sqlalchemy.schema.MetaData` instance.  All
1043      :class:`~sqlalchemy.schema.Table` objects implicitly declared by
1044      subclasses of the base will share this MetaData.  A MetaData instance
1045      will be created if none is provided.  The
1046      :class:`~sqlalchemy.schema.MetaData` instance will be available via the
1047      ``metadata`` attribute of the generated declarative base class.
1048
1049    :param mapper:
1050      An optional callable, defaults to :class:`_orm.Mapper`. Will
1051      be used to map subclasses to their Tables.
1052
1053    :param cls:
1054      Defaults to :class:`object`. A type to use as the base for the generated
1055      declarative base class. May be a class or tuple of classes.
1056
1057    :param name:
1058      Defaults to ``Base``.  The display name for the generated
1059      class.  Customizing this is not required, but can improve clarity in
1060      tracebacks and debugging.
1061
1062    :param constructor:
1063      Specify the implementation for the ``__init__`` function on a mapped
1064      class that has no ``__init__`` of its own.  Defaults to an
1065      implementation that assigns \**kwargs for declared
1066      fields and relationships to an instance.  If ``None`` is supplied,
1067      no __init__ will be provided and construction will fall back to
1068      cls.__init__ by way of the normal Python semantics.
1069
1070    :param class_registry: optional dictionary that will serve as the
1071      registry of class names-> mapped classes when string names
1072      are used to identify classes inside of :func:`_orm.relationship`
1073      and others.  Allows two or more declarative base classes
1074      to share the same registry of class names for simplified
1075      inter-base relationships.
1076
1077    :param type_annotation_map: optional dictionary of Python types to
1078        SQLAlchemy :class:`_types.TypeEngine` classes or instances.  This
1079        is used exclusively by the :class:`_orm.MappedColumn` construct
1080        to produce column types based on annotations within the
1081        :class:`_orm.Mapped` type.
1082
1083
1084        .. versionadded:: 2.0
1085
1086        .. seealso::
1087
1088            :ref:`orm_declarative_mapped_column_type_map`
1089
1090    :param metaclass:
1091      Defaults to :class:`.DeclarativeMeta`.  A metaclass or __metaclass__
1092      compatible callable to use as the meta type of the generated
1093      declarative base class.
1094
1095    .. seealso::
1096
1097        :class:`_orm.registry`
1098
1099    """
1100
1101    return registry(
1102        metadata=metadata,
1103        class_registry=class_registry,
1104        constructor=constructor,
1105        type_annotation_map=type_annotation_map,
1106    ).generate_base(
1107        mapper=mapper,
1108        cls=cls,
1109        name=name,
1110        metaclass=metaclass,
1111    )
1112
1113
1114class registry:
1115    """Generalized registry for mapping classes.
1116
1117    The :class:`_orm.registry` serves as the basis for maintaining a collection
1118    of mappings, and provides configurational hooks used to map classes.
1119
1120    The three general kinds of mappings supported are Declarative Base,
1121    Declarative Decorator, and Imperative Mapping.   All of these mapping
1122    styles may be used interchangeably:
1123
1124    * :meth:`_orm.registry.generate_base` returns a new declarative base
1125      class, and is the underlying implementation of the
1126      :func:`_orm.declarative_base` function.
1127
1128    * :meth:`_orm.registry.mapped` provides a class decorator that will
1129      apply declarative mapping to a class without the use of a declarative
1130      base class.
1131
1132    * :meth:`_orm.registry.map_imperatively` will produce a
1133      :class:`_orm.Mapper` for a class without scanning the class for
1134      declarative class attributes. This method suits the use case historically
1135      provided by the ``sqlalchemy.orm.mapper()`` classical mapping function,
1136      which is removed as of SQLAlchemy 2.0.
1137
1138    .. versionadded:: 1.4
1139
1140    .. seealso::
1141
1142        :ref:`orm_mapping_classes_toplevel` - overview of class mapping
1143        styles.
1144
1145    """
1146
1147    _class_registry: clsregistry._ClsRegistryType
1148    _managers: weakref.WeakKeyDictionary[ClassManager[Any], Literal[True]]
1149    _non_primary_mappers: weakref.WeakKeyDictionary[Mapper[Any], Literal[True]]
1150    metadata: MetaData
1151    constructor: CallableReference[Callable[..., None]]
1152    type_annotation_map: _MutableTypeAnnotationMapType
1153    _dependents: Set[_RegistryType]
1154    _dependencies: Set[_RegistryType]
1155    _new_mappers: bool
1156
1157    def __init__(
1158        self,
1159        *,
1160        metadata: Optional[MetaData] = None,
1161        class_registry: Optional[clsregistry._ClsRegistryType] = None,
1162        type_annotation_map: Optional[_TypeAnnotationMapType] = None,
1163        constructor: Callable[..., None] = _declarative_constructor,
1164    ):
1165        r"""Construct a new :class:`_orm.registry`
1166
1167        :param metadata:
1168          An optional :class:`_schema.MetaData` instance.  All
1169          :class:`_schema.Table` objects generated using declarative
1170          table mapping will make use of this :class:`_schema.MetaData`
1171          collection.  If this argument is left at its default of ``None``,
1172          a blank :class:`_schema.MetaData` collection is created.
1173
1174        :param constructor:
1175          Specify the implementation for the ``__init__`` function on a mapped
1176          class that has no ``__init__`` of its own.  Defaults to an
1177          implementation that assigns \**kwargs for declared
1178          fields and relationships to an instance.  If ``None`` is supplied,
1179          no __init__ will be provided and construction will fall back to
1180          cls.__init__ by way of the normal Python semantics.
1181
1182        :param class_registry: optional dictionary that will serve as the
1183          registry of class names-> mapped classes when string names
1184          are used to identify classes inside of :func:`_orm.relationship`
1185          and others.  Allows two or more declarative base classes
1186          to share the same registry of class names for simplified
1187          inter-base relationships.
1188
1189        :param type_annotation_map: optional dictionary of Python types to
1190          SQLAlchemy :class:`_types.TypeEngine` classes or instances.
1191          The provided dict will update the default type mapping.  This
1192          is used exclusively by the :class:`_orm.MappedColumn` construct
1193          to produce column types based on annotations within the
1194          :class:`_orm.Mapped` type.
1195
1196          .. versionadded:: 2.0
1197
1198          .. seealso::
1199
1200              :ref:`orm_declarative_mapped_column_type_map`

Showing the first 1,200 of 2005 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai