Team Ai
Datasetpublic

codekingpro/portable-devtools

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

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

codekingpro/portable-devtools · Team Ai