You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					573 lines
				
				15 KiB
			
		
		
			
		
	
	
					573 lines
				
				15 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								# orm/base.py
							 | 
						||
| 
								 | 
							
								# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors
							 | 
						||
| 
								 | 
							
								# <see AUTHORS file>
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This module is part of SQLAlchemy and is released under
							 | 
						||
| 
								 | 
							
								# the MIT License: https://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""Constants and rudimental functions used throughout the ORM.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import operator
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from . import exc
							 | 
						||
| 
								 | 
							
								from .. import exc as sa_exc
							 | 
						||
| 
								 | 
							
								from .. import inspection
							 | 
						||
| 
								 | 
							
								from .. import util
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PASSIVE_NO_RESULT = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_NO_RESULT",
							 | 
						||
| 
								 | 
							
								    """Symbol returned by a loader callable or other attribute/history
							 | 
						||
| 
								 | 
							
								    retrieval operation when a value could not be determined, based
							 | 
						||
| 
								 | 
							
								    on loader callable flags.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PASSIVE_CLASS_MISMATCH = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_CLASS_MISMATCH",
							 | 
						||
| 
								 | 
							
								    """Symbol indicating that an object is locally present for a given
							 | 
						||
| 
								 | 
							
								    primary key identity but it is not of the requested class.  The
							 | 
						||
| 
								 | 
							
								    return value is therefore None and no SQL should be emitted.""",
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ATTR_WAS_SET = util.symbol(
							 | 
						||
| 
								 | 
							
								    "ATTR_WAS_SET",
							 | 
						||
| 
								 | 
							
								    """Symbol returned by a loader callable to indicate the
							 | 
						||
| 
								 | 
							
								    retrieved value, or values, were assigned to their attributes
							 | 
						||
| 
								 | 
							
								    on the target object.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ATTR_EMPTY = util.symbol(
							 | 
						||
| 
								 | 
							
								    "ATTR_EMPTY",
							 | 
						||
| 
								 | 
							
								    """Symbol used internally to indicate an attribute had no callable.""",
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NO_VALUE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NO_VALUE",
							 | 
						||
| 
								 | 
							
								    """Symbol which may be placed as the 'previous' value of an attribute,
							 | 
						||
| 
								 | 
							
								    indicating no value was loaded for an attribute when it was modified,
							 | 
						||
| 
								 | 
							
								    and flags indicated we were not to load it.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								NEVER_SET = NO_VALUE
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								Synonymous with NO_VALUE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								.. versionchanged:: 1.4   NEVER_SET was merged with NO_VALUE
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NO_CHANGE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NO_CHANGE",
							 | 
						||
| 
								 | 
							
								    """No callables or SQL should be emitted on attribute access
							 | 
						||
| 
								 | 
							
								    and no state should change
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								    canonical=0,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CALLABLES_OK = util.symbol(
							 | 
						||
| 
								 | 
							
								    "CALLABLES_OK",
							 | 
						||
| 
								 | 
							
								    """Loader callables can be fired off if a value
							 | 
						||
| 
								 | 
							
								    is not present.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								    canonical=1,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SQL_OK = util.symbol(
							 | 
						||
| 
								 | 
							
								    "SQL_OK",
							 | 
						||
| 
								 | 
							
								    """Loader callables can emit SQL at least on scalar value attributes.""",
							 | 
						||
| 
								 | 
							
								    canonical=2,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								RELATED_OBJECT_OK = util.symbol(
							 | 
						||
| 
								 | 
							
								    "RELATED_OBJECT_OK",
							 | 
						||
| 
								 | 
							
								    """Callables can use SQL to load related objects as well
							 | 
						||
| 
								 | 
							
								    as scalar value attributes.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								    canonical=4,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								INIT_OK = util.symbol(
							 | 
						||
| 
								 | 
							
								    "INIT_OK",
							 | 
						||
| 
								 | 
							
								    """Attributes should be initialized with a blank
							 | 
						||
| 
								 | 
							
								    value (None or an empty collection) upon get, if no other
							 | 
						||
| 
								 | 
							
								    value can be obtained.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								    canonical=8,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NON_PERSISTENT_OK = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NON_PERSISTENT_OK",
							 | 
						||
| 
								 | 
							
								    """Callables can be emitted if the parent is not persistent.""",
							 | 
						||
| 
								 | 
							
								    canonical=16,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								LOAD_AGAINST_COMMITTED = util.symbol(
							 | 
						||
| 
								 | 
							
								    "LOAD_AGAINST_COMMITTED",
							 | 
						||
| 
								 | 
							
								    """Callables should use committed values as primary/foreign keys during a
							 | 
						||
| 
								 | 
							
								    load.
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								    canonical=32,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NO_AUTOFLUSH = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NO_AUTOFLUSH",
							 | 
						||
| 
								 | 
							
								    """Loader callables should disable autoflush.""",
							 | 
						||
| 
								 | 
							
								    canonical=64,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NO_RAISE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NO_RAISE",
							 | 
						||
| 
								 | 
							
								    """Loader callables should not raise any assertions""",
							 | 
						||
| 
								 | 
							
								    canonical=128,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DEFERRED_HISTORY_LOAD = util.symbol(
							 | 
						||
| 
								 | 
							
								    "DEFERRED_HISTORY_LOAD",
							 | 
						||
| 
								 | 
							
								    """indicates special load of the previous value of an attribute""",
							 | 
						||
| 
								 | 
							
								    canonical=256,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# pre-packaged sets of flags used as inputs
							 | 
						||
| 
								 | 
							
								PASSIVE_OFF = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_OFF",
							 | 
						||
| 
								 | 
							
								    "Callables can be emitted in all cases.",
							 | 
						||
| 
								 | 
							
								    canonical=(
							 | 
						||
| 
								 | 
							
								        RELATED_OBJECT_OK | NON_PERSISTENT_OK | INIT_OK | CALLABLES_OK | SQL_OK
							 | 
						||
| 
								 | 
							
								    ),
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								PASSIVE_RETURN_NO_VALUE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_RETURN_NO_VALUE",
							 | 
						||
| 
								 | 
							
								    """PASSIVE_OFF ^ INIT_OK""",
							 | 
						||
| 
								 | 
							
								    canonical=PASSIVE_OFF ^ INIT_OK,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								PASSIVE_NO_INITIALIZE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_NO_INITIALIZE",
							 | 
						||
| 
								 | 
							
								    "PASSIVE_RETURN_NO_VALUE ^ CALLABLES_OK",
							 | 
						||
| 
								 | 
							
								    canonical=PASSIVE_RETURN_NO_VALUE ^ CALLABLES_OK,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								PASSIVE_NO_FETCH = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_NO_FETCH", "PASSIVE_OFF ^ SQL_OK", canonical=PASSIVE_OFF ^ SQL_OK
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								PASSIVE_NO_FETCH_RELATED = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_NO_FETCH_RELATED",
							 | 
						||
| 
								 | 
							
								    "PASSIVE_OFF ^ RELATED_OBJECT_OK",
							 | 
						||
| 
								 | 
							
								    canonical=PASSIVE_OFF ^ RELATED_OBJECT_OK,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								PASSIVE_ONLY_PERSISTENT = util.symbol(
							 | 
						||
| 
								 | 
							
								    "PASSIVE_ONLY_PERSISTENT",
							 | 
						||
| 
								 | 
							
								    "PASSIVE_OFF ^ NON_PERSISTENT_OK",
							 | 
						||
| 
								 | 
							
								    canonical=PASSIVE_OFF ^ NON_PERSISTENT_OK,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								DEFAULT_MANAGER_ATTR = "_sa_class_manager"
							 | 
						||
| 
								 | 
							
								DEFAULT_STATE_ATTR = "_sa_instance_state"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								EXT_CONTINUE = util.symbol("EXT_CONTINUE")
							 | 
						||
| 
								 | 
							
								EXT_STOP = util.symbol("EXT_STOP")
							 | 
						||
| 
								 | 
							
								EXT_SKIP = util.symbol("EXT_SKIP")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ONETOMANY = util.symbol(
							 | 
						||
| 
								 | 
							
								    "ONETOMANY",
							 | 
						||
| 
								 | 
							
								    """Indicates the one-to-many direction for a :func:`_orm.relationship`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This symbol is typically used by the internals but may be exposed within
							 | 
						||
| 
								 | 
							
								    certain API features.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MANYTOONE = util.symbol(
							 | 
						||
| 
								 | 
							
								    "MANYTOONE",
							 | 
						||
| 
								 | 
							
								    """Indicates the many-to-one direction for a :func:`_orm.relationship`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This symbol is typically used by the internals but may be exposed within
							 | 
						||
| 
								 | 
							
								    certain API features.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								MANYTOMANY = util.symbol(
							 | 
						||
| 
								 | 
							
								    "MANYTOMANY",
							 | 
						||
| 
								 | 
							
								    """Indicates the many-to-many direction for a :func:`_orm.relationship`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This symbol is typically used by the internals but may be exposed within
							 | 
						||
| 
								 | 
							
								    certain API features.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								NOT_EXTENSION = util.symbol(
							 | 
						||
| 
								 | 
							
								    "NOT_EXTENSION",
							 | 
						||
| 
								 | 
							
								    """Symbol indicating an :class:`InspectionAttr` that's
							 | 
						||
| 
								 | 
							
								    not part of sqlalchemy.ext.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Is assigned to the :attr:`.InspectionAttr.extension_type`
							 | 
						||
| 
								 | 
							
								    attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """,
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_never_set = frozenset([NEVER_SET])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_none_set = frozenset([None, NEVER_SET, PASSIVE_NO_RESULT])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_SET_DEFERRED_EXPIRED = util.symbol("SET_DEFERRED_EXPIRED")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_DEFER_FOR_STATE = util.symbol("DEFER_FOR_STATE")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_RAISE_FOR_STATE = util.symbol("RAISE_FOR_STATE")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _assertions(*assertions):
							 | 
						||
| 
								 | 
							
								    @util.decorator
							 | 
						||
| 
								 | 
							
								    def generate(fn, *args, **kw):
							 | 
						||
| 
								 | 
							
								        self = args[0]
							 | 
						||
| 
								 | 
							
								        for assertion in assertions:
							 | 
						||
| 
								 | 
							
								            assertion(self, fn.__name__)
							 | 
						||
| 
								 | 
							
								        fn(self, *args[1:], **kw)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return generate
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# these can be replaced by sqlalchemy.ext.instrumentation
							 | 
						||
| 
								 | 
							
								# if augmented class instrumentation is enabled.
							 | 
						||
| 
								 | 
							
								def manager_of_class(cls):
							 | 
						||
| 
								 | 
							
								    return cls.__dict__.get(DEFAULT_MANAGER_ATTR, None)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								instance_state = operator.attrgetter(DEFAULT_STATE_ATTR)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								instance_dict = operator.attrgetter("__dict__")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def instance_str(instance):
							 | 
						||
| 
								 | 
							
								    """Return a string describing an instance."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return state_str(instance_state(instance))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def state_str(state):
							 | 
						||
| 
								 | 
							
								    """Return a string describing an instance via its InstanceState."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if state is None:
							 | 
						||
| 
								 | 
							
								        return "None"
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return "<%s at 0x%x>" % (state.class_.__name__, id(state.obj()))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def state_class_str(state):
							 | 
						||
| 
								 | 
							
								    """Return a string describing an instance's class via its
							 | 
						||
| 
								 | 
							
								    InstanceState.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if state is None:
							 | 
						||
| 
								 | 
							
								        return "None"
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return "<%s>" % (state.class_.__name__,)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def attribute_str(instance, attribute):
							 | 
						||
| 
								 | 
							
								    return instance_str(instance) + "." + attribute
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def state_attribute_str(state, attribute):
							 | 
						||
| 
								 | 
							
								    return state_str(state) + "." + attribute
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def object_mapper(instance):
							 | 
						||
| 
								 | 
							
								    """Given an object, return the primary Mapper associated with the object
							 | 
						||
| 
								 | 
							
								    instance.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
							 | 
						||
| 
								 | 
							
								    if no mapping is configured.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This function is available via the inspection system as::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        inspect(instance).mapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Using the inspection system will raise
							 | 
						||
| 
								 | 
							
								    :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
							 | 
						||
| 
								 | 
							
								    not part of a mapping.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    return object_state(instance).mapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def object_state(instance):
							 | 
						||
| 
								 | 
							
								    """Given an object, return the :class:`.InstanceState`
							 | 
						||
| 
								 | 
							
								    associated with the object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
							 | 
						||
| 
								 | 
							
								    if no mapping is configured.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Equivalent functionality is available via the :func:`_sa.inspect`
							 | 
						||
| 
								 | 
							
								    function as::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        inspect(instance)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Using the inspection system will raise
							 | 
						||
| 
								 | 
							
								    :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
							 | 
						||
| 
								 | 
							
								    not part of a mapping.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    state = _inspect_mapped_object(instance)
							 | 
						||
| 
								 | 
							
								    if state is None:
							 | 
						||
| 
								 | 
							
								        raise exc.UnmappedInstanceError(instance)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return state
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@inspection._inspects(object)
							 | 
						||
| 
								 | 
							
								def _inspect_mapped_object(instance):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        return instance_state(instance)
							 | 
						||
| 
								 | 
							
								    except (exc.UnmappedClassError,) + exc.NO_STATE:
							 | 
						||
| 
								 | 
							
								        return None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _class_to_mapper(class_or_mapper):
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(class_or_mapper, False)
							 | 
						||
| 
								 | 
							
								    if insp is not None:
							 | 
						||
| 
								 | 
							
								        return insp.mapper
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        raise exc.UnmappedClassError(class_or_mapper)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _mapper_or_none(entity):
							 | 
						||
| 
								 | 
							
								    """Return the :class:`_orm.Mapper` for the given class or None if the
							 | 
						||
| 
								 | 
							
								    class is not mapped.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(entity, False)
							 | 
						||
| 
								 | 
							
								    if insp is not None:
							 | 
						||
| 
								 | 
							
								        return insp.mapper
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _is_mapped_class(entity):
							 | 
						||
| 
								 | 
							
								    """Return True if the given object is a mapped class,
							 | 
						||
| 
								 | 
							
								    :class:`_orm.Mapper`, or :class:`.AliasedClass`.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(entity, False)
							 | 
						||
| 
								 | 
							
								    return (
							 | 
						||
| 
								 | 
							
								        insp is not None
							 | 
						||
| 
								 | 
							
								        and not insp.is_clause_element
							 | 
						||
| 
								 | 
							
								        and (insp.is_mapper or insp.is_aliased_class)
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _orm_columns(entity):
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(entity, False)
							 | 
						||
| 
								 | 
							
								    if hasattr(insp, "selectable") and hasattr(insp.selectable, "c"):
							 | 
						||
| 
								 | 
							
								        return [c for c in insp.selectable.c]
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return [entity]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _is_aliased_class(entity):
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(entity, False)
							 | 
						||
| 
								 | 
							
								    return insp is not None and getattr(insp, "is_aliased_class", False)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def _entity_descriptor(entity, key):
							 | 
						||
| 
								 | 
							
								    """Return a class attribute given an entity and string name.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    May return :class:`.InstrumentedAttribute` or user-defined
							 | 
						||
| 
								 | 
							
								    attribute.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    insp = inspection.inspect(entity)
							 | 
						||
| 
								 | 
							
								    if insp.is_selectable:
							 | 
						||
| 
								 | 
							
								        description = entity
							 | 
						||
| 
								 | 
							
								        entity = insp.c
							 | 
						||
| 
								 | 
							
								    elif insp.is_aliased_class:
							 | 
						||
| 
								 | 
							
								        entity = insp.entity
							 | 
						||
| 
								 | 
							
								        description = entity
							 | 
						||
| 
								 | 
							
								    elif hasattr(insp, "mapper"):
							 | 
						||
| 
								 | 
							
								        description = entity = insp.mapper.class_
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        description = entity
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        return getattr(entity, key)
							 | 
						||
| 
								 | 
							
								    except AttributeError as err:
							 | 
						||
| 
								 | 
							
								        util.raise_(
							 | 
						||
| 
								 | 
							
								            sa_exc.InvalidRequestError(
							 | 
						||
| 
								 | 
							
								                "Entity '%s' has no property '%s'" % (description, key)
							 | 
						||
| 
								 | 
							
								            ),
							 | 
						||
| 
								 | 
							
								            replace_context=err,
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_state_mapper = util.dottedgetter("manager.mapper")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@inspection._inspects(type)
							 | 
						||
| 
								 | 
							
								def _inspect_mapped_class(class_, configure=False):
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        class_manager = manager_of_class(class_)
							 | 
						||
| 
								 | 
							
								        if not class_manager.is_mapped:
							 | 
						||
| 
								 | 
							
								            return None
							 | 
						||
| 
								 | 
							
								        mapper = class_manager.mapper
							 | 
						||
| 
								 | 
							
								    except exc.NO_STATE:
							 | 
						||
| 
								 | 
							
								        return None
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        if configure:
							 | 
						||
| 
								 | 
							
								            mapper._check_configure()
							 | 
						||
| 
								 | 
							
								        return mapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def class_mapper(class_, configure=True):
							 | 
						||
| 
								 | 
							
								    """Given a class, return the primary :class:`_orm.Mapper` associated
							 | 
						||
| 
								 | 
							
								    with the key.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Raises :exc:`.UnmappedClassError` if no mapping is configured
							 | 
						||
| 
								 | 
							
								    on the given class, or :exc:`.ArgumentError` if a non-class
							 | 
						||
| 
								 | 
							
								    object is passed.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Equivalent functionality is available via the :func:`_sa.inspect`
							 | 
						||
| 
								 | 
							
								    function as::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        inspect(some_mapped_class)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Using the inspection system will raise
							 | 
						||
| 
								 | 
							
								    :class:`sqlalchemy.exc.NoInspectionAvailable` if the class is not mapped.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    mapper = _inspect_mapped_class(class_, configure=configure)
							 | 
						||
| 
								 | 
							
								    if mapper is None:
							 | 
						||
| 
								 | 
							
								        if not isinstance(class_, type):
							 | 
						||
| 
								 | 
							
								            raise sa_exc.ArgumentError(
							 | 
						||
| 
								 | 
							
								                "Class object expected, got '%r'." % (class_,)
							 | 
						||
| 
								 | 
							
								            )
							 | 
						||
| 
								 | 
							
								        raise exc.UnmappedClassError(class_)
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return mapper
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class InspectionAttr(object):
							 | 
						||
| 
								 | 
							
								    """A base class applied to all ORM objects that can be returned
							 | 
						||
| 
								 | 
							
								    by the :func:`_sa.inspect` function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The attributes defined here allow the usage of simple boolean
							 | 
						||
| 
								 | 
							
								    checks to test basic facts about the object returned.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    While the boolean checks here are basically the same as using
							 | 
						||
| 
								 | 
							
								    the Python isinstance() function, the flags here can be used without
							 | 
						||
| 
								 | 
							
								    the need to import all of these classes, and also such that
							 | 
						||
| 
								 | 
							
								    the SQLAlchemy class system can change while leaving the flags
							 | 
						||
| 
								 | 
							
								    here intact for forwards-compatibility.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_selectable = False
							 | 
						||
| 
								 | 
							
								    """Return True if this object is an instance of
							 | 
						||
| 
								 | 
							
								    :class:`_expression.Selectable`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_aliased_class = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of :class:`.AliasedClass`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_instance = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of :class:`.InstanceState`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_mapper = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of :class:`_orm.Mapper`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_bundle = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of :class:`.Bundle`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_property = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of :class:`.MapperProperty`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_attribute = False
							 | 
						||
| 
								 | 
							
								    """True if this object is a Python :term:`descriptor`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This can refer to one of many types.   Usually a
							 | 
						||
| 
								 | 
							
								    :class:`.QueryableAttribute` which handles attributes events on behalf
							 | 
						||
| 
								 | 
							
								    of a :class:`.MapperProperty`.   But can also be an extension type
							 | 
						||
| 
								 | 
							
								    such as :class:`.AssociationProxy` or :class:`.hybrid_property`.
							 | 
						||
| 
								 | 
							
								    The :attr:`.InspectionAttr.extension_type` will refer to a constant
							 | 
						||
| 
								 | 
							
								    identifying the specific subtype.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :attr:`_orm.Mapper.all_orm_descriptors`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _is_internal_proxy = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an internal proxy object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 1.2.12
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    is_clause_element = False
							 | 
						||
| 
								 | 
							
								    """True if this object is an instance of
							 | 
						||
| 
								 | 
							
								    :class:`_expression.ClauseElement`."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    extension_type = NOT_EXTENSION
							 | 
						||
| 
								 | 
							
								    """The extension type, if any.
							 | 
						||
| 
								 | 
							
								    Defaults to :data:`.interfaces.NOT_EXTENSION`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :data:`.HYBRID_METHOD`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :data:`.HYBRID_PROPERTY`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        :data:`.ASSOCIATION_PROXY`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class InspectionAttrInfo(InspectionAttr):
							 | 
						||
| 
								 | 
							
								    """Adds the ``.info`` attribute to :class:`.InspectionAttr`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The rationale for :class:`.InspectionAttr` vs. :class:`.InspectionAttrInfo`
							 | 
						||
| 
								 | 
							
								    is that the former is compatible as a mixin for classes that specify
							 | 
						||
| 
								 | 
							
								    ``__slots__``; this is essentially an implementation artifact.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @util.memoized_property
							 | 
						||
| 
								 | 
							
								    def info(self):
							 | 
						||
| 
								 | 
							
								        """Info dictionary associated with the object, allowing user-defined
							 | 
						||
| 
								 | 
							
								        data to be associated with this :class:`.InspectionAttr`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        The dictionary is generated when first accessed.  Alternatively,
							 | 
						||
| 
								 | 
							
								        it can be specified as a constructor argument to the
							 | 
						||
| 
								 | 
							
								        :func:`.column_property`, :func:`_orm.relationship`, or
							 | 
						||
| 
								 | 
							
								        :func:`.composite`
							 | 
						||
| 
								 | 
							
								        functions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. versionchanged:: 1.0.0 :attr:`.MapperProperty.info` is also
							 | 
						||
| 
								 | 
							
								           available on extension types via the
							 | 
						||
| 
								 | 
							
								           :attr:`.InspectionAttrInfo.info` attribute, so that it can apply
							 | 
						||
| 
								 | 
							
								           to a wider variety of ORM and extension constructs.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        .. seealso::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.QueryableAttribute.info`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            :attr:`.SchemaItem.info`
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        """
							 | 
						||
| 
								 | 
							
								        return {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class _MappedAttribute(object):
							 | 
						||
| 
								 | 
							
								    """Mixin for attributes which should be replaced by mapper-assigned
							 | 
						||
| 
								 | 
							
								    attributes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    __slots__ = ()
							 |