1# orm/mapper.py
2# Copyright (C) 2005-2019 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: http://www.opensource.org/licenses/mit-license.php
7
8"""Logic to map Python classes to and from selectables.
9
10Defines the :class:`~sqlalchemy.orm.mapper.Mapper` class, the central
11configurational unit which associates a class with a database table.
12
13This is a semi-private module; the main configurational API of the ORM is
14available in :class:`~sqlalchemy.orm.`.
15
16"""
17from __future__ import absolute_import
18
19from collections import deque
20from itertools import chain
21import sys
22import types
23import weakref
24
25from . import attributes
26from . import exc as orm_exc
27from . import instrumentation
28from . import loading
29from . import properties
30from . import util as orm_util
31from .base import _class_to_mapper
32from .base import _INSTRUMENTOR
33from .base import _state_mapper
34from .base import class_mapper
35from .base import state_str
36from .interfaces import _MappedAttribute
37from .interfaces import InspectionAttr
38from .interfaces import MapperProperty
39from .path_registry import PathRegistry
40from .. import event
41from .. import exc as sa_exc
42from .. import inspection
43from .. import log
44from .. import schema
45from .. import sql
46from .. import util
47from ..sql import expression
48from ..sql import operators
49from ..sql import util as sql_util
50from ..sql import visitors
51
52
53_mapper_registry = weakref.WeakKeyDictionary()
54_already_compiling = False
55
56_memoized_configured_property = util.group_expirable_memoized_property()
57
58
59# a constant returned by _get_attr_by_column to indicate
60# this mapper is not handling an attribute for a particular
61# column
62NO_ATTRIBUTE = util.symbol("NO_ATTRIBUTE")
63
64# lock used to synchronize the "mapper configure" step
65_CONFIGURE_MUTEX = util.threading.RLock()
66
67
68@inspection._self_inspects
69@log.class_logger
70class Mapper(InspectionAttr):
71    """Define the correlation of class attributes to database table
72    columns.
73
74    The :class:`.Mapper` object is instantiated using the
75    :func:`~sqlalchemy.orm.mapper` function.    For information
76    about instantiating new :class:`.Mapper` objects, see
77    that function's documentation.
78
79
80    When :func:`.mapper` is used
81    explicitly to link a user defined class with table
82    metadata, this is referred to as *classical mapping*.
83    Modern SQLAlchemy usage tends to favor the
84    :mod:`sqlalchemy.ext.declarative` extension for class
85    configuration, which
86    makes usage of :func:`.mapper` behind the scenes.
87
88    Given a particular class known to be mapped by the ORM,
89    the :class:`.Mapper` which maintains it can be acquired
90    using the :func:`.inspect` function::
91
92        from sqlalchemy import inspect
93
94        mapper = inspect(MyClass)
95
96    A class which was mapped by the :mod:`sqlalchemy.ext.declarative`
97    extension will also have its mapper available via the ``__mapper__``
98    attribute.
99
100
101    """
102
103    _new_mappers = False
104
105    def __init__(
106        self,
107        class_,
108        local_table=None,
109        properties=None,
110        primary_key=None,
111        non_primary=False,
112        inherits=None,
113        inherit_condition=None,
114        inherit_foreign_keys=None,
115        extension=None,
116        order_by=False,
117        always_refresh=False,
118        version_id_col=None,
119        version_id_generator=None,
120        polymorphic_on=None,
121        _polymorphic_map=None,
122        polymorphic_identity=None,
123        concrete=False,
124        with_polymorphic=None,
125        polymorphic_load=None,
126        allow_partial_pks=True,
127        batch=True,
128        column_prefix=None,
129        include_properties=None,
130        exclude_properties=None,
131        passive_updates=True,
132        passive_deletes=False,
133        confirm_deleted_rows=True,
134        eager_defaults=False,
135        legacy_is_orphan=False,
136        _compiled_cache_size=100,
137    ):
138        r"""Return a new :class:`~.Mapper` object.
139
140        This function is typically used behind the scenes
141        via the Declarative extension.   When using Declarative,
142        many of the usual :func:`.mapper` arguments are handled
143        by the Declarative extension itself, including ``class_``,
144        ``local_table``, ``properties``, and  ``inherits``.
145        Other options are passed to :func:`.mapper` using
146        the ``__mapper_args__`` class variable::
147
148           class MyClass(Base):
149               __tablename__ = 'my_table'
150               id = Column(Integer, primary_key=True)
151               type = Column(String(50))
152               alt = Column("some_alt", Integer)
153
154               __mapper_args__ = {
155                   'polymorphic_on' : type
156               }
157
158
159        Explicit use of :func:`.mapper`
160        is often referred to as *classical mapping*.  The above
161        declarative example is equivalent in classical form to::
162
163            my_table = Table("my_table", metadata,
164                Column('id', Integer, primary_key=True),
165                Column('type', String(50)),
166                Column("some_alt", Integer)
167            )
168
169            class MyClass(object):
170                pass
171
172            mapper(MyClass, my_table,
173                polymorphic_on=my_table.c.type,
174                properties={
175                    'alt':my_table.c.some_alt
176                })
177
178        .. seealso::
179
180            :ref:`classical_mapping` - discussion of direct usage of
181            :func:`.mapper`
182
183        :param class\_: The class to be mapped.  When using Declarative,
184          this argument is automatically passed as the declared class
185          itself.
186
187        :param local_table: The :class:`.Table` or other selectable
188           to which the class is mapped.  May be ``None`` if
189           this mapper inherits from another mapper using single-table
190           inheritance.   When using Declarative, this argument is
191           automatically passed by the extension, based on what
192           is configured via the ``__table__`` argument or via the
193           :class:`.Table` produced as a result of the ``__tablename__``
194           and :class:`.Column` arguments present.
195
196        :param always_refresh: If True, all query operations for this mapped
197           class will overwrite all data within object instances that already
198           exist within the session, erasing any in-memory changes with
199           whatever information was loaded from the database. Usage of this
200           flag is highly discouraged; as an alternative, see the method
201           :meth:`.Query.populate_existing`.
202
203        :param allow_partial_pks: Defaults to True.  Indicates that a
204           composite primary key with some NULL values should be considered as
205           possibly existing within the database. This affects whether a
206           mapper will assign an incoming row to an existing identity, as well
207           as if :meth:`.Session.merge` will check the database first for a
208           particular primary key value. A "partial primary key" can occur if
209           one has mapped to an OUTER JOIN, for example.
210
211        :param batch: Defaults to ``True``, indicating that save operations
212           of multiple entities can be batched together for efficiency.
213           Setting to False indicates
214           that an instance will be fully saved before saving the next
215           instance.  This is used in the extremely rare case that a
216           :class:`.MapperEvents` listener requires being called
217           in between individual row persistence operations.
218
219        :param column_prefix: A string which will be prepended
220           to the mapped attribute name when :class:`.Column`
221           objects are automatically assigned as attributes to the
222           mapped class.  Does not affect explicitly specified
223           column-based properties.
224
225           See the section :ref:`column_prefix` for an example.
226
227        :param concrete: If True, indicates this mapper should use concrete
228           table inheritance with its parent mapper.
229
230           See the section :ref:`concrete_inheritance` for an example.
231
232        :param confirm_deleted_rows: defaults to True; when a DELETE occurs
233          of one more rows based on specific primary keys, a warning is
234          emitted when the number of rows matched does not equal the number
235          of rows expected.  This parameter may be set to False to handle the
236          case where database ON DELETE CASCADE rules may be deleting some of
237          those rows automatically.  The warning may be changed to an
238          exception in a future release.
239
240          .. versionadded:: 0.9.4 - added
241             :paramref:`.mapper.confirm_deleted_rows` as well as conditional
242             matched row checking on delete.
243
244        :param eager_defaults: if True, the ORM will immediately fetch the
245          value of server-generated default values after an INSERT or UPDATE,
246          rather than leaving them as expired to be fetched on next access.
247          This can be used for event schemes where the server-generated values
248          are needed immediately before the flush completes.   By default,
249          this scheme will emit an individual ``SELECT`` statement per row
250          inserted or updated, which note can add significant performance
251          overhead.  However, if the
252          target database supports :term:`RETURNING`, the default values will
253          be returned inline with the INSERT or UPDATE statement, which can
254          greatly enhance performance for an application that needs frequent
255          access to just-generated server defaults.
256
257          .. seealso::
258
259                :ref:`orm_server_defaults`
260
261          .. versionchanged:: 0.9.0 The ``eager_defaults`` option can now
262             make use of :term:`RETURNING` for backends which support it.
263
264        :param exclude_properties: A list or set of string column names to
265          be excluded from mapping.
266
267          See :ref:`include_exclude_cols` for an example.
268
269        :param extension: A :class:`.MapperExtension` instance or
270           list of :class:`.MapperExtension` instances which will be applied
271           to all operations by this :class:`.Mapper`.
272
273           .. deprecated:: 0.7
274
275                :class:`.MapperExtension` is deprecated in favor of the
276                :class:`.MapperEvents` listener interface.  The
277                :paramref:`.mapper.extension` parameter will be
278                removed in a future release.
279
280        :param include_properties: An inclusive list or set of string column
281          names to map.
282
283          See :ref:`include_exclude_cols` for an example.
284
285        :param inherits: A mapped class or the corresponding :class:`.Mapper`
286          of one indicating a superclass to which this :class:`.Mapper`
287          should *inherit* from.   The mapped class here must be a subclass
288          of the other mapper's class.   When using Declarative, this argument
289          is passed automatically as a result of the natural class
290          hierarchy of the declared classes.
291
292          .. seealso::
293
294            :ref:`inheritance_toplevel`
295
296        :param inherit_condition: For joined table inheritance, a SQL
297           expression which will
298           define how the two tables are joined; defaults to a natural join
299           between the two tables.
300
301        :param inherit_foreign_keys: When ``inherit_condition`` is used and
302           the columns present are missing a :class:`.ForeignKey`
303           configuration, this parameter can be used to specify which columns
304           are "foreign".  In most cases can be left as ``None``.
305
306        :param legacy_is_orphan: Boolean, defaults to ``False``.
307          When ``True``, specifies that "legacy" orphan consideration
308          is to be applied to objects mapped by this mapper, which means
309          that a pending (that is, not persistent) object is auto-expunged
310          from an owning :class:`.Session` only when it is de-associated
311          from *all* parents that specify a ``delete-orphan`` cascade towards
312          this mapper.  The new default behavior is that the object is
313          auto-expunged when it is de-associated with *any* of its parents
314          that specify ``delete-orphan`` cascade.  This behavior is more
315          consistent with that of a persistent object, and allows behavior to
316          be consistent in more scenarios independently of whether or not an
317          orphanable object has been flushed yet or not.
318
319          See the change note and example at :ref:`legacy_is_orphan_addition`
320          for more detail on this change.
321
322        :param non_primary: Specify that this :class:`.Mapper` is in addition
323          to the "primary" mapper, that is, the one used for persistence.
324          The :class:`.Mapper` created here may be used for ad-hoc
325          mapping of the class to an alternate selectable, for loading
326          only.
327
328          :paramref:`.Mapper.non_primary` is not an often used option, but
329          is useful in some specific :func:`.relationship` cases.
330
331          .. seealso::
332
333              :ref:`relationship_non_primary_mapper`
334
335        :param order_by: A single :class:`.Column` or list of :class:`.Column`
336           objects for which selection operations should use as the default
337           ordering for entities.  By default mappers have no pre-defined
338           ordering.
339
340           .. deprecated:: 1.1 The :paramref:`.Mapper.order_by` parameter
341              is deprecated, and will be removed in a future release.
342              Use :meth:`.Query.order_by` to determine the ordering of a
343              result set.
344
345        :param passive_deletes: Indicates DELETE behavior of foreign key
346           columns when a joined-table inheritance entity is being deleted.
347           Defaults to ``False`` for a base mapper; for an inheriting mapper,
348           defaults to ``False`` unless the value is set to ``True``
349           on the superclass mapper.
350
351           When ``True``, it is assumed that ON DELETE CASCADE is configured
352           on the foreign key relationships that link this mapper's table
353           to its superclass table, so that when the unit of work attempts
354           to delete the entity, it need only emit a DELETE statement for the
355           superclass table, and not this table.
356
357           When ``False``, a DELETE statement is emitted for this mapper's
358           table individually.  If the primary key attributes local to this
359           table are unloaded, then a SELECT must be emitted in order to
360           validate these attributes; note that the primary key columns
361           of a joined-table subclass are not part of the "primary key" of
362           the object as a whole.
363
364           Note that a value of ``True`` is **always** forced onto the
365           subclass mappers; that is, it's not possible for a superclass
366           to specify passive_deletes without this taking effect for
367           all subclass mappers.
368
369           .. versionadded:: 1.1
370
371           .. seealso::
372
373               :ref:`passive_deletes` - description of similar feature as
374               used with :func:`.relationship`
375
376               :paramref:`.mapper.passive_updates` - supporting ON UPDATE
377               CASCADE for joined-table inheritance mappers
378
379        :param passive_updates: Indicates UPDATE behavior of foreign key
380           columns when a primary key column changes on a joined-table
381           inheritance mapping.   Defaults to ``True``.
382
383           When True, it is assumed that ON UPDATE CASCADE is configured on
384           the foreign key in the database, and that the database will handle
385           propagation of an UPDATE from a source column to dependent columns
386           on joined-table rows.
387
388           When False, it is assumed that the database does not enforce
389           referential integrity and will not be issuing its own CASCADE
390           operation for an update.  The unit of work process will
391           emit an UPDATE statement for the dependent columns during a
392           primary key change.
393
394           .. seealso::
395
396               :ref:`passive_updates` - description of a similar feature as
397               used with :func:`.relationship`
398
399               :paramref:`.mapper.passive_deletes` - supporting ON DELETE
400               CASCADE for joined-table inheritance mappers
401
402        :param polymorphic_load: Specifies "polymorphic loading" behavior
403          for a subclass in an inheritance hierarchy (joined and single
404          table inheritance only).   Valid values are:
405
406            * "'inline'" - specifies this class should be part of the
407              "with_polymorphic" mappers, e.g. its columns will be included
408              in a SELECT query against the base.
409
410            * "'selectin'" - specifies that when instances of this class
411              are loaded, an additional SELECT will be emitted to retrieve
412              the columns specific to this subclass.  The SELECT uses
413              IN to fetch multiple subclasses at once.
414
415         .. versionadded:: 1.2
416
417         .. seealso::
418
419            :ref:`with_polymorphic_mapper_config`
420
421            :ref:`polymorphic_selectin`
422
423        :param polymorphic_on: Specifies the column, attribute, or
424          SQL expression used to determine the target class for an
425          incoming row, when inheriting classes are present.
426
427          This value is commonly a :class:`.Column` object that's
428          present in the mapped :class:`.Table`::
429
430            class Employee(Base):
431                __tablename__ = 'employee'
432
433                id = Column(Integer, primary_key=True)
434                discriminator = Column(String(50))
435
436                __mapper_args__ = {
437                    "polymorphic_on":discriminator,
438                    "polymorphic_identity":"employee"
439                }
440
441          It may also be specified
442          as a SQL expression, as in this example where we
443          use the :func:`.case` construct to provide a conditional
444          approach::
445
446            class Employee(Base):
447                __tablename__ = 'employee'
448
449                id = Column(Integer, primary_key=True)
450                discriminator = Column(String(50))
451
452                __mapper_args__ = {
453                    "polymorphic_on":case([
454                        (discriminator == "EN", "engineer"),
455                        (discriminator == "MA", "manager"),
456                    ], else_="employee"),
457                    "polymorphic_identity":"employee"
458                }
459
460          It may also refer to any attribute
461          configured with :func:`.column_property`, or to the
462          string name of one::
463
464                class Employee(Base):
465                    __tablename__ = 'employee'
466
467                    id = Column(Integer, primary_key=True)
468                    discriminator = Column(String(50))
469                    employee_type = column_property(
470                        case([
471                            (discriminator == "EN", "engineer"),
472                            (discriminator == "MA", "manager"),
473                        ], else_="employee")
474                    )
475
476                    __mapper_args__ = {
477                        "polymorphic_on":employee_type,
478                        "polymorphic_identity":"employee"
479                    }
480
481          When setting ``polymorphic_on`` to reference an
482          attribute or expression that's not present in the
483          locally mapped :class:`.Table`, yet the value
484          of the discriminator should be persisted to the database,
485          the value of the
486          discriminator is not automatically set on new
487          instances; this must be handled by the user,
488          either through manual means or via event listeners.
489          A typical approach to establishing such a listener
490          looks like::
491
492                from sqlalchemy import event
493                from sqlalchemy.orm import object_mapper
494
495                @event.listens_for(Employee, "init", propagate=True)
496                def set_identity(instance, *arg, **kw):
497                    mapper = object_mapper(instance)
498                    instance.discriminator = mapper.polymorphic_identity
499
500          Where above, we assign the value of ``polymorphic_identity``
501          for the mapped class to the ``discriminator`` attribute,
502          thus persisting the value to the ``discriminator`` column
503          in the database.
504
505          .. warning::
506
507             Currently, **only one discriminator column may be set**, typically
508             on the base-most class in the hierarchy. "Cascading" polymorphic
509             columns are not yet supported.
510
511          .. seealso::
512
513            :ref:`inheritance_toplevel`
514
515        :param polymorphic_identity: Specifies the value which
516          identifies this particular class as returned by the
517          column expression referred to by the ``polymorphic_on``
518          setting.  As rows are received, the value corresponding
519          to the ``polymorphic_on`` column expression is compared
520          to this value, indicating which subclass should
521          be used for the newly reconstructed object.
522
523        :param properties: A dictionary mapping the string names of object
524           attributes to :class:`.MapperProperty` instances, which define the
525           persistence behavior of that attribute.  Note that :class:`.Column`
526           objects present in
527           the mapped :class:`.Table` are automatically placed into
528           ``ColumnProperty`` instances upon mapping, unless overridden.
529           When using Declarative, this argument is passed automatically,
530           based on all those :class:`.MapperProperty` instances declared
531           in the declared class body.
532
533        :param primary_key: A list of :class:`.Column` objects which define
534           the primary key to be used against this mapper's selectable unit.
535           This is normally simply the primary key of the ``local_table``, but
536           can be overridden here.
537
538        :param version_id_col: A :class:`.Column`
539           that will be used to keep a running version id of rows
540           in the table.  This is used to detect concurrent updates or
541           the presence of stale data in a flush.  The methodology is to
542           detect if an UPDATE statement does not match the last known
543           version id, a
544           :class:`~sqlalchemy.orm.exc.StaleDataError` exception is
545           thrown.
546           By default, the column must be of :class:`.Integer` type,
547           unless ``version_id_generator`` specifies an alternative version
548           generator.
549
550           .. seealso::
551
552              :ref:`mapper_version_counter` - discussion of version counting
553              and rationale.
554
555        :param version_id_generator: Define how new version ids should
556          be generated.  Defaults to ``None``, which indicates that
557          a simple integer counting scheme be employed.  To provide a custom
558          versioning scheme, provide a callable function of the form::
559
560              def generate_version(version):
561                  return next_version
562
563          Alternatively, server-side versioning functions such as triggers,
564          or programmatic versioning schemes outside of the version id
565          generator may be used, by specifying the value ``False``.
566          Please see :ref:`server_side_version_counter` for a discussion
567          of important points when using this option.
568
569          .. versionadded:: 0.9.0 ``version_id_generator`` supports
570             server-side version number generation.
571
572          .. seealso::
573
574             :ref:`custom_version_counter`
575
576             :ref:`server_side_version_counter`
577
578
579        :param with_polymorphic: A tuple in the form ``(<classes>,
580            <selectable>)`` indicating the default style of "polymorphic"
581            loading, that is, which tables are queried at once. <classes> is
582            any single or list of mappers and/or classes indicating the
583            inherited classes that should be loaded at once. The special value
584            ``'*'`` may be used to indicate all descending classes should be
585            loaded immediately. The second tuple argument <selectable>
586            indicates a selectable that will be used to query for multiple
587            classes.
588
589            .. seealso::
590
591              :ref:`with_polymorphic` - discussion of polymorphic querying
592              techniques.
593
594        """
595
596        self.class_ = util.assert_arg_type(class_, type, "class_")
597
598        self.class_manager = None
599
600        self._primary_key_argument = util.to_list(primary_key)
601        self.non_primary = non_primary
602
603        if order_by is not False:
604            self.order_by = util.to_list(order_by)
605            util.warn_deprecated(
606                "Mapper.order_by is deprecated."
607                "Use Query.order_by() in order to affect the ordering of ORM "
608                "result sets."
609            )
610
611        else:
612            self.order_by = order_by
613
614        self.always_refresh = always_refresh
615
616        if isinstance(version_id_col, MapperProperty):
617            self.version_id_prop = version_id_col
618            self.version_id_col = None
619        else:
620            self.version_id_col = version_id_col
621        if version_id_generator is False:
622            self.version_id_generator = False
623        elif version_id_generator is None:
624            self.version_id_generator = lambda x: (x or 0) + 1
625        else:
626            self.version_id_generator = version_id_generator
627
628        self.concrete = concrete
629        self.single = False
630        self.inherits = inherits
631        self.local_table = local_table
632        self.inherit_condition = inherit_condition
633        self.inherit_foreign_keys = inherit_foreign_keys
634        self._init_properties = properties or {}
635        self._delete_orphans = []
636        self.batch = batch
637        self.eager_defaults = eager_defaults
638        self.column_prefix = column_prefix
639        self.polymorphic_on = expression._clause_element_as_expr(
640            polymorphic_on
641        )
642        self._dependency_processors = []
643        self.validators = util.immutabledict()
644        self.passive_updates = passive_updates
645        self.passive_deletes = passive_deletes
646        self.legacy_is_orphan = legacy_is_orphan
647        self._clause_adapter = None
648        self._requires_row_aliasing = False
649        self._inherits_equated_pairs = None
650        self._memoized_values = {}
651        self._compiled_cache_size = _compiled_cache_size
652        self._reconstructor = None
653        self._deprecated_extensions = util.to_list(extension or [])
654        self.allow_partial_pks = allow_partial_pks
655
656        if self.inherits and not self.concrete:
657            self.confirm_deleted_rows = False
658        else:
659            self.confirm_deleted_rows = confirm_deleted_rows
660
661        if isinstance(self.local_table, expression.SelectBase):
662            raise sa_exc.InvalidRequestError(
663                "When mapping against a select() construct, map against "
664                "an alias() of the construct instead."
665                "This because several databases don't allow a "
666                "SELECT from a subquery that does not have an alias."
667            )
668
669        self._set_with_polymorphic(with_polymorphic)
670        self.polymorphic_load = polymorphic_load
671
672        # our 'polymorphic identity', a string name that when located in a
673        #  result set row indicates this Mapper should be used to construct
674        # the object instance for that row.
675        self.polymorphic_identity = polymorphic_identity
676
677        # a dictionary of 'polymorphic identity' names, associating those
678        # names with Mappers that will be used to construct object instances
679        # upon a select operation.
680        if _polymorphic_map is None:
681            self.polymorphic_map = {}
682        else:
683            self.polymorphic_map = _polymorphic_map
684
685        if include_properties is not None:
686            self.include_properties = util.to_set(include_properties)
687        else:
688            self.include_properties = None
689        if exclude_properties:
690            self.exclude_properties = util.to_set(exclude_properties)
691        else:
692            self.exclude_properties = None
693
694        self.configured = False
695
696        # prevent this mapper from being constructed
697        # while a configure_mappers() is occurring (and defer a
698        # configure_mappers() until construction succeeds)
699        _CONFIGURE_MUTEX.acquire()
700        try:
701            self.dispatch._events._new_mapper_instance(class_, self)
702            self._configure_inheritance()
703            self._configure_legacy_instrument_class()
704            self._configure_class_instrumentation()
705            self._configure_listeners()
706            self._configure_properties()
707            self._configure_polymorphic_setter()
708            self._configure_pks()
709            Mapper._new_mappers = True
710            self._log("constructed")
711            self._expire_memoizations()
712        finally:
713            _CONFIGURE_MUTEX.release()
714
715    # major attributes initialized at the classlevel so that
716    # they can be Sphinx-documented.
717
718    is_mapper = True
719    """Part of the inspection API."""
720
721    represents_outer_join = False
722
723    @property
724    def mapper(self):
725        """Part of the inspection API.
726
727        Returns self.
728
729        """
730        return self
731
732    @property
733    def entity(self):
734        r"""Part of the inspection API.
735
736        Returns self.class\_.
737
738        """
739        return self.class_
740
741    local_table = None
742    """The :class:`.Selectable` which this :class:`.Mapper` manages.
743
744    Typically is an instance of :class:`.Table` or :class:`.Alias`.
745    May also be ``None``.
746
747    The "local" table is the
748    selectable that the :class:`.Mapper` is directly responsible for
749    managing from an attribute access and flush perspective.   For
750    non-inheriting mappers, the local table is the same as the
751    "mapped" table.   For joined-table inheritance mappers, local_table
752    will be the particular sub-table of the overall "join" which
753    this :class:`.Mapper` represents.  If this mapper is a
754    single-table inheriting mapper, local_table will be ``None``.
755
756    .. seealso::
757
758        :attr:`~.Mapper.mapped_table`.
759
760    """
761
762    mapped_table = None
763    """The :class:`.Selectable` to which this :class:`.Mapper` is mapped.
764
765    Typically an instance of :class:`.Table`, :class:`.Join`, or
766    :class:`.Alias`.
767
768    The "mapped" table is the selectable that
769    the mapper selects from during queries.   For non-inheriting
770    mappers, the mapped table is the same as the "local" table.
771    For joined-table inheritance mappers, mapped_table references the
772    full :class:`.Join` representing full rows for this particular
773    subclass.  For single-table inheritance mappers, mapped_table
774    references the base table.
775
776    .. seealso::
777
778        :attr:`~.Mapper.local_table`.
779
780    """
781
782    inherits = None
783    """References the :class:`.Mapper` which this :class:`.Mapper`
784    inherits from, if any.
785
786    This is a *read only* attribute determined during mapper construction.
787    Behavior is undefined if directly modified.
788
789    """
790
791    configured = None
792    """Represent ``True`` if this :class:`.Mapper` has been configured.
793
794    This is a *read only* attribute determined during mapper construction.
795    Behavior is undefined if directly modified.
796
797    .. seealso::
798
799        :func:`.configure_mappers`.
800
801    """
802
803    concrete = None
804    """Represent ``True`` if this :class:`.Mapper` is a concrete
805    inheritance mapper.
806
807    This is a *read only* attribute determined during mapper construction.
808    Behavior is undefined if directly modified.
809
810    """
811
812    tables = None
813    """An iterable containing the collection of :class:`.Table` objects
814    which this :class:`.Mapper` is aware of.
815
816    If the mapper is mapped to a :class:`.Join`, or an :class:`.Alias`
817    representing a :class:`.Select`, the individual :class:`.Table`
818    objects that comprise the full construct will be represented here.
819
820    This is a *read only* attribute determined during mapper construction.
821    Behavior is undefined if directly modified.
822
823    """
824
825    primary_key = None
826    """An iterable containing the collection of :class:`.Column` objects
827    which comprise the 'primary key' of the mapped table, from the
828    perspective of this :class:`.Mapper`.
829
830    This list is against the selectable in :attr:`~.Mapper.mapped_table`. In
831    the case of inheriting mappers, some columns may be managed by a
832    superclass mapper.  For example, in the case of a :class:`.Join`, the
833    primary key is determined by all of the primary key columns across all
834    tables referenced by the :class:`.Join`.
835
836    The list is also not necessarily the same as the primary key column
837    collection associated with the underlying tables; the :class:`.Mapper`
838    features a ``primary_key`` argument that can override what the
839    :class:`.Mapper` considers as primary key columns.
840
841    This is a *read only* attribute determined during mapper construction.
842    Behavior is undefined if directly modified.
843
844    """
845
846    class_ = None
847    """The Python class which this :class:`.Mapper` maps.
848
849    This is a *read only* attribute determined during mapper construction.
850    Behavior is undefined if directly modified.
851
852    """
853
854    class_manager = None
855    """The :class:`.ClassManager` which maintains event listeners
856    and class-bound descriptors for this :class:`.Mapper`.
857
858    This is a *read only* attribute determined during mapper construction.
859    Behavior is undefined if directly modified.
860
861    """
862
863    single = None
864    """Represent ``True`` if this :class:`.Mapper` is a single table
865    inheritance mapper.
866
867    :attr:`~.Mapper.local_table` will be ``None`` if this flag is set.
868
869    This is a *read only* attribute determined during mapper construction.
870    Behavior is undefined if directly modified.
871
872    """
873
874    non_primary = None
875    """Represent ``True`` if this :class:`.Mapper` is a "non-primary"
876    mapper, e.g. a mapper that is used only to select rows but not for
877    persistence management.
878
879    This is a *read only* attribute determined during mapper construction.
880    Behavior is undefined if directly modified.
881
882    """
883
884    polymorphic_on = None
885    """The :class:`.Column` or SQL expression specified as the
886    ``polymorphic_on`` argument
887    for this :class:`.Mapper`, within an inheritance scenario.
888
889    This attribute is normally a :class:`.Column` instance but
890    may also be an expression, such as one derived from
891    :func:`.cast`.
892
893    This is a *read only* attribute determined during mapper construction.
894    Behavior is undefined if directly modified.
895
896    """
897
898    polymorphic_map = None
899    """A mapping of "polymorphic identity" identifiers mapped to
900    :class:`.Mapper` instances, within an inheritance scenario.
901
902    The identifiers can be of any type which is comparable to the
903    type of column represented by :attr:`~.Mapper.polymorphic_on`.
904
905    An inheritance chain of mappers will all reference the same
906    polymorphic map object.  The object is used to correlate incoming
907    result rows to target mappers.
908
909    This is a *read only* attribute determined during mapper construction.
910    Behavior is undefined if directly modified.
911
912    """
913
914    polymorphic_identity = None
915    """Represent an identifier which is matched against the
916    :attr:`~.Mapper.polymorphic_on` column during result row loading.
917
918    Used only with inheritance, this object can be of any type which is
919    comparable to the type of column represented by
920    :attr:`~.Mapper.polymorphic_on`.
921
922    This is a *read only* attribute determined during mapper construction.
923    Behavior is undefined if directly modified.
924
925    """
926
927    base_mapper = None
928    """The base-most :class:`.Mapper` in an inheritance chain.
929
930    In a non-inheriting scenario, this attribute will always be this
931    :class:`.Mapper`.   In an inheritance scenario, it references
932    the :class:`.Mapper` which is parent to all other :class:`.Mapper`
933    objects in the inheritance chain.
934
935    This is a *read only* attribute determined during mapper construction.
936    Behavior is undefined if directly modified.
937
938    """
939
940    columns = None
941    """A collection of :class:`.Column` or other scalar expression
942    objects maintained by this :class:`.Mapper`.
943
944    The collection behaves the same as that of the ``c`` attribute on
945    any :class:`.Table` object, except that only those columns included in
946    this mapping are present, and are keyed based on the attribute name
947    defined in the mapping, not necessarily the ``key`` attribute of the
948    :class:`.Column` itself.   Additionally, scalar expressions mapped
949    by :func:`.column_property` are also present here.
950
951    This is a *read only* attribute determined during mapper construction.
952    Behavior is undefined if directly modified.
953
954    """
955
956    validators = None
957    """An immutable dictionary of attributes which have been decorated
958    using the :func:`~.orm.validates` decorator.
959
960    The dictionary contains string attribute names as keys
961    mapped to the actual validation method.
962
963    """
964
965    c = None
966    """A synonym for :attr:`~.Mapper.columns`."""
967
968    @util.memoized_property
969    def _path_registry(self):
970        return PathRegistry.per_mapper(self)
971
972    def _configure_inheritance(self):
973        """Configure settings related to inheriting and/or inherited mappers
974        being present."""
975
976        # a set of all mappers which inherit from this one.
977        self._inheriting_mappers = util.WeakSequence()
978
979        if self.inherits:
980            if isinstance(self.inherits, type):
981                self.inherits = class_mapper(self.inherits, configure=False)
982            if not issubclass(self.class_, self.inherits.class_):
983                raise sa_exc.ArgumentError(
984                    "Class '%s' does not inherit from '%s'"
985                    % (self.class_.__name__, self.inherits.class_.__name__)
986                )
987            if self.non_primary != self.inherits.non_primary:
988                np = not self.non_primary and "primary" or "non-primary"
989                raise sa_exc.ArgumentError(
990                    "Inheritance of %s mapper for class '%s' is "
991                    "only allowed from a %s mapper"
992                    % (np, self.class_.__name__, np)
993                )
994            # inherit_condition is optional.
995            if self.local_table is None:
996                self.local_table = self.inherits.local_table
997                self.mapped_table = self.inherits.mapped_table
998                self.single = True
999            elif self.local_table is not self.inherits.local_table:
1000                if self.concrete:
1001                    self.mapped_table = self.local_table
1002                    for mapper in self.iterate_to_root():
1003                        if mapper.polymorphic_on is not None:
1004                            mapper._requires_row_aliasing = True
1005                else:
1006                    if self.inherit_condition is None:
1007                        # figure out inherit condition from our table to the
1008                        # immediate table of the inherited mapper, not its
1009                        # full table which could pull in other stuff we don't
1010                        # want (allows test/inheritance.InheritTest4 to pass)
1011                        self.inherit_condition = sql_util.join_condition(
1012                            self.inherits.local_table, self.local_table
1013                        )
1014                    self.mapped_table = sql.join(
1015                        self.inherits.mapped_table,
1016                        self.local_table,
1017                        self.inherit_condition,
1018                    )
1019
1020                    fks = util.to_set(self.inherit_foreign_keys)
1021                    self._inherits_equated_pairs = sql_util.criterion_as_pairs(
1022                        self.mapped_table.onclause,
1023                        consider_as_foreign_keys=fks,
1024                    )
1025            else:
1026                self.mapped_table = self.local_table
1027
1028            if self.polymorphic_identity is not None and not self.concrete:
1029                self._identity_class = self.inherits._identity_class
1030            else:
1031                self._identity_class = self.class_
1032
1033            if self.version_id_col is None:
1034                self.version_id_col = self.inherits.version_id_col
1035                self.version_id_generator = self.inherits.version_id_generator
1036            elif (
1037                self.inherits.version_id_col is not None
1038                and self.version_id_col is not self.inherits.version_id_col
1039            ):
1040                util.warn(
1041                    "Inheriting version_id_col '%s' does not match inherited "
1042                    "version_id_col '%s' and will not automatically populate "
1043                    "the inherited versioning column. "
1044                    "version_id_col should only be specified on "
1045                    "the base-most mapper that includes versioning."
1046                    % (
1047                        self.version_id_col.description,
1048                        self.inherits.version_id_col.description,
1049                    )
1050                )
1051
1052            if (
1053                self.order_by is False
1054                and not self.concrete
1055                and self.inherits.order_by is not False
1056            ):
1057                self.order_by = self.inherits.order_by
1058
1059            self.polymorphic_map = self.inherits.polymorphic_map
1060            self.batch = self.inherits.batch
1061            self.inherits._inheriting_mappers.append(self)
1062            self.base_mapper = self.inherits.base_mapper
1063            self.passive_updates = self.inherits.passive_updates
1064            self.passive_deletes = (
1065                self.inherits.passive_deletes or self.passive_deletes
1066            )
1067            self._all_tables = self.inherits._all_tables
1068
1069            if self.polymorphic_identity is not None:
1070                if self.polymorphic_identity in self.polymorphic_map:
1071                    util.warn(
1072                        "Reassigning polymorphic association for identity %r "
1073                        "from %r to %r: Check for duplicate use of %r as "
1074                        "value for polymorphic_identity."
1075                        % (
1076                            self.polymorphic_identity,
1077                            self.polymorphic_map[self.polymorphic_identity],
1078                            self,
1079                            self.polymorphic_identity,
1080                        )
1081                    )
1082                self.polymorphic_map[self.polymorphic_identity] = self
1083
1084            if self.polymorphic_load and self.concrete:
1085                raise sa_exc.ArgumentError(
1086                    "polymorphic_load is not currently supported "
1087                    "with concrete table inheritance"
1088                )
1089            if self.polymorphic_load == "inline":
1090                self.inherits._add_with_polymorphic_subclass(self)
1091            elif self.polymorphic_load == "selectin":
1092                pass
1093            elif self.polymorphic_load is not None:
1094                raise sa_exc.ArgumentError(
1095                    "unknown argument for polymorphic_load: %r"
1096                    % self.polymorphic_load
1097                )
1098
1099        else:
1100            self._all_tables = set()
1101            self.base_mapper = self
1102            self.mapped_table = self.local_table
1103            if self.polymorphic_identity is not None:
1104                self.polymorphic_map[self.polymorphic_identity] = self
1105            self._identity_class = self.class_
1106
1107        if self.mapped_table is None:
1108            raise sa_exc.ArgumentError(
1109                "Mapper '%s' does not have a mapped_table specified." % self
1110            )
1111
1112    def _set_with_polymorphic(self, with_polymorphic):
1113        if with_polymorphic == "*":
1114            self.with_polymorphic = ("*", None)
1115        elif isinstance(with_polymorphic, (tuple, list)):
1116            if isinstance(
1117                with_polymorphic[0], util.string_types + (tuple, list)
1118            ):
1119                self.with_polymorphic = with_polymorphic
1120            else:
1121                self.with_polymorphic = (with_polymorphic, None)
1122        elif with_polymorphic is not None:
1123            raise sa_exc.ArgumentError("Invalid setting for with_polymorphic")
1124        else:
1125            self.with_polymorphic = None
1126
1127        if isinstance(self.local_table, expression.SelectBase):
1128            raise sa_exc.InvalidRequestError(
1129                "When mapping against a select() construct, map against "
1130                "an alias() of the construct instead."
1131                "This because several databases don't allow a "
1132                "SELECT from a subquery that does not have an alias."
1133            )
1134
1135        if self.with_polymorphic and isinstance(
1136            self.with_polymorphic[1], expression.SelectBase
1137        ):
1138            self.with_polymorphic = (
1139                self.with_polymorphic[0],
1140                self.with_polymorphic[1].alias(),
1141            )
1142
1143        if self.configured:
1144            self._expire_memoizations()
1145
1146    def _add_with_polymorphic_subclass(self, mapper):
1147        subcl = mapper.class_
1148        if self.with_polymorphic is None:
1149            self._set_with_polymorphic((subcl,))
1150        elif self.with_polymorphic[0] != "*":
1151            self._set_with_polymorphic(
1152                (self.with_polymorphic[0] + (subcl,), self.with_polymorphic[1])
1153            )
1154
1155    def _set_concrete_base(self, mapper):
1156        """Set the given :class:`.Mapper` as the 'inherits' for this
1157        :class:`.Mapper`, assuming this :class:`.Mapper` is concrete
1158        and does not already have an inherits."""
1159
1160        assert self.concrete
1161        assert not self.inherits
1162        assert isinstance(mapper, Mapper)
1163        self.inherits = mapper
1164        self.inherits.polymorphic_map.update(self.polymorphic_map)
1165        self.polymorphic_map = self.inherits.polymorphic_map
1166        for mapper in self.iterate_to_root():
1167            if mapper.polymorphic_on is not None:
1168                mapper._requires_row_aliasing = True
1169        self.batch = self.inherits.batch
1170        for mp in self.self_and_descendants:
1171            mp.base_mapper = self.inherits.base_mapper
1172        self.inherits._inheriting_mappers.append(self)
1173        self.passive_updates = self.inherits.passive_updates
1174        self._all_tables = self.inherits._all_tables
1175
1176        for key, prop in mapper._props.items():
1177            if key not in self._props and not self._should_exclude(
1178                key, key, local=False, column=None
1179            ):
1180                self._adapt_inherited_property(key, prop, False)
1181
1182    def _set_polymorphic_on(self, polymorphic_on):
1183        self.polymorphic_on = polymorphic_on
1184        self._configure_polymorphic_setter(True)
1185
1186    def _configure_legacy_instrument_class(self):
1187
1188        if self.inherits:
1189            self.dispatch._update(self.inherits.dispatch)
1190            super_extensions = set(
1191                chain(
1192                    *[
1193                        m._deprecated_extensions
1194                        for m in self.inherits.iterate_to_root()
1195                    ]
1196                )
1197            )
1198        else:
1199            super_extensions = set()
1200
1201        for ext in self._deprecated_extensions:
1202            if ext not in super_extensions:
1203                ext._adapt_instrument_class(self, ext)
1204
1205    def _configure_listeners(self):
1206        if self.inherits:
1207            super_extensions = set(
1208                chain(
1209                    *[
1210                        m._deprecated_extensions
1211                        for m in self.inherits.iterate_to_root()
1212                    ]
1213                )
1214            )
1215        else:
1216            super_extensions = set()
1217
1218        for ext in self._deprecated_extensions:
1219            if ext not in super_extensions:
1220                ext._adapt_listener(self, ext)
1221
1222    def _configure_class_instrumentation(self):
1223        """If this mapper is to be a primary mapper (i.e. the
1224        non_primary flag is not set), associate this Mapper with the
1225        given class_ and entity name.
1226
1227        Subsequent calls to ``class_mapper()`` for the class_/entity
1228        name combination will return this mapper.  Also decorate the
1229        `__init__` method on the mapped class to include optional
1230        auto-session attachment logic.
1231
1232        """
1233
1234        manager = attributes.manager_of_class(self.class_)
1235
1236        if self.non_primary:
1237            if not manager or not manager.is_mapped:
1238                raise sa_exc.InvalidRequestError(
1239                    "Class %s has no primary mapper configured.  Configure "
1240                    "a primary mapper first before setting up a non primary "
1241                    "Mapper." % self.class_
1242                )
1243            self.class_manager = manager
1244            self._identity_class = manager.mapper._identity_class
1245            _mapper_registry[self] = True
1246            return
1247
1248        if manager is not None:
1249            assert manager.class_ is self.class_
1250            if manager.is_mapped:
1251                raise sa_exc.ArgumentError(
1252                    "Class '%s' already has a primary mapper defined. "
1253                    "Use non_primary=True to "
1254                    "create a non primary Mapper.  clear_mappers() will "
1255                    "remove *all* current mappers from all classes."
1256                    % self.class_
1257                )
1258            # else:
1259            # a ClassManager may already exist as
1260            # ClassManager.instrument_attribute() creates
1261            # new managers for each subclass if they don't yet exist.
1262
1263        _mapper_registry[self] = True
1264
1265        # note: this *must be called before instrumentation.register_class*
1266        # to maintain the documented behavior of instrument_class
1267        self.dispatch.instrument_class(self, self.class_)
1268
1269        if manager is None:
1270            manager = instrumentation.register_class(self.class_)
1271
1272        self.class_manager = manager
1273
1274        manager.mapper = self
1275        manager.deferred_scalar_loader = util.partial(
1276            loading.load_scalar_attributes, self
1277        )
1278
1279        # The remaining members can be added by any mapper,
1280        # e_name None or not.
1281        if manager.info.get(_INSTRUMENTOR, False):
1282            return
1283
1284        event.listen(manager, "first_init", _event_on_first_init, raw=True)
1285        event.listen(manager, "init", _event_on_init, raw=True)
1286
1287        for key, method in util.iterate_attributes(self.class_):
1288            if key == "__init__" and hasattr(method, "_sa_original_init"):
1289                method = method._sa_original_init
1290                if isinstance(method, types.MethodType):
1291                    method = method.im_func
1292            if isinstance(method, types.FunctionType):
1293                if hasattr(method, "__sa_reconstructor__"):
1294                    self._reconstructor = method
1295                    event.listen(manager, "load", _event_on_load, raw=True)
1296                elif hasattr(method, "__sa_validators__"):
1297                    validation_opts = method.__sa_validation_opts__
1298                    for name in method.__sa_validators__:
1299                        if name in self.validators:
1300                            raise sa_exc.InvalidRequestError(
1301                                "A validation function for mapped "
1302                                "attribute %r on mapper %s already exists."
1303                                % (name, self)
1304                            )
1305                        self.validators = self.validators.union(
1306                            {name: (method, validation_opts)}
1307                        )
1308
1309        manager.info[_INSTRUMENTOR] = self
1310
1311    @classmethod
1312    def _configure_all(cls):
1313        """Class-level path to the :func:`.configure_mappers` call.
1314        """
1315        configure_mappers()
1316
1317    def dispose(self):
1318        # Disable any attribute-based compilation.
1319        self.configured = True
1320
1321        if hasattr(self, "_configure_failed"):
1322            del self._configure_failed
1323
1324        if (
1325            not self.non_primary
1326            and self.class_manager is not None
1327            and self.class_manager.is_mapped
1328            and self.class_manager.mapper is self
1329        ):
1330            instrumentation.unregister_class(self.class_)
1331
1332    def _configure_pks(self):
1333        self.tables = sql_util.find_tables(self.mapped_table)
1334
1335        self._pks_by_table = {}
1336        self._cols_by_table = {}
1337
1338        all_cols = util.column_set(
1339            chain(*[col.proxy_set for col in self._columntoproperty])
1340        )
1341
1342        pk_cols = util.column_set(c for c in all_cols if c.primary_key)
1343
1344        # identify primary key columns which are also mapped by this mapper.
1345        tables = set(self.tables + [self.mapped_table])
1346        self._all_tables.update(tables)
1347        for t in tables:
1348            if t.primary_key and pk_cols.issuperset(t.primary_key):
1349                # ordering is important since it determines the ordering of
1350                # mapper.primary_key (and therefore query.get())
1351                self._pks_by_table[t] = util.ordered_column_set(
1352                    t.primary_key
1353                ).intersection(pk_cols)
1354            self._cols_by_table[t] = util.ordered_column_set(t.c).intersection(
1355                all_cols
1356            )
1357
1358        # if explicit PK argument sent, add those columns to the
1359        # primary key mappings
1360        if self._primary_key_argument:
1361            for k in self._primary_key_argument:
1362                if k.table not in self._pks_by_table:
1363                    self._pks_by_table[k.table] = util.OrderedSet()
1364                self._pks_by_table[k.table].add(k)
1365
1366        # otherwise, see that we got a full PK for the mapped table
1367        elif (
1368            self.mapped_table not in self._pks_by_table
1369            or len(self._pks_by_table[self.mapped_table]) == 0
1370        ):
1371            raise sa_exc.ArgumentError(
1372                "Mapper %s could not assemble any primary "
1373                "key columns for mapped table '%s'"
1374                % (self, self.mapped_table.description)
1375            )
1376        elif self.local_table not in self._pks_by_table and isinstance(
1377            self.local_table, schema.Table
1378        ):
1379            util.warn(
1380                "Could not assemble any primary "
1381                "keys for locally mapped table '%s' - "
1382                "no rows will be persisted in this Table."
1383                % self.local_table.description
1384            )
1385
1386        if (
1387            self.inherits
1388            and not self.concrete
1389            and not self._primary_key_argument
1390        ):
1391            # if inheriting, the "primary key" for this mapper is
1392            # that of the inheriting (unless concrete or explicit)
1393            self.primary_key = self.inherits.primary_key
1394        else:
1395            # determine primary key from argument or mapped_table pks -
1396            # reduce to the minimal set of columns
1397            if self._primary_key_argument:
1398                primary_key = sql_util.reduce_columns(
1399                    [
1400                        self.mapped_table.corresponding_column(c)
1401                        for c in self._primary_key_argument
1402                    ],
1403                    ignore_nonexistent_tables=True,
1404                )
1405            else:
1406                primary_key = sql_util.reduce_columns(
1407                    self._pks_by_table[self.mapped_table],
1408                    ignore_nonexistent_tables=True,
1409                )
1410
1411            if len(primary_key) == 0:
1412                raise sa_exc.ArgumentError(
1413                    "Mapper %s could not assemble any primary "
1414                    "key columns for mapped table '%s'"
1415                    % (self, self.mapped_table.description)
1416                )
1417
1418            self.primary_key = tuple(primary_key)
1419            self._log("Identified primary key columns: %s", primary_key)
1420
1421        # determine cols that aren't expressed within our tables; mark these
1422        # as "read only" properties which are refreshed upon INSERT/UPDATE
1423        self._readonly_props = set(
1424            self._columntoproperty[col]
1425            for col in self._columntoproperty
1426            if self._columntoproperty[col] not in self._identity_key_props
1427            and (
1428                not hasattr(col, "table")
1429                or col.table not in self._cols_by_table
1430            )
1431        )
1432
1433    def _configure_properties(self):
1434        # Column and other ClauseElement objects which are mapped
1435        self.columns = self.c = util.OrderedProperties()
1436
1437        # object attribute names mapped to MapperProperty objects
1438        self._props = util.OrderedDict()
1439
1440        # table columns mapped to lists of MapperProperty objects
1441        # using a list allows a single column to be defined as
1442        # populating multiple object attributes
1443        self._columntoproperty = _ColumnMapping(self)
1444
1445        # load custom properties
1446        if self._init_properties:
1447            for key, prop in self._init_properties.items():
1448                self._configure_property(key, prop, False)
1449
1450        # pull properties from the inherited mapper if any.
1451        if self.inherits:
1452            for key, prop in self.inherits._props.items():
1453                if key not in self._props and not self._should_exclude(
1454                    key, key, local=False, column=None
1455                ):
1456                    self._adapt_inherited_property(key, prop, False)
1457
1458        # create properties for each column in the mapped table,
1459        # for those columns which don't already map to a property
1460        for column in self.mapped_table.columns:
1461            if column in self._columntoproperty:
1462                continue
1463
1464            column_key = (self.column_prefix or "") + column.key
1465
1466            if self._should_exclude(
1467                column.key,
1468                column_key,
1469                local=self.local_table.c.contains_column(column),
1470                column=column,
1471            ):
1472                continue
1473
1474            # adjust the "key" used for this column to that
1475            # of the inheriting mapper
1476            for mapper in self.iterate_to_root():
1477                if column in mapper._columntoproperty:
1478                    column_key = mapper._columntoproperty[column].key
1479
1480            self._configure_property(
1481                column_key, column, init=False, setparent=True
1482            )
1483
1484    def _configure_polymorphic_setter(self, init=False):
1485        """Configure an attribute on the mapper representing the
1486        'polymorphic_on' column, if applicable, and not
1487        already generated by _configure_properties (which is typical).
1488
1489        Also create a setter function which will assign this
1490        attribute to the value of the 'polymorphic_identity'
1491        upon instance construction, also if applicable.  This
1492        routine will run when an instance is created.
1493
1494        """
1495        setter = False
1496
1497        if self.polymorphic_on is not None:
1498            setter = True
1499
1500            if isinstance(self.polymorphic_on, util.string_types):
1501                # polymorphic_on specified as a string - link
1502                # it to mapped ColumnProperty
1503                try:
1504                    self.polymorphic_on = self._props[self.polymorphic_on]
1505                except KeyError:
1506                    raise sa_exc.ArgumentError(
1507                        "Can't determine polymorphic_on "
1508                        "value '%s' - no attribute is "
1509                        "mapped to this name." % self.polymorphic_on
1510                    )
1511
1512            if self.polymorphic_on in self._columntoproperty:
1513                # polymorphic_on is a column that is already mapped
1514                # to a ColumnProperty
1515                prop = self._columntoproperty[self.polymorphic_on]
1516            elif isinstance(self.polymorphic_on, MapperProperty):
1517                # polymorphic_on is directly a MapperProperty,
1518                # ensure it's a ColumnProperty
1519                if not isinstance(
1520                    self.polymorphic_on, properties.ColumnProperty
1521                ):
1522                    raise sa_exc.ArgumentError(
1523                        "Only direct column-mapped "
1524                        "property or SQL expression "
1525                        "can be passed for polymorphic_on"
1526                    )
1527                prop = self.polymorphic_on
1528            elif not expression._is_column(self.polymorphic_on):
1529                # polymorphic_on is not a Column and not a ColumnProperty;
1530                # not supported right now.
1531                raise sa_exc.ArgumentError(
1532                    "Only direct column-mapped "
1533                    "property or SQL expression "
1534                    "can be passed for polymorphic_on"
1535                )
1536            else:
1537                # polymorphic_on is a Column or SQL expression and
1538                # doesn't appear to be mapped. this means it can be 1.
1539                # only present in the with_polymorphic selectable or
1540                # 2. a totally standalone SQL expression which we'd
1541                # hope is compatible with this mapper's mapped_table
1542                col = self.mapped_table.corresponding_column(
1543                    self.polymorphic_on
1544                )
1545                if col is None:
1546                    # polymorphic_on doesn't derive from any
1547                    # column/expression isn't present in the mapped
1548                    # table. we will make a "hidden" ColumnProperty
1549                    # for it. Just check that if it's directly a
1550                    # schema.Column and we have with_polymorphic, it's
1551                    # likely a user error if the schema.Column isn't
1552                    # represented somehow in either mapped_table or
1553                    # with_polymorphic.   Otherwise as of 0.7.4 we
1554                    # just go with it and assume the user wants it
1555                    # that way (i.e. a CASE statement)
1556                    setter = False
1557                    instrument = False
1558                    col = self.polymorphic_on
1559                    if isinstance(col, schema.Column) and (
1560                        self.with_polymorphic is None
1561                        or self.with_polymorphic[1].corresponding_column(col)
1562                        is None
1563                    ):
1564                        raise sa_exc.InvalidRequestError(
1565                            "Could not map polymorphic_on column "
1566                            "'%s' to the mapped table - polymorphic "
1567                            "loads will not function properly"
1568                            % col.description
1569                        )
1570                else:
1571                    # column/expression that polymorphic_on derives from
1572                    # is present in our mapped table
1573                    # and is probably mapped, but polymorphic_on itself
1574                    # is not.  This happens when
1575                    # the polymorphic_on is only directly present in the
1576                    # with_polymorphic selectable, as when use
1577                    # polymorphic_union.
1578                    # we'll make a separate ColumnProperty for it.
1579                    instrument = True
1580                key = getattr(col, "key", None)
1581                if key:
1582                    if self._should_exclude(col.key, col.key, False, col):
1583                        raise sa_exc.InvalidRequestError(
1584                            "Cannot exclude or override the "
1585                            "discriminator column %r" % col.key
1586                        )
1587                else:
1588                    self.polymorphic_on = col = col.label("_sa_polymorphic_on")
1589                    key = col.key
1590
1591                prop = properties.ColumnProperty(col, _instrument=instrument)
1592                self._configure_property(key, prop, init=init, setparent=True)
1593
1594            # the actual polymorphic_on should be the first public-facing
1595            # column in the property
1596            self.polymorphic_on = prop.columns[0]
1597            polymorphic_key = prop.key
1598
1599        else:
1600            # no polymorphic_on was set.
1601            # check inheriting mappers for one.
1602            for mapper in self.iterate_to_root():
1603                # determine if polymorphic_on of the parent
1604                # should be propagated here.   If the col
1605                # is present in our mapped table, or if our mapped
1606                # table is the same as the parent (i.e. single table
1607                # inheritance), we can use it
1608                if mapper.polymorphic_on is not None:
1609                    if self.mapped_table is mapper.mapped_table:
1610                        self.polymorphic_on = mapper.polymorphic_on
1611                    else:
1612                        self.polymorphic_on = (
1613                            self.mapped_table.corresponding_column
1614                        )(mapper.polymorphic_on)
1615                    # we can use the parent mapper's _set_polymorphic_identity
1616                    # directly; it ensures the polymorphic_identity of the
1617                    # instance's mapper is used so is portable to subclasses.
1618                    if self.polymorphic_on is not None:
1619                        self._set_polymorphic_identity = (
1620                            mapper._set_polymorphic_identity
1621                        )
1622                        self._validate_polymorphic_identity = (
1623                            mapper._validate_polymorphic_identity
1624                        )
1625                    else:
1626                        self._set_polymorphic_identity = None
1627                    return
1628
1629        if setter:
1630
1631            def _set_polymorphic_identity(state):
1632                dict_ = state.dict
1633                state.get_impl(polymorphic_key).set(
1634                    state,
1635                    dict_,
1636                    state.manager.mapper.polymorphic_identity,
1637                    None,
1638                )
1639
1640            def _validate_polymorphic_identity(mapper, state, dict_):
1641                if (
1642                    polymorphic_key in dict_
1643                    and dict_[polymorphic_key]
1644                    not in mapper._acceptable_polymorphic_identities
1645                ):
1646                    util.warn_limited(
1647                        "Flushing object %s with "
1648                        "incompatible polymorphic identity %r; the "
1649                        "object may not refresh and/or load correctly",
1650                        (state_str(state), dict_[polymorphic_key]),
1651                    )
1652
1653            self._set_polymorphic_identity = _set_polymorphic_identity
1654            self._validate_polymorphic_identity = (
1655                _validate_polymorphic_identity
1656            )
1657        else:
1658            self._set_polymorphic_identity = None
1659
1660    _validate_polymorphic_identity = None
1661
1662    @_memoized_configured_property
1663    def _version_id_prop(self):
1664        if self.version_id_col is not None:
1665            return self._columntoproperty[self.version_id_col]
1666        else:
1667            return None
1668
1669    @_memoized_configured_property
1670    def _acceptable_polymorphic_identities(self):
1671        identities = set()
1672
1673        stack = deque([self])
1674        while stack:
1675            item = stack.popleft()
1676            if item.mapped_table is self.mapped_table:
1677                identities.add(item.polymorphic_identity)
1678                stack.extend(item._inheriting_mappers)
1679
1680        return identities
1681
1682    @_memoized_configured_property
1683    def _prop_set(self):
1684        return frozenset(self._props.values())
1685
1686    def _adapt_inherited_property(self, key, prop, init):
1687        if not self.concrete:
1688            self._configure_property(key, prop, init=False, setparent=False)
1689        elif key not in self._props:
1690            # determine if the class implements this attribute; if not,
1691            # or if it is implemented by the attribute that is handling the
1692            # given superclass-mapped property, then we need to report that we
1693            # can't use this at the instance level since we are a concrete
1694            # mapper and we don't map this.  don't trip user-defined
1695            # descriptors that might have side effects when invoked.
1696            implementing_attribute = self.class_manager._get_class_attr_mro(
1697                key, prop
1698            )
1699            if implementing_attribute is prop or (
1700                isinstance(
1701                    implementing_attribute, attributes.InstrumentedAttribute
1702                )
1703                and implementing_attribute._parententity is prop.parent
1704            ):
1705                self._configure_property(
1706                    key,
1707                    properties.ConcreteInheritedProperty(),
1708                    init=init,
1709                    setparent=True,
1710                )
1711
1712    def _configure_property(self, key, prop, init=True, setparent=True):
1713        self._log("_configure_property(%s, %s)", key, prop.__class__.__name__)
1714
1715        if not isinstance(prop, MapperProperty):
1716            prop = self._property_from_column(key, prop)
1717
1718        if isinstance(prop, properties.ColumnProperty):
1719            col = self.mapped_table.corresponding_column(prop.columns[0])
1720
1721            # if the column is not present in the mapped table,
1722            # test if a column has been added after the fact to the
1723            # parent table (or their parent, etc.) [ticket:1570]
1724            if col is None and self.inherits:
1725                path = [self]
1726                for m in self.inherits.iterate_to_root():
1727                    col = m.local_table.corresponding_column(prop.columns[0])
1728                    if col is not None:
1729                        for m2 in path:
1730                            m2.mapped_table._reset_exported()
1731                        col = self.mapped_table.corresponding_column(
1732                            prop.columns[0]
1733                        )
1734                        break
1735                    path.append(m)
1736
1737            # subquery expression, column not present in the mapped
1738            # selectable.
1739            if col is None:
1740                col = prop.columns[0]
1741
1742                # column is coming in after _readonly_props was
1743                # initialized; check for 'readonly'
1744                if hasattr(self, "_readonly_props") and (
1745                    not hasattr(col, "table")
1746                    or col.table not in self._cols_by_table
1747                ):
1748                    self._readonly_props.add(prop)
1749
1750            else:
1751                # if column is coming in after _cols_by_table was
1752                # initialized, ensure the col is in the right set
1753                if (
1754                    hasattr(self, "_cols_by_table")
1755                    and col.table in self._cols_by_table
1756                    and col not in self._cols_by_table[col.table]
1757                ):
1758                    self._cols_by_table[col.table].add(col)
1759
1760            # if this properties.ColumnProperty represents the "polymorphic
1761            # discriminator" column, mark it.  We'll need this when rendering
1762            # columns in SELECT statements.
1763            if not hasattr(prop, "_is_polymorphic_discriminator"):
1764                prop._is_polymorphic_discriminator = (
1765                    col is self.polymorphic_on
1766                    or prop.columns[0] is self.polymorphic_on
1767                )
1768
1769            self.columns[key] = col
1770            for col in prop.columns + prop._orig_columns:
1771                for col in col.proxy_set:
1772                    self._columntoproperty[col] = prop
1773
1774        prop.key = key
1775
1776        if setparent:
1777            prop.set_parent(self, init)
1778
1779        if key in self._props and getattr(
1780            self._props[key], "_mapped_by_synonym", False
1781        ):
1782            syn = self._props[key]._mapped_by_synonym
1783            raise sa_exc.ArgumentError(
1784                "Can't call map_column=True for synonym %r=%r, "
1785                "a ColumnProperty already exists keyed to the name "
1786                "%r for column %r" % (syn, key, key, syn)
1787            )
1788
1789        if (
1790            key in self._props
1791            and not isinstance(prop, properties.ColumnProperty)
1792            and not isinstance(
1793                self._props[key],
1794                (
1795                    properties.ColumnProperty,
1796                    properties.ConcreteInheritedProperty,
1797                ),
1798            )
1799        ):
1800            util.warn(
1801                "Property %s on %s being replaced with new "
1802                "property %s; the old property will be discarded"
1803                % (self._props[key], self, prop)
1804            )
1805            oldprop = self._props[key]
1806            self._path_registry.pop(oldprop, None)
1807
1808        self._props[key] = prop
1809
1810        if not self.non_primary:
1811            prop.instrument_class(self)
1812
1813        for mapper in self._inheriting_mappers:
1814            mapper._adapt_inherited_property(key, prop, init)
1815
1816        if init:
1817            prop.init()
1818            prop.post_instrument_class(self)
1819
1820        if self.configured:
1821            self._expire_memoizations()
1822
1823    def _property_from_column(self, key, prop):
1824        """generate/update a :class:`.ColumnProprerty` given a
1825        :class:`.Column` object. """
1826
1827        # we were passed a Column or a list of Columns;
1828        # generate a properties.ColumnProperty
1829        columns = util.to_list(prop)
1830        column = columns[0]
1831        if not expression._is_column(column):
1832            raise sa_exc.ArgumentError(
1833                "%s=%r is not an instance of MapperProperty or Column"
1834                % (key, prop)
1835            )
1836
1837        prop = self._props.get(key, None)
1838
1839        if isinstance(prop, properties.ColumnProperty):
1840            if (
1841                (
1842                    not self._inherits_equated_pairs
1843                    or (prop.columns[0], column)
1844                    not in self._inherits_equated_pairs
1845                )
1846                and not prop.columns[0].shares_lineage(column)
1847                and prop.columns[0] is not self.version_id_col
1848                and column is not self.version_id_col
1849            ):
1850                warn_only = prop.parent is not self
1851                msg = (
1852                    "Implicitly combining column %s with column "
1853                    "%s under attribute '%s'.  Please configure one "
1854                    "or more attributes for these same-named columns "
1855                    "explicitly." % (prop.columns[-1], column, key)
1856                )
1857                if warn_only:
1858                    util.warn(msg)
1859                else:
1860                    raise sa_exc.InvalidRequestError(msg)
1861
1862            # existing properties.ColumnProperty from an inheriting
1863            # mapper. make a copy and append our column to it
1864            prop = prop.copy()
1865            prop.columns.insert(0, column)
1866            self._log(
1867                "inserting column to existing list "
1868                "in properties.ColumnProperty %s" % (key)
1869            )
1870            return prop
1871        elif prop is None or isinstance(
1872            prop, properties.ConcreteInheritedProperty
1873        ):
1874            mapped_column = []
1875            for c in columns:
1876                mc = self.mapped_table.corresponding_column(c)
1877                if mc is None:
1878                    mc = self.local_table.corresponding_column(c)
1879                    if mc is not None:
1880                        # if the column is in the local table but not the
1881                        # mapped table, this corresponds to adding a
1882                        # column after the fact to the local table.
1883                        # [ticket:1523]
1884                        self.mapped_table._reset_exported()
1885                    mc = self.mapped_table.corresponding_column(c)
1886                    if mc is None:
1887                        raise sa_exc.ArgumentError(
1888                            "When configuring property '%s' on %s, "
1889                            "column '%s' is not represented in the mapper's "
1890                            "table. Use the `column_property()` function to "
1891                            "force this column to be mapped as a read-only "
1892                            "attribute." % (key, self, c)
1893                        )
1894                mapped_column.append(mc)
1895            return properties.ColumnProperty(*mapped_column)
1896        else:
1897            raise sa_exc.ArgumentError(
1898                "WARNING: when configuring property '%s' on %s, "
1899                "column '%s' conflicts with property '%r'. "
1900                "To resolve this, map the column to the class under a "
1901                "different name in the 'properties' dictionary.  Or, "
1902                "to remove all awareness of the column entirely "
1903                "(including its availability as a foreign key), "
1904                "use the 'include_properties' or 'exclude_properties' "
1905                "mapper arguments to control specifically which table "
1906                "columns get mapped." % (key, self, column.key, prop)
1907            )
1908
1909    def _post_configure_properties(self):
1910        """Call the ``init()`` method on all ``MapperProperties``
1911        attached to this mapper.
1912
1913        This is a deferred configuration step which is intended
1914        to execute once all mappers have been constructed.
1915
1916        """
1917
1918        self._log("_post_configure_properties() started")
1919        l = [(key, prop) for key, prop in self._props.items()]
1920        for key, prop in l:
1921            self._log("initialize prop %s", key)
1922
1923            if prop.parent is self and not prop._configure_started:
1924                prop.init()
1925
1926            if prop._configure_finished:
1927                prop.post_instrument_class(self)
1928
1929        self._log("_post_configure_properties() complete")
1930        self.configured = True
1931
1932    def add_properties(self, dict_of_properties):
1933        """Add the given dictionary of properties to this mapper,
1934        using `add_property`.
1935
1936        """
1937        for key, value in dict_of_properties.items():
1938            self.add_property(key, value)
1939
1940    def add_property(self, key, prop):
1941        """Add an individual MapperProperty to this mapper.
1942
1943        If the mapper has not been configured yet, just adds the
1944        property to the initial properties dictionary sent to the
1945        constructor.  If this Mapper has already been configured, then
1946        the given MapperProperty is configured immediately.
1947
1948        """
1949        self._init_properties[key] = prop
1950        self._configure_property(key, prop, init=self.configured)
1951
1952    def _expire_memoizations(self):
1953        for mapper in self.iterate_to_root():
1954            _memoized_configured_property.expire_instance(mapper)
1955
1956    @property
1957    def _log_desc(self):
1958        return (
1959            "("
1960            + self.class_.__name__
1961            + "|"
1962            + (
1963                self.local_table is not None
1964                and self.local_table.description
1965                or str(self.local_table)
1966            )
1967            + (self.non_primary and "|non-primary" or "")
1968            + ")"
1969        )
1970
1971    def _log(self, msg, *args):
1972        self.logger.info("%s " + msg, *((self._log_desc,) + args))
1973
1974    def _log_debug(self, msg, *args):
1975        self.logger.debug("%s " + msg, *((self._log_desc,) + args))
1976
1977    def __repr__(self):
1978        return "<Mapper at 0x%x; %s>" % (id(self), self.class_.__name__)
1979
1980    def __str__(self):
1981        return "Mapper|%s|%s%s" % (
1982            self.class_.__name__,
1983            self.local_table is not None
1984            and self.local_table.description
1985            or None,
1986            self.non_primary and "|non-primary" or "",
1987        )
1988
1989    def _is_orphan(self, state):
1990        orphan_possible = False
1991        for mapper in self.iterate_to_root():
1992            for (key, cls) in mapper._delete_orphans:
1993                orphan_possible = True
1994
1995                has_parent = attributes.manager_of_class(cls).has_parent(
1996                    state, key, optimistic=state.has_identity
1997                )
1998
1999                if self.legacy_is_orphan and has_parent:
2000                    return False
2001                elif not self.legacy_is_orphan and not has_parent:
2002                    return True
2003
2004        if self.legacy_is_orphan:
2005            return orphan_possible
2006        else:
2007            return False
2008
2009    def has_property(self, key):
2010        return key in self._props
2011
2012    def get_property(self, key, _configure_mappers=True):
2013        """return a MapperProperty associated with the given key.
2014        """
2015
2016        if _configure_mappers and Mapper._new_mappers:
2017            configure_mappers()
2018
2019        try:
2020            return self._props[key]
2021        except KeyError:
2022            raise sa_exc.InvalidRequestError(
2023                "Mapper '%s' has no property '%s'" % (self, key)
2024            )
2025
2026    def get_property_by_column(self, column):
2027        """Given a :class:`.Column` object, return the
2028        :class:`.MapperProperty` which maps this column."""
2029
2030        return self._columntoproperty[column]
2031
2032    @property
2033    def iterate_properties(self):
2034        """return an iterator of all MapperProperty objects."""
2035        if Mapper._new_mappers:
2036            configure_mappers()
2037        return iter(self._props.values())
2038
2039    def _mappers_from_spec(self, spec, selectable):
2040        """given a with_polymorphic() argument, return the set of mappers it
2041        represents.
2042
2043        Trims the list of mappers to just those represented within the given
2044        selectable, if present. This helps some more legacy-ish mappings.
2045
2046        """
2047        if spec == "*":
2048            mappers = list(self.self_and_descendants)
2049        elif spec:
2050            mappers = set()
2051            for m in util.to_list(spec):
2052                m = _class_to_mapper(m)
2053                if not m.isa(self):
2054                    raise sa_exc.InvalidRequestError(
2055                        "%r does not inherit from %r" % (m, self)
2056                    )
2057
2058                if selectable is None:
2059                    mappers.update(m.iterate_to_root())
2060                else:
2061                    mappers.add(m)
2062            mappers = [m for m in self.self_and_descendants if m in mappers]
2063        else:
2064            mappers = []
2065
2066        if selectable is not None:
2067            tables = set(
2068                sql_util.find_tables(selectable, include_aliases=True)
2069            )
2070            mappers = [m for m in mappers if m.local_table in tables]
2071        return mappers
2072
2073    def _selectable_from_mappers(self, mappers, innerjoin):
2074        """given a list of mappers (assumed to be within this mapper's
2075        inheritance hierarchy), construct an outerjoin amongst those mapper's
2076        mapped tables.
2077
2078        """
2079        from_obj = self.mapped_table
2080        for m in mappers:
2081            if m is self:
2082                continue
2083            if m.concrete:
2084                raise sa_exc.InvalidRequestError(
2085                    "'with_polymorphic()' requires 'selectable' argument "
2086                    "when concrete-inheriting mappers are used."
2087                )
2088            elif not m.single:
2089                if innerjoin:
2090                    from_obj = from_obj.join(
2091                        m.local_table, m.inherit_condition
2092                    )
2093                else:
2094                    from_obj = from_obj.outerjoin(
2095                        m.local_table, m.inherit_condition
2096                    )
2097
2098        return from_obj
2099
2100    @_memoized_configured_property
2101    def _single_table_criterion(self):
2102        if self.single and self.inherits and self.polymorphic_on is not None:
2103            return self.polymorphic_on._annotate({"parentmapper": self}).in_(
2104                m.polymorphic_identity for m in self.self_and_descendants
2105            )
2106        else:
2107            return None
2108
2109    @_memoized_configured_property
2110    def _with_polymorphic_mappers(self):
2111        if Mapper._new_mappers:
2112            configure_mappers()
2113        if not self.with_polymorphic:
2114            return []
2115        return self._mappers_from_spec(*self.with_polymorphic)
2116
2117    @_memoized_configured_property
2118    def _with_polymorphic_selectable(self):
2119        if not self.with_polymorphic:
2120            return self.mapped_table
2121
2122        spec, selectable = self.with_polymorphic
2123        if selectable is not None:
2124            return selectable
2125        else:
2126            return self._selectable_from_mappers(
2127                self._mappers_from_spec(spec, selectable), False
2128            )
2129
2130    with_polymorphic_mappers = _with_polymorphic_mappers
2131    """The list of :class:`.Mapper` objects included in the
2132    default "polymorphic" query.
2133
2134    """
2135
2136    @_memoized_configured_property
2137    def _insert_cols_evaluating_none(self):
2138        return dict(
2139            (
2140                table,
2141                frozenset(
2142                    col for col in columns if col.type.should_evaluate_none
2143                ),
2144            )
2145            for table, columns in self._cols_by_table.items()
2146        )
2147
2148    @_memoized_configured_property
2149    def _insert_cols_as_none(self):
2150        return dict(
2151            (
2152                table,
2153                frozenset(
2154                    col.key
2155                    for col in columns
2156                    if not col.primary_key
2157                    and not col.server_default
2158                    and not col.default
2159                    and not col.type.should_evaluate_none
2160                ),
2161            )
2162            for table, columns in self._cols_by_table.items()
2163        )
2164
2165    @_memoized_configured_property
2166    def _propkey_to_col(self):
2167        return dict(
2168            (
2169                table,
2170                dict(
2171                    (self._columntoproperty[col].key, col) for col in columns
2172                ),
2173            )
2174            for table, columns in self._cols_by_table.items()
2175        )
2176
2177    @_memoized_configured_property
2178    def _pk_keys_by_table(self):
2179        return dict(
2180            (table, frozenset([col.key for col in pks]))
2181            for table, pks in self._pks_by_table.items()
2182        )
2183
2184    @_memoized_configured_property
2185    def _pk_attr_keys_by_table(self):
2186        return dict(
2187            (
2188                table,
2189                frozenset([self._columntoproperty[col].key for col in pks]),
2190            )
2191            for table, pks in self._pks_by_table.items()
2192        )
2193
2194    @_memoized_configured_property
2195    def _server_default_cols(self):
2196        return dict(
2197            (
2198                table,
2199                frozenset(
2200                    [
2201                        col.key
2202                        for col in columns
2203                        if col.server_default is not None
2204                    ]
2205                ),
2206            )
2207            for table, columns in self._cols_by_table.items()
2208        )
2209
2210    @_memoized_configured_property
2211    def _server_default_plus_onupdate_propkeys(self):
2212        result = set()
2213
2214        for table, columns in self._cols_by_table.items():
2215            for col in columns:
2216                if (
2217                    col.server_default is not None
2218                    or col.server_onupdate is not None
2219                ) and col in self._columntoproperty:
2220                    result.add(self._columntoproperty[col].key)
2221
2222        return result
2223
2224    @_memoized_configured_property
2225    def _server_onupdate_default_cols(self):
2226        return dict(
2227            (
2228                table,
2229                frozenset(
2230                    [
2231                        col.key
2232                        for col in columns
2233                        if col.server_onupdate is not None
2234                    ]
2235                ),
2236            )
2237            for table, columns in self._cols_by_table.items()
2238        )
2239
2240    @property
2241    def selectable(self):
2242        """The :func:`.select` construct this :class:`.Mapper` selects from
2243        by default.
2244
2245        Normally, this is equivalent to :attr:`.mapped_table`, unless
2246        the ``with_polymorphic`` feature is in use, in which case the
2247        full "polymorphic" selectable is returned.
2248
2249        """
2250        return self._with_polymorphic_selectable
2251
2252    def _with_polymorphic_args(
2253        self, spec=None, selectable=False, innerjoin=False
2254    ):
2255        if self.with_polymorphic:
2256            if not spec:
2257                spec = self.with_polymorphic[0]
2258            if selectable is False:
2259                selectable = self.with_polymorphic[1]
2260        elif selectable is False:
2261            selectable = None
2262        mappers = self._mappers_from_spec(spec, selectable)
2263        if selectable is not None:
2264            return mappers, selectable
2265        else:
2266            return mappers, self._selectable_from_mappers(mappers, innerjoin)
2267
2268    @_memoized_configured_property
2269    def _polymorphic_properties(self):
2270        return list(
2271            self._iterate_polymorphic_properties(
2272                self._with_polymorphic_mappers
2273            )
2274        )
2275
2276    def _iterate_polymorphic_properties(self, mappers=None):
2277        """Return an iterator of MapperProperty objects which will render into
2278        a SELECT."""
2279        if mappers is None:
2280            mappers = self._with_polymorphic_mappers
2281
2282        if not mappers:
2283            for c in self.iterate_properties:
2284                yield c
2285        else:
2286            # in the polymorphic case, filter out discriminator columns
2287            # from other mappers, as these are sometimes dependent on that
2288            # mapper's polymorphic selectable (which we don't want rendered)
2289            for c in util.unique_list(
2290                chain(
2291                    *[
2292                        list(mapper.iterate_properties)
2293                        for mapper in [self] + mappers
2294                    ]
2295                )
2296            ):
2297                if getattr(c, "_is_polymorphic_discriminator", False) and (
2298                    self.polymorphic_on is None
2299                    or c.columns[0] is not self.polymorphic_on
2300                ):
2301                    continue
2302                yield c
2303
2304    @_memoized_configured_property
2305    def attrs(self):
2306        """A namespace of all :class:`.MapperProperty` objects
2307        associated this mapper.
2308
2309        This is an object that provides each property based on
2310        its key name.  For instance, the mapper for a
2311        ``User`` class which has ``User.name`` attribute would
2312        provide ``mapper.attrs.name``, which would be the
2313        :class:`.ColumnProperty` representing the ``name``
2314        column.   The namespace object can also be iterated,
2315        which would yield each :class:`.MapperProperty`.
2316
2317        :class:`.Mapper` has several pre-filtered views
2318        of this attribute which limit the types of properties
2319        returned, including :attr:`.synonyms`, :attr:`.column_attrs`,
2320        :attr:`.relationships`, and :attr:`.composites`.
2321
2322        .. warning::
2323
2324            The :attr:`.Mapper.attrs` accessor namespace is an
2325            instance of :class:`.OrderedProperties`.  This is
2326            a dictionary-like object which includes a small number of
2327            named methods such as :meth:`.OrderedProperties.items`
2328            and :meth:`.OrderedProperties.values`.  When
2329            accessing attributes dynamically, favor using the dict-access
2330            scheme, e.g. ``mapper.attrs[somename]`` over
2331            ``getattr(mapper.attrs, somename)`` to avoid name collisions.
2332
2333        .. seealso::
2334
2335            :attr:`.Mapper.all_orm_descriptors`
2336
2337        """
2338        if Mapper._new_mappers:
2339            configure_mappers()
2340        return util.ImmutableProperties(self._props)
2341
2342    @_memoized_configured_property
2343    def all_orm_descriptors(self):
2344        """A namespace of all :class:`.InspectionAttr` attributes associated
2345        with the mapped class.
2346
2347        These attributes are in all cases Python :term:`descriptors`
2348        associated with the mapped class or its superclasses.
2349
2350        This namespace includes attributes that are mapped to the class
2351        as well as attributes declared by extension modules.
2352        It includes any Python descriptor type that inherits from
2353        :class:`.InspectionAttr`.  This includes
2354        :class:`.QueryableAttribute`, as well as extension types such as
2355        :class:`.hybrid_property`, :class:`.hybrid_method` and
2356        :class:`.AssociationProxy`.
2357
2358        To distinguish between mapped attributes and extension attributes,
2359        the attribute :attr:`.InspectionAttr.extension_type` will refer
2360        to a constant that distinguishes between different extension types.
2361
2362        When dealing with a :class:`.QueryableAttribute`, the
2363        :attr:`.QueryableAttribute.property` attribute refers to the
2364        :class:`.MapperProperty` property, which is what you get when
2365        referring to the collection of mapped properties via
2366        :attr:`.Mapper.attrs`.
2367
2368        .. warning::
2369
2370            The :attr:`.Mapper.all_orm_descriptors` accessor namespace is an
2371            instance of :class:`.OrderedProperties`.  This is
2372            a dictionary-like object which includes a small number of
2373            named methods such as :meth:`.OrderedProperties.items`
2374            and :meth:`.OrderedProperties.values`.  When
2375            accessing attributes dynamically, favor using the dict-access
2376            scheme, e.g. ``mapper.all_orm_descriptors[somename]`` over
2377            ``getattr(mapper.all_orm_descriptors, somename)`` to avoid name
2378            collisions.
2379
2380        .. seealso::
2381
2382            :attr:`.Mapper.attrs`
2383
2384        """
2385        return util.ImmutableProperties(
2386            dict(self.class_manager._all_sqla_attributes())
2387        )
2388
2389    @_memoized_configured_property
2390    def synonyms(self):
2391        """Return a namespace of all :class:`.SynonymProperty`
2392        properties maintained by this :class:`.Mapper`.
2393
2394        .. seealso::
2395
2396            :attr:`.Mapper.attrs` - namespace of all :class:`.MapperProperty`
2397            objects.
2398
2399        """
2400        return self._filter_properties(properties.SynonymProperty)
2401
2402    @_memoized_configured_property
2403    def column_attrs(self):
2404        """Return a namespace of all :class:`.ColumnProperty`
2405        properties maintained by this :class:`.Mapper`.
2406
2407        .. seealso::
2408
2409            :attr:`.Mapper.attrs` - namespace of all :class:`.MapperProperty`
2410            objects.
2411
2412        """
2413        return self._filter_properties(properties.ColumnProperty)
2414
2415    @_memoized_configured_property
2416    def relationships(self):
2417        """A namespace of all :class:`.RelationshipProperty` properties
2418        maintained by this :class:`.Mapper`.
2419
2420        .. warning::
2421
2422            the :attr:`.Mapper.relationships` accessor namespace is an
2423            instance of :class:`.OrderedProperties`.  This is
2424            a dictionary-like object which includes a small number of
2425            named methods such as :meth:`.OrderedProperties.items`
2426            and :meth:`.OrderedProperties.values`.  When
2427            accessing attributes dynamically, favor using the dict-access
2428            scheme, e.g. ``mapper.relationships[somename]`` over
2429            ``getattr(mapper.relationships, somename)`` to avoid name
2430            collisions.
2431
2432        .. seealso::
2433
2434            :attr:`.Mapper.attrs` - namespace of all :class:`.MapperProperty`
2435            objects.
2436
2437        """
2438        return self._filter_properties(properties.RelationshipProperty)
2439
2440    @_memoized_configured_property
2441    def composites(self):
2442        """Return a namespace of all :class:`.CompositeProperty`
2443        properties maintained by this :class:`.Mapper`.
2444
2445        .. seealso::
2446
2447            :attr:`.Mapper.attrs` - namespace of all :class:`.MapperProperty`
2448            objects.
2449
2450        """
2451        return self._filter_properties(properties.CompositeProperty)
2452
2453    def _filter_properties(self, type_):
2454        if Mapper._new_mappers:
2455            configure_mappers()
2456        return util.ImmutableProperties(
2457            util.OrderedDict(
2458                (k, v) for k, v in self._props.items() if isinstance(v, type_)
2459            )
2460        )
2461
2462    @_memoized_configured_property
2463    def _get_clause(self):
2464        """create a "get clause" based on the primary key.  this is used
2465        by query.get() and many-to-one lazyloads to load this item
2466        by primary key.
2467
2468        """
2469        params = [
2470            (primary_key, sql.bindparam(None, type_=primary_key.type))
2471            for primary_key in self.primary_key
2472        ]
2473        return (
2474            sql.and_(*[k == v for (k, v) in params]),
2475            util.column_dict(params),
2476        )
2477
2478    @_memoized_configured_property
2479    def _equivalent_columns(self):
2480        """Create a map of all equivalent columns, based on
2481        the determination of column pairs that are equated to
2482        one another based on inherit condition.  This is designed
2483        to work with the queries that util.polymorphic_union
2484        comes up with, which often don't include the columns from
2485        the base table directly (including the subclass table columns
2486        only).
2487
2488        The resulting structure is a dictionary of columns mapped
2489        to lists of equivalent columns, e.g.::
2490
2491            {
2492                tablea.col1:
2493                    {tableb.col1, tablec.col1},
2494                tablea.col2:
2495                    {tabled.col2}
2496            }
2497
2498        """
2499        result = util.column_dict()
2500
2501        def visit_binary(binary):
2502            if binary.operator == operators.eq:
2503                if binary.left in result:
2504                    result[binary.left].add(binary.right)
2505                else:
2506                    result[binary.left] = util.column_set((binary.right,))
2507                if binary.right in result:
2508                    result[binary.right].add(binary.left)
2509                else:
2510                    result[binary.right] = util.column_set((binary.left,))
2511
2512        for mapper in self.base_mapper.self_and_descendants:
2513            if mapper.inherit_condition is not None:
2514                visitors.traverse(
2515                    mapper.inherit_condition, {}, {"binary": visit_binary}
2516                )
2517
2518        return result
2519
2520    def _is_userland_descriptor(self, obj):
2521        if isinstance(
2522            obj,
2523            (
2524                _MappedAttribute,
2525                instrumentation.ClassManager,
2526                expression.ColumnElement,
2527            ),
2528        ):
2529            return False
2530        else:
2531            return True
2532
2533    def _should_exclude(self, name, assigned_name, local, column):
2534        """determine whether a particular property should be implicitly
2535        present on the class.
2536
2537        This occurs when properties are propagated from an inherited class, or
2538        are applied from the columns present in the mapped table.
2539
2540        """
2541
2542        # check for class-bound attributes and/or descriptors,
2543        # either local or from an inherited class
2544        if local:
2545            if self.class_.__dict__.get(
2546                assigned_name, None
2547            ) is not None and self._is_userland_descriptor(
2548                self.class_.__dict__[assigned_name]
2549            ):
2550                return True
2551        else:
2552            attr = self.class_manager._get_class_attr_mro(assigned_name, None)
2553            if attr is not None and self._is_userland_descriptor(attr):
2554                return True
2555
2556        if (
2557            self.include_properties is not None
2558            and name not in self.include_properties
2559            and (column is None or column not in self.include_properties)
2560        ):
2561            self._log("not including property %s" % (name))
2562            return True
2563
2564        if self.exclude_properties is not None and (
2565            name in self.exclude_properties
2566            or (column is not None and column in self.exclude_properties)
2567        ):
2568            self._log("excluding property %s" % (name))
2569            return True
2570
2571        return False
2572
2573    def common_parent(self, other):
2574        """Return true if the given mapper shares a
2575        common inherited parent as this mapper."""
2576
2577        return self.base_mapper is other.base_mapper
2578
2579    def _canload(self, state, allow_subtypes):
2580        s = self.primary_mapper()
2581        if self.polymorphic_on is not None or allow_subtypes:
2582            return _state_mapper(state).isa(s)
2583        else:
2584            return _state_mapper(state) is s
2585
2586    def isa(self, other):
2587        """Return True if the this mapper inherits from the given mapper."""
2588
2589        m = self
2590        while m and m is not other:
2591            m = m.inherits
2592        return bool(m)
2593
2594    def iterate_to_root(self):
2595        m = self
2596        while m:
2597            yield m
2598            m = m.inherits
2599
2600    @_memoized_configured_property
2601    def self_and_descendants(self):
2602        """The collection including this mapper and all descendant mappers.
2603
2604        This includes not just the immediately inheriting mappers but
2605        all their inheriting mappers as well.
2606
2607        """
2608        descendants = []
2609        stack = deque([self])
2610        while stack:
2611            item = stack.popleft()
2612            descendants.append(item)
2613            stack.extend(item._inheriting_mappers)
2614        return util.WeakSequence(descendants)
2615
2616    def polymorphic_iterator(self):
2617        """Iterate through the collection including this mapper and
2618        all descendant mappers.
2619
2620        This includes not just the immediately inheriting mappers but
2621        all their inheriting mappers as well.
2622
2623        To iterate through an entire hierarchy, use
2624        ``mapper.base_mapper.polymorphic_iterator()``.
2625
2626        """
2627        return iter(self.self_and_descendants)
2628
2629    def primary_mapper(self):
2630        """Return the primary mapper corresponding to this mapper's class key
2631        (class)."""
2632
2633        return self.class_manager.mapper
2634
2635    @property
2636    def primary_base_mapper(self):
2637        return self.class_manager.mapper.base_mapper
2638
2639    def _result_has_identity_key(self, result, adapter=None):
2640        pk_cols = self.primary_key
2641        if adapter:
2642            pk_cols = [adapter.columns[c] for c in pk_cols]
2643        for col in pk_cols:
2644            if not result._has_key(col):
2645                return False
2646        else:
2647            return True
2648
2649    def identity_key_from_row(self, row, identity_token=None, adapter=None):
2650        """Return an identity-map key for use in storing/retrieving an
2651        item from the identity map.
2652
2653        :param row: A :class:`.RowProxy` instance.  The columns which are
2654         mapped by this :class:`.Mapper` should be locatable in the row,
2655         preferably via the :class:`.Column` object directly (as is the case
2656         when a :func:`.select` construct is executed), or via string names of
2657         the form ``<tablename>_<colname>``.
2658
2659        """
2660        pk_cols = self.primary_key
2661        if adapter:
2662            pk_cols = [adapter.columns[c] for c in pk_cols]
2663
2664        return (
2665            self._identity_class,
2666            tuple(row[column] for column in pk_cols),
2667            identity_token,
2668        )
2669
2670    def identity_key_from_primary_key(self, primary_key, identity_token=None):
2671        """Return an identity-map key for use in storing/retrieving an
2672        item from an identity map.
2673
2674        :param primary_key: A list of values indicating the identifier.
2675
2676        """
2677        return self._identity_class, tuple(primary_key), identity_token
2678
2679    def identity_key_from_instance(self, instance):
2680        """Return the identity key for the given instance, based on
2681        its primary key attributes.
2682
2683        If the instance's state is expired, calling this method
2684        will result in a database check to see if the object has been deleted.
2685        If the row no longer exists,
2686        :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised.
2687
2688        This value is typically also found on the instance state under the
2689        attribute name `key`.
2690
2691        """
2692        state = attributes.instance_state(instance)
2693        return self._identity_key_from_state(state, attributes.PASSIVE_OFF)
2694
2695    def _identity_key_from_state(
2696        self, state, passive=attributes.PASSIVE_RETURN_NEVER_SET
2697    ):
2698        dict_ = state.dict
2699        manager = state.manager
2700        return (
2701            self._identity_class,
2702            tuple(
2703                [
2704                    manager[prop.key].impl.get(state, dict_, passive)
2705                    for prop in self._identity_key_props
2706                ]
2707            ),
2708            state.identity_token,
2709        )
2710
2711    def primary_key_from_instance(self, instance):
2712        """Return the list of primary key values for the given
2713        instance.
2714
2715        If the instance's state is expired, calling this method
2716        will result in a database check to see if the object has been deleted.
2717        If the row no longer exists,
2718        :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised.
2719
2720        """
2721        state = attributes.instance_state(instance)
2722        identity_key = self._identity_key_from_state(
2723            state, attributes.PASSIVE_OFF
2724        )
2725        return identity_key[1]
2726
2727    @_memoized_configured_property
2728    def _identity_key_props(self):
2729        return [self._columntoproperty[col] for col in self.primary_key]
2730
2731    @_memoized_configured_property
2732    def _all_pk_props(self):
2733        collection = set()
2734        for table in self.tables:
2735            collection.update(self._pks_by_table[table])
2736        return collection
2737
2738    @_memoized_configured_property
2739    def _should_undefer_in_wildcard(self):
2740        cols = set(self.primary_key)
2741        if self.polymorphic_on is not None:
2742            cols.add(self.polymorphic_on)
2743        return cols
2744
2745    @_memoized_configured_property
2746    def _primary_key_propkeys(self):
2747        return {prop.key for prop in self._all_pk_props}
2748
2749    def _get_state_attr_by_column(
2750        self, state, dict_, column, passive=attributes.PASSIVE_RETURN_NEVER_SET
2751    ):
2752        prop = self._columntoproperty[column]
2753        return state.manager[prop.key].impl.get(state, dict_, passive=passive)
2754
2755    def _set_committed_state_attr_by_column(self, state, dict_, column, value):
2756        prop = self._columntoproperty[column]
2757        state.manager[prop.key].impl.set_committed_value(state, dict_, value)
2758
2759    def _set_state_attr_by_column(self, state, dict_, column, value):
2760        prop = self._columntoproperty[column]
2761        state.manager[prop.key].impl.set(state, dict_, value, None)
2762
2763    def _get_committed_attr_by_column(self, obj, column):
2764        state = attributes.instance_state(obj)
2765        dict_ = attributes.instance_dict(obj)
2766        return self._get_committed_state_attr_by_column(
2767            state, dict_, column, passive=attributes.PASSIVE_OFF
2768        )
2769
2770    def _get_committed_state_attr_by_column(
2771        self, state, dict_, column, passive=attributes.PASSIVE_RETURN_NEVER_SET
2772    ):
2773
2774        prop = self._columntoproperty[column]
2775        return state.manager[prop.key].impl.get_committed_value(
2776            state, dict_, passive=passive
2777        )
2778
2779    def _optimized_get_statement(self, state, attribute_names):
2780        """assemble a WHERE clause which retrieves a given state by primary
2781        key, using a minimized set of tables.
2782
2783        Applies to a joined-table inheritance mapper where the
2784        requested attribute names are only present on joined tables,
2785        not the base table.  The WHERE clause attempts to include
2786        only those tables to minimize joins.
2787
2788        """
2789        props = self._props
2790
2791        tables = set(
2792            chain(
2793                *[
2794                    sql_util.find_tables(c, check_columns=True)
2795                    for key in attribute_names
2796                    for c in props[key].columns
2797                ]
2798            )
2799        )
2800
2801        if self.base_mapper.local_table in tables:
2802            return None
2803
2804        class ColumnsNotAvailable(Exception):
2805            pass
2806
2807        def visit_binary(binary):
2808            leftcol = binary.left
2809            rightcol = binary.right
2810            if leftcol is None or rightcol is None:
2811                return
2812
2813            if leftcol.table not in tables:
2814                leftval = self._get_committed_state_attr_by_column(
2815                    state,
2816                    state.dict,
2817                    leftcol,
2818                    passive=attributes.PASSIVE_NO_INITIALIZE,
2819                )
2820                if leftval in orm_util._none_set:
2821                    raise ColumnsNotAvailable()
2822                binary.left = sql.bindparam(
2823                    None, leftval, type_=binary.right.type
2824                )
2825            elif rightcol.table not in tables:
2826                rightval = self._get_committed_state_attr_by_column(
2827                    state,
2828                    state.dict,
2829                    rightcol,
2830                    passive=attributes.PASSIVE_NO_INITIALIZE,
2831                )
2832                if rightval in orm_util._none_set:
2833                    raise ColumnsNotAvailable()
2834                binary.right = sql.bindparam(
2835                    None, rightval, type_=binary.right.type
2836                )
2837
2838        allconds = []
2839
2840        try:
2841            start = False
2842            for mapper in reversed(list(self.iterate_to_root())):
2843                if mapper.local_table in tables:
2844                    start = True
2845                elif not isinstance(
2846                    mapper.local_table, expression.TableClause
2847                ):
2848                    return None
2849                if start and not mapper.single:
2850                    allconds.append(
2851                        visitors.cloned_traverse(
2852                            mapper.inherit_condition,
2853                            {},
2854                            {"binary": visit_binary},
2855                        )
2856                    )
2857        except ColumnsNotAvailable:
2858            return None
2859
2860        cond = sql.and_(*allconds)
2861
2862        cols = []
2863        for key in attribute_names:
2864            cols.extend(props[key].columns)
2865        return sql.select(cols, cond, use_labels=True)
2866
2867    def _iterate_to_target_viawpoly(self, mapper):
2868        if self.isa(mapper):
2869            prev = self
2870            for m in self.iterate_to_root():
2871                yield m
2872
2873                if m is not prev and prev not in m._with_polymorphic_mappers:
2874                    break
2875
2876                prev = m
2877                if m is mapper:
2878                    break
2879
2880    def _should_selectin_load(self, enabled_via_opt, polymorphic_from):
2881        if not enabled_via_opt:
2882            # common case, takes place for all polymorphic loads
2883            mapper = polymorphic_from
2884            for m in self._iterate_to_target_viawpoly(mapper):
2885                if m.polymorphic_load == "selectin":
2886                    return m
2887        else:
2888            # uncommon case, selectin load options were used
2889            enabled_via_opt = set(enabled_via_opt)
2890            enabled_via_opt_mappers = {e.mapper: e for e in enabled_via_opt}
2891            for entity in enabled_via_opt.union([polymorphic_from]):
2892                mapper = entity.mapper
2893                for m in self._iterate_to_target_viawpoly(mapper):
2894                    if (
2895                        m.polymorphic_load == "selectin"
2896                        or m in enabled_via_opt_mappers
2897                    ):
2898                        return enabled_via_opt_mappers.get(m, m)
2899
2900        return None
2901
2902    @util.dependencies(
2903        "sqlalchemy.ext.baked", "sqlalchemy.orm.strategy_options"
2904    )
2905    def _subclass_load_via_in(self, baked, strategy_options, entity):
2906        """Assemble a BakedQuery that can load the columns local to
2907        this subclass as a SELECT with IN.
2908
2909        """
2910        assert self.inherits
2911
2912        polymorphic_prop = self._columntoproperty[self.polymorphic_on]
2913        keep_props = set([polymorphic_prop] + self._identity_key_props)
2914
2915        disable_opt = strategy_options.Load(entity)
2916        enable_opt = strategy_options.Load(entity)
2917
2918        for prop in self.attrs:
2919            if prop.parent is self or prop in keep_props:
2920                # "enable" options, to turn on the properties that we want to
2921                # load by default (subject to options from the query)
2922                enable_opt.set_generic_strategy(
2923                    (prop.key,), dict(prop.strategy_key)
2924                )
2925            else:
2926                # "disable" options, to turn off the properties from the
2927                # superclass that we *don't* want to load, applied after
2928                # the options from the query to override them
2929                disable_opt.set_generic_strategy(
2930                    (prop.key,), {"do_nothing": True}
2931                )
2932
2933        if len(self.primary_key) > 1:
2934            in_expr = sql.tuple_(*self.primary_key)
2935        else:
2936            in_expr = self.primary_key[0]
2937
2938        if entity.is_aliased_class:
2939            assert entity.mapper is self
2940            q = baked.BakedQuery(
2941                self._compiled_cache,
2942                lambda session: session.query(entity)
2943                .select_entity_from(entity.selectable)
2944                ._adapt_all_clauses(),
2945                (self,),
2946            )
2947            q.spoil()
2948        else:
2949            q = baked.BakedQuery(
2950                self._compiled_cache,
2951                lambda session: session.query(self),
2952                (self,),
2953            )
2954
2955        q += lambda q: q.filter(
2956            in_expr.in_(sql.bindparam("primary_keys", expanding=True))
2957        ).order_by(*self.primary_key)
2958
2959        return q, enable_opt, disable_opt
2960
2961    @_memoized_configured_property
2962    def _subclass_load_via_in_mapper(self):
2963        return self._subclass_load_via_in(self)
2964
2965    def cascade_iterator(self, type_, state, halt_on=None):
2966        """Iterate each element and its mapper in an object graph,
2967        for all relationships that meet the given cascade rule.
2968
2969        :param type_:
2970          The name of the cascade rule (i.e. ``"save-update"``, ``"delete"``,
2971          etc.).
2972
2973          .. note::  the ``"all"`` cascade is not accepted here.  For a generic
2974             object traversal function, see :ref:`faq_walk_objects`.
2975
2976        :param state:
2977          The lead InstanceState.  child items will be processed per
2978          the relationships defined for this object's mapper.
2979
2980        :return: the method yields individual object instances.
2981
2982        .. seealso::
2983
2984            :ref:`unitofwork_cascades`
2985
2986            :ref:`faq_walk_objects` - illustrates a generic function to
2987            traverse all objects without relying on cascades.
2988
2989        """
2990        visited_states = set()
2991        prp, mpp = object(), object()
2992
2993        assert state.mapper.isa(self)
2994
2995        visitables = deque(
2996            [(deque(state.mapper._props.values()), prp, state, state.dict)]
2997        )
2998
2999        while visitables:
3000            iterator, item_type, parent_state, parent_dict = visitables[-1]
3001            if not iterator:
3002                visitables.pop()
3003                continue
3004
3005            if item_type is prp:
3006                prop = iterator.popleft()
3007                if type_ not in prop.cascade:
3008                    continue
3009                queue = deque(
3010                    prop.cascade_iterator(
3011                        type_,
3012                        parent_state,
3013                        parent_dict,
3014                        visited_states,
3015                        halt_on,
3016                    )
3017                )
3018                if queue:
3019                    visitables.append((queue, mpp, None, None))
3020            elif item_type is mpp:
3021                (
3022                    instance,
3023                    instance_mapper,
3024                    corresponding_state,
3025                    corresponding_dict,
3026                ) = iterator.popleft()
3027                yield (
3028                    instance,
3029                    instance_mapper,
3030                    corresponding_state,
3031                    corresponding_dict,
3032                )
3033                visitables.append(
3034                    (
3035                        deque(instance_mapper._props.values()),
3036                        prp,
3037                        corresponding_state,
3038                        corresponding_dict,
3039                    )
3040                )
3041
3042    @_memoized_configured_property
3043    def _compiled_cache(self):
3044        return util.LRUCache(self._compiled_cache_size)
3045
3046    @_memoized_configured_property
3047    def _sorted_tables(self):
3048        table_to_mapper = {}
3049
3050        for mapper in self.base_mapper.self_and_descendants:
3051            for t in mapper.tables:
3052                table_to_mapper.setdefault(t, mapper)
3053
3054        extra_dependencies = []
3055        for table, mapper in table_to_mapper.items():
3056            super_ = mapper.inherits
3057            if super_:
3058                extra_dependencies.extend(
3059                    [(super_table, table) for super_table in super_.tables]
3060                )
3061
3062        def skip(fk):
3063            # attempt to skip dependencies that are not
3064            # significant to the inheritance chain
3065            # for two tables that are related by inheritance.
3066            # while that dependency may be important, it's technically
3067            # not what we mean to sort on here.
3068            parent = table_to_mapper.get(fk.parent.table)
3069            dep = table_to_mapper.get(fk.column.table)
3070            if (
3071                parent is not None
3072                and dep is not None
3073                and dep is not parent
3074                and dep.inherit_condition is not None
3075            ):
3076                cols = set(sql_util._find_columns(dep.inherit_condition))
3077                if parent.inherit_condition is not None:
3078                    cols = cols.union(
3079                        sql_util._find_columns(parent.inherit_condition)
3080                    )
3081                    return fk.parent not in cols and fk.column not in cols
3082                else:
3083                    return fk.parent not in cols
3084            return False
3085
3086        sorted_ = sql_util.sort_tables(
3087            table_to_mapper,
3088            skip_fn=skip,
3089            extra_dependencies=extra_dependencies,
3090        )
3091
3092        ret = util.OrderedDict()
3093        for t in sorted_:
3094            ret[t] = table_to_mapper[t]
3095        return ret
3096
3097    def _memo(self, key, callable_):
3098        if key in self._memoized_values:
3099            return self._memoized_values[key]
3100        else:
3101            self._memoized_values[key] = value = callable_()
3102            return value
3103
3104    @util.memoized_property
3105    def _table_to_equated(self):
3106        """memoized map of tables to collections of columns to be
3107        synchronized upwards to the base mapper."""
3108
3109        result = util.defaultdict(list)
3110
3111        for table in self._sorted_tables:
3112            cols = set(table.c)
3113            for m in self.iterate_to_root():
3114                if m._inherits_equated_pairs and cols.intersection(
3115                    util.reduce(
3116                        set.union,
3117                        [l.proxy_set for l, r in m._inherits_equated_pairs],
3118                    )
3119                ):
3120                    result[table].append((m, m._inherits_equated_pairs))
3121
3122        return result
3123
3124
3125def configure_mappers():
3126    """Initialize the inter-mapper relationships of all mappers that
3127    have been constructed thus far.
3128
3129    This function can be called any number of times, but in
3130    most cases is invoked automatically, the first time mappings are used,
3131    as well as whenever mappings are used and additional not-yet-configured
3132    mappers have been constructed.
3133
3134    Points at which this occur include when a mapped class is instantiated
3135    into an instance, as well as when the :meth:`.Session.query` method
3136    is used.
3137
3138    The :func:`.configure_mappers` function provides several event hooks
3139    that can be used to augment its functionality.  These methods include:
3140
3141    * :meth:`.MapperEvents.before_configured` - called once before
3142      :func:`.configure_mappers` does any work; this can be used to establish
3143      additional options, properties, or related mappings before the operation
3144      proceeds.
3145
3146    * :meth:`.MapperEvents.mapper_configured` - called as each individual
3147      :class:`.Mapper` is configured within the process; will include all
3148      mapper state except for backrefs set up by other mappers that are still
3149      to be configured.
3150
3151    * :meth:`.MapperEvents.after_configured` - called once after
3152      :func:`.configure_mappers` is complete; at this stage, all
3153      :class:`.Mapper` objects that are known  to SQLAlchemy will be fully
3154      configured.  Note that the calling application may still have other
3155      mappings that haven't been produced yet, such as if they are in modules
3156      as yet unimported.
3157
3158    """
3159
3160    if not Mapper._new_mappers:
3161        return
3162
3163    _CONFIGURE_MUTEX.acquire()
3164    try:
3165        global _already_compiling
3166        if _already_compiling:
3167            return
3168        _already_compiling = True
3169        try:
3170
3171            # double-check inside mutex
3172            if not Mapper._new_mappers:
3173                return
3174
3175            Mapper.dispatch._for_class(Mapper).before_configured()
3176            # initialize properties on all mappers
3177            # note that _mapper_registry is unordered, which
3178            # may randomly conceal/reveal issues related to
3179            # the order of mapper compilation
3180
3181            for mapper in list(_mapper_registry):
3182                if getattr(mapper, "_configure_failed", False):
3183                    e = sa_exc.InvalidRequestError(
3184                        "One or more mappers failed to initialize - "
3185                        "can't proceed with initialization of other "
3186                        "mappers. Triggering mapper: '%s'. "
3187                        "Original exception was: %s"
3188                        % (mapper, mapper._configure_failed)
3189                    )
3190                    e._configure_failed = mapper._configure_failed
3191                    raise e
3192                if not mapper.configured:
3193                    try:
3194                        mapper._post_configure_properties()
3195                        mapper._expire_memoizations()
3196                        mapper.dispatch.mapper_configured(
3197                            mapper, mapper.class_
3198                        )
3199                    except Exception:
3200                        exc = sys.exc_info()[1]
3201                        if not hasattr(exc, "_configure_failed"):
3202                            mapper._configure_failed = exc
3203                        raise
3204
3205            Mapper._new_mappers = False
3206        finally:
3207            _already_compiling = False
3208    finally:
3209        _CONFIGURE_MUTEX.release()
3210    Mapper.dispatch._for_class(Mapper).after_configured()
3211
3212
3213def reconstructor(fn):
3214    """Decorate a method as the 'reconstructor' hook.
3215
3216    Designates a method as the "reconstructor", an ``__init__``-like
3217    method that will be called by the ORM after the instance has been
3218    loaded from the database or otherwise reconstituted.
3219
3220    The reconstructor will be invoked with no arguments.  Scalar
3221    (non-collection) database-mapped attributes of the instance will
3222    be available for use within the function.  Eagerly-loaded
3223    collections are generally not yet available and will usually only
3224    contain the first element.  ORM state changes made to objects at
3225    this stage will not be recorded for the next flush() operation, so
3226    the activity within a reconstructor should be conservative.
3227
3228    .. seealso::
3229
3230        :ref:`mapping_constructors`
3231
3232        :meth:`.InstanceEvents.load`
3233
3234    """
3235    fn.__sa_reconstructor__ = True
3236    return fn
3237
3238
3239def validates(*names, **kw):
3240    r"""Decorate a method as a 'validator' for one or more named properties.
3241
3242    Designates a method as a validator, a method which receives the
3243    name of the attribute as well as a value to be assigned, or in the
3244    case of a collection, the value to be added to the collection.
3245    The function can then raise validation exceptions to halt the
3246    process from continuing (where Python's built-in ``ValueError``
3247    and ``AssertionError`` exceptions are reasonable choices), or can
3248    modify or replace the value before proceeding. The function should
3249    otherwise return the given value.
3250
3251    Note that a validator for a collection **cannot** issue a load of that
3252    collection within the validation routine - this usage raises
3253    an assertion to avoid recursion overflows.  This is a reentrant
3254    condition which is not supported.
3255
3256    :param \*names: list of attribute names to be validated.
3257    :param include_removes: if True, "remove" events will be
3258     sent as well - the validation function must accept an additional
3259     argument "is_remove" which will be a boolean.
3260
3261    :param include_backrefs: defaults to ``True``; if ``False``, the
3262     validation function will not emit if the originator is an attribute
3263     event related via a backref.  This can be used for bi-directional
3264     :func:`.validates` usage where only one validator should emit per
3265     attribute operation.
3266
3267     .. versionadded:: 0.9.0
3268
3269    .. seealso::
3270
3271      :ref:`simple_validators` - usage examples for :func:`.validates`
3272
3273    """
3274    include_removes = kw.pop("include_removes", False)
3275    include_backrefs = kw.pop("include_backrefs", True)
3276
3277    def wrap(fn):
3278        fn.__sa_validators__ = names
3279        fn.__sa_validation_opts__ = {
3280            "include_removes": include_removes,
3281            "include_backrefs": include_backrefs,
3282        }
3283        return fn
3284
3285    return wrap
3286
3287
3288def _event_on_load(state, ctx):
3289    instrumenting_mapper = state.manager.info[_INSTRUMENTOR]
3290    if instrumenting_mapper._reconstructor:
3291        instrumenting_mapper._reconstructor(state.obj())
3292
3293
3294def _event_on_first_init(manager, cls):
3295    """Initial mapper compilation trigger.
3296
3297    instrumentation calls this one when InstanceState
3298    is first generated, and is needed for legacy mutable
3299    attributes to work.
3300    """
3301
3302    instrumenting_mapper = manager.info.get(_INSTRUMENTOR)
3303    if instrumenting_mapper:
3304        if Mapper._new_mappers:
3305            configure_mappers()
3306
3307
3308def _event_on_init(state, args, kwargs):
3309    """Run init_instance hooks.
3310
3311    This also includes mapper compilation, normally not needed
3312    here but helps with some piecemeal configuration
3313    scenarios (such as in the ORM tutorial).
3314
3315    """
3316
3317    instrumenting_mapper = state.manager.info.get(_INSTRUMENTOR)
3318    if instrumenting_mapper:
3319        if Mapper._new_mappers:
3320            configure_mappers()
3321        if instrumenting_mapper._set_polymorphic_identity:
3322            instrumenting_mapper._set_polymorphic_identity(state)
3323
3324
3325class _ColumnMapping(dict):
3326    """Error reporting helper for mapper._columntoproperty."""
3327
3328    __slots__ = ("mapper",)
3329
3330    def __init__(self, mapper):
3331        self.mapper = mapper
3332
3333    def __missing__(self, column):
3334        prop = self.mapper._props.get(column)
3335        if prop:
3336            raise orm_exc.UnmappedColumnError(
3337                "Column '%s.%s' is not available, due to "
3338                "conflicting property '%s':%r"
3339                % (column.table.name, column.name, column.key, prop)
3340            )
3341        raise orm_exc.UnmappedColumnError(
3342            "No column %s is configured on mapper %s..."
3343            % (column, self.mapper)
3344        )
3345