| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002 | 
							- # orm/session.py
 
- # Copyright (C) 2005-2017 the SQLAlchemy authors and contributors
 
- # <see AUTHORS file>
 
- #
 
- # This module is part of SQLAlchemy and is released under
 
- # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
- """Provides the Session class and related utilities."""
 
- import weakref
 
- from .. import util, sql, engine, exc as sa_exc
 
- from ..sql import util as sql_util, expression
 
- from . import (
 
-     SessionExtension, attributes, exc, query,
 
-     loading, identity
 
- )
 
- from ..inspection import inspect
 
- from .base import (
 
-     object_mapper, class_mapper,
 
-     _class_to_mapper, _state_mapper, object_state,
 
-     _none_set, state_str, instance_str
 
- )
 
- import itertools
 
- from . import persistence
 
- from .unitofwork import UOWTransaction
 
- from . import state as statelib
 
- import sys
 
- __all__ = ['Session', 'SessionTransaction',
 
-            'SessionExtension', 'sessionmaker']
 
- _sessions = weakref.WeakValueDictionary()
 
- """Weak-referencing dictionary of :class:`.Session` objects.
 
- """
 
- def _state_session(state):
 
-     """Given an :class:`.InstanceState`, return the :class:`.Session`
 
-         associated, if any.
 
-     """
 
-     if state.session_id:
 
-         try:
 
-             return _sessions[state.session_id]
 
-         except KeyError:
 
-             pass
 
-     return None
 
- class _SessionClassMethods(object):
 
-     """Class-level methods for :class:`.Session`, :class:`.sessionmaker`."""
 
-     @classmethod
 
-     def close_all(cls):
 
-         """Close *all* sessions in memory."""
 
-         for sess in _sessions.values():
 
-             sess.close()
 
-     @classmethod
 
-     @util.dependencies("sqlalchemy.orm.util")
 
-     def identity_key(cls, orm_util, *args, **kwargs):
 
-         """Return an identity key.
 
-         This is an alias of :func:`.util.identity_key`.
 
-         """
 
-         return orm_util.identity_key(*args, **kwargs)
 
-     @classmethod
 
-     def object_session(cls, instance):
 
-         """Return the :class:`.Session` to which an object belongs.
 
-         This is an alias of :func:`.object_session`.
 
-         """
 
-         return object_session(instance)
 
- ACTIVE = util.symbol('ACTIVE')
 
- PREPARED = util.symbol('PREPARED')
 
- COMMITTED = util.symbol('COMMITTED')
 
- DEACTIVE = util.symbol('DEACTIVE')
 
- CLOSED = util.symbol('CLOSED')
 
- class SessionTransaction(object):
 
-     """A :class:`.Session`-level transaction.
 
-     :class:`.SessionTransaction` is a mostly behind-the-scenes object
 
-     not normally referenced directly by application code.   It coordinates
 
-     among multiple :class:`.Connection` objects, maintaining a database
 
-     transaction for each one individually, committing or rolling them
 
-     back all at once.   It also provides optional two-phase commit behavior
 
-     which can augment this coordination operation.
 
-     The :attr:`.Session.transaction` attribute of :class:`.Session`
 
-     refers to the current :class:`.SessionTransaction` object in use, if any.
 
-     The :attr:`.SessionTransaction.parent` attribute refers to the parent
 
-     :class:`.SessionTransaction` in the stack of :class:`.SessionTransaction`
 
-     objects.  If this attribute is ``None``, then this is the top of the stack.
 
-     If non-``None``, then this :class:`.SessionTransaction` refers either
 
-     to a so-called "subtransaction" or a "nested" transaction.  A
 
-     "subtransaction" is a scoping concept that demarcates an inner portion
 
-     of the outermost "real" transaction.  A nested transaction, which
 
-     is indicated when the :attr:`.SessionTransaction.nested`
 
-     attribute is also True, indicates that this :class:`.SessionTransaction`
 
-     corresponds to a SAVEPOINT.
 
-     **Life Cycle**
 
-     A :class:`.SessionTransaction` is associated with a :class:`.Session`
 
-     in its default mode of ``autocommit=False`` immediately, associated
 
-     with no database connections.  As the :class:`.Session` is called upon
 
-     to emit SQL on behalf of various :class:`.Engine` or :class:`.Connection`
 
-     objects, a corresponding :class:`.Connection` and associated
 
-     :class:`.Transaction` is added to a collection within the
 
-     :class:`.SessionTransaction` object, becoming one of the
 
-     connection/transaction pairs maintained by the
 
-     :class:`.SessionTransaction`.  The start of a :class:`.SessionTransaction`
 
-     can be tracked using the :meth:`.SessionEvents.after_transaction_create`
 
-     event.
 
-     The lifespan of the :class:`.SessionTransaction` ends when the
 
-     :meth:`.Session.commit`, :meth:`.Session.rollback` or
 
-     :meth:`.Session.close` methods are called.  At this point, the
 
-     :class:`.SessionTransaction` removes its association with its parent
 
-     :class:`.Session`.   A :class:`.Session` that is in ``autocommit=False``
 
-     mode will create a new :class:`.SessionTransaction` to replace it
 
-     immediately, whereas a :class:`.Session` that's in ``autocommit=True``
 
-     mode will remain without a :class:`.SessionTransaction` until the
 
-     :meth:`.Session.begin` method is called.  The end of a
 
-     :class:`.SessionTransaction` can be tracked using the
 
-     :meth:`.SessionEvents.after_transaction_end` event.
 
-     **Nesting and Subtransactions**
 
-     Another detail of :class:`.SessionTransaction` behavior is that it is
 
-     capable of "nesting".  This means that the :meth:`.Session.begin` method
 
-     can be called while an existing :class:`.SessionTransaction` is already
 
-     present, producing a new :class:`.SessionTransaction` that temporarily
 
-     replaces the parent :class:`.SessionTransaction`.   When a
 
-     :class:`.SessionTransaction` is produced as nested, it assigns itself to
 
-     the :attr:`.Session.transaction` attribute, and it additionally will assign
 
-     the previous :class:`.SessionTransaction` to its :attr:`.Session.parent`
 
-     attribute.  The behavior is effectively a
 
-     stack, where :attr:`.Session.transaction` refers to the current head of
 
-     the stack, and the :attr:`.SessionTransaction.parent` attribute allows
 
-     traversal up the stack until :attr:`.SessionTransaction.parent` is
 
-     ``None``, indicating the top of the stack.
 
-     When the scope of :class:`.SessionTransaction` is ended via
 
-     :meth:`.Session.commit` or :meth:`.Session.rollback`, it restores its
 
-     parent :class:`.SessionTransaction` back onto the
 
-     :attr:`.Session.transaction` attribute.
 
-     The purpose of this stack is to allow nesting of
 
-     :meth:`.Session.rollback` or :meth:`.Session.commit` calls in context
 
-     with various flavors of :meth:`.Session.begin`. This nesting behavior
 
-     applies to when :meth:`.Session.begin_nested` is used to emit a
 
-     SAVEPOINT transaction, and is also used to produce a so-called
 
-     "subtransaction" which allows a block of code to use a
 
-     begin/rollback/commit sequence regardless of whether or not its enclosing
 
-     code block has begun a transaction.  The :meth:`.flush` method, whether
 
-     called explicitly or via autoflush, is the primary consumer of the
 
-     "subtransaction" feature, in that it wishes to guarantee that it works
 
-     within in a transaction block regardless of whether or not the
 
-     :class:`.Session` is in transactional mode when the method is called.
 
-     Note that the flush process that occurs within the "autoflush" feature
 
-     as well as when the :meth:`.Session.flush` method is used **always**
 
-     creates a :class:`.SessionTransaction` object.   This object is normally
 
-     a subtransaction, unless the :class:`.Session` is in autocommit mode
 
-     and no transaction exists at all, in which case it's the outermost
 
-     transaction.   Any event-handling logic or other inspection logic
 
-     needs to take into account whether a :class:`.SessionTransaction`
 
-     is the outermost transaction, a subtransaction, or a "nested" / SAVEPOINT
 
-     transaction.
 
-     .. seealso::
 
-     :meth:`.Session.rollback`
 
-     :meth:`.Session.commit`
 
-     :meth:`.Session.begin`
 
-     :meth:`.Session.begin_nested`
 
-     :attr:`.Session.is_active`
 
-     :meth:`.SessionEvents.after_transaction_create`
 
-     :meth:`.SessionEvents.after_transaction_end`
 
-     :meth:`.SessionEvents.after_commit`
 
-     :meth:`.SessionEvents.after_rollback`
 
-     :meth:`.SessionEvents.after_soft_rollback`
 
-     """
 
-     _rollback_exception = None
 
-     def __init__(self, session, parent=None, nested=False):
 
-         self.session = session
 
-         self._connections = {}
 
-         self._parent = parent
 
-         self.nested = nested
 
-         self._state = ACTIVE
 
-         if not parent and nested:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Can't start a SAVEPOINT transaction when no existing "
 
-                 "transaction is in progress")
 
-         if self.session._enable_transaction_accounting:
 
-             self._take_snapshot()
 
-         self.session.dispatch.after_transaction_create(self.session, self)
 
-     @property
 
-     def parent(self):
 
-         """The parent :class:`.SessionTransaction` of this
 
-         :class:`.SessionTransaction`.
 
-         If this attribute is ``None``, indicates this
 
-         :class:`.SessionTransaction` is at the top of the stack, and
 
-         corresponds to a real "COMMIT"/"ROLLBACK"
 
-         block.  If non-``None``, then this is either a "subtransaction"
 
-         or a "nested" / SAVEPOINT transaction.  If the
 
-         :attr:`.SessionTransaction.nested` attribute is ``True``, then
 
-         this is a SAVEPOINT, and if ``False``, indicates this a subtransaction.
 
-         .. versionadded:: 1.0.16 - use ._parent for previous versions
 
-         """
 
-         return self._parent
 
-     nested = False
 
-     """Indicates if this is a nested, or SAVEPOINT, transaction.
 
-     When :attr:`.SessionTransaction.nested` is True, it is expected
 
-     that :attr:`.SessionTransaction.parent` will be True as well.
 
-     """
 
-     @property
 
-     def is_active(self):
 
-         return self.session is not None and self._state is ACTIVE
 
-     def _assert_active(self, prepared_ok=False,
 
-                        rollback_ok=False,
 
-                        deactive_ok=False,
 
-                        closed_msg="This transaction is closed"):
 
-         if self._state is COMMITTED:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "This session is in 'committed' state; no further "
 
-                 "SQL can be emitted within this transaction."
 
-             )
 
-         elif self._state is PREPARED:
 
-             if not prepared_ok:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "This session is in 'prepared' state; no further "
 
-                     "SQL can be emitted within this transaction."
 
-                 )
 
-         elif self._state is DEACTIVE:
 
-             if not deactive_ok and not rollback_ok:
 
-                 if self._rollback_exception:
 
-                     raise sa_exc.InvalidRequestError(
 
-                         "This Session's transaction has been rolled back "
 
-                         "due to a previous exception during flush."
 
-                         " To begin a new transaction with this Session, "
 
-                         "first issue Session.rollback()."
 
-                         " Original exception was: %s"
 
-                         % self._rollback_exception
 
-                     )
 
-                 elif not deactive_ok:
 
-                     raise sa_exc.InvalidRequestError(
 
-                         "This Session's transaction has been rolled back "
 
-                         "by a nested rollback() call.  To begin a new "
 
-                         "transaction, issue Session.rollback() first."
 
-                     )
 
-         elif self._state is CLOSED:
 
-             raise sa_exc.ResourceClosedError(closed_msg)
 
-     @property
 
-     def _is_transaction_boundary(self):
 
-         return self.nested or not self._parent
 
-     def connection(self, bindkey, execution_options=None, **kwargs):
 
-         self._assert_active()
 
-         bind = self.session.get_bind(bindkey, **kwargs)
 
-         return self._connection_for_bind(bind, execution_options)
 
-     def _begin(self, nested=False):
 
-         self._assert_active()
 
-         return SessionTransaction(
 
-             self.session, self, nested=nested)
 
-     def _iterate_self_and_parents(self, upto=None):
 
-         current = self
 
-         result = ()
 
-         while current:
 
-             result += (current, )
 
-             if current._parent is upto:
 
-                 break
 
-             elif current._parent is None:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "Transaction %s is not on the active transaction list" % (
 
-                         upto))
 
-             else:
 
-                 current = current._parent
 
-         return result
 
-     def _take_snapshot(self):
 
-         if not self._is_transaction_boundary:
 
-             self._new = self._parent._new
 
-             self._deleted = self._parent._deleted
 
-             self._dirty = self._parent._dirty
 
-             self._key_switches = self._parent._key_switches
 
-             return
 
-         if not self.session._flushing:
 
-             self.session.flush()
 
-         self._new = weakref.WeakKeyDictionary()
 
-         self._deleted = weakref.WeakKeyDictionary()
 
-         self._dirty = weakref.WeakKeyDictionary()
 
-         self._key_switches = weakref.WeakKeyDictionary()
 
-     def _restore_snapshot(self, dirty_only=False):
 
-         """Restore the restoration state taken before a transaction began.
 
-         Corresponds to a rollback.
 
-         """
 
-         assert self._is_transaction_boundary
 
-         self.session._expunge_states(
 
-             set(self._new).union(self.session._new),
 
-             to_transient=True)
 
-         for s, (oldkey, newkey) in self._key_switches.items():
 
-             self.session.identity_map.safe_discard(s)
 
-             s.key = oldkey
 
-             self.session.identity_map.replace(s)
 
-         for s in set(self._deleted).union(self.session._deleted):
 
-             self.session._update_impl(s, revert_deletion=True)
 
-         assert not self.session._deleted
 
-         for s in self.session.identity_map.all_states():
 
-             if not dirty_only or s.modified or s in self._dirty:
 
-                 s._expire(s.dict, self.session.identity_map._modified)
 
-     def _remove_snapshot(self):
 
-         """Remove the restoration state taken before a transaction began.
 
-         Corresponds to a commit.
 
-         """
 
-         assert self._is_transaction_boundary
 
-         if not self.nested and self.session.expire_on_commit:
 
-             for s in self.session.identity_map.all_states():
 
-                 s._expire(s.dict, self.session.identity_map._modified)
 
-             statelib.InstanceState._detach_states(
 
-                 list(self._deleted), self.session)
 
-             self._deleted.clear()
 
-         elif self.nested:
 
-             self._parent._new.update(self._new)
 
-             self._parent._dirty.update(self._dirty)
 
-             self._parent._deleted.update(self._deleted)
 
-             self._parent._key_switches.update(self._key_switches)
 
-     def _connection_for_bind(self, bind, execution_options):
 
-         self._assert_active()
 
-         if bind in self._connections:
 
-             if execution_options:
 
-                 util.warn(
 
-                     "Connection is already established for the "
 
-                     "given bind; execution_options ignored")
 
-             return self._connections[bind][0]
 
-         if self._parent:
 
-             conn = self._parent._connection_for_bind(bind, execution_options)
 
-             if not self.nested:
 
-                 return conn
 
-         else:
 
-             if isinstance(bind, engine.Connection):
 
-                 conn = bind
 
-                 if conn.engine in self._connections:
 
-                     raise sa_exc.InvalidRequestError(
 
-                         "Session already has a Connection associated for the "
 
-                         "given Connection's Engine")
 
-             else:
 
-                 conn = bind.contextual_connect()
 
-         if execution_options:
 
-             conn = conn.execution_options(**execution_options)
 
-         if self.session.twophase and self._parent is None:
 
-             transaction = conn.begin_twophase()
 
-         elif self.nested:
 
-             transaction = conn.begin_nested()
 
-         else:
 
-             transaction = conn.begin()
 
-         self._connections[conn] = self._connections[conn.engine] = \
 
-             (conn, transaction, conn is not bind)
 
-         self.session.dispatch.after_begin(self.session, self, conn)
 
-         return conn
 
-     def prepare(self):
 
-         if self._parent is not None or not self.session.twophase:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "'twophase' mode not enabled, or not root transaction; "
 
-                 "can't prepare.")
 
-         self._prepare_impl()
 
-     def _prepare_impl(self):
 
-         self._assert_active()
 
-         if self._parent is None or self.nested:
 
-             self.session.dispatch.before_commit(self.session)
 
-         stx = self.session.transaction
 
-         if stx is not self:
 
-             for subtransaction in stx._iterate_self_and_parents(upto=self):
 
-                 subtransaction.commit()
 
-         if not self.session._flushing:
 
-             for _flush_guard in range(100):
 
-                 if self.session._is_clean():
 
-                     break
 
-                 self.session.flush()
 
-             else:
 
-                 raise exc.FlushError(
 
-                     "Over 100 subsequent flushes have occurred within "
 
-                     "session.commit() - is an after_flush() hook "
 
-                     "creating new objects?")
 
-         if self._parent is None and self.session.twophase:
 
-             try:
 
-                 for t in set(self._connections.values()):
 
-                     t[1].prepare()
 
-             except:
 
-                 with util.safe_reraise():
 
-                     self.rollback()
 
-         self._state = PREPARED
 
-     def commit(self):
 
-         self._assert_active(prepared_ok=True)
 
-         if self._state is not PREPARED:
 
-             self._prepare_impl()
 
-         if self._parent is None or self.nested:
 
-             for t in set(self._connections.values()):
 
-                 t[1].commit()
 
-             self._state = COMMITTED
 
-             self.session.dispatch.after_commit(self.session)
 
-             if self.session._enable_transaction_accounting:
 
-                 self._remove_snapshot()
 
-         self.close()
 
-         return self._parent
 
-     def rollback(self, _capture_exception=False):
 
-         self._assert_active(prepared_ok=True, rollback_ok=True)
 
-         stx = self.session.transaction
 
-         if stx is not self:
 
-             for subtransaction in stx._iterate_self_and_parents(upto=self):
 
-                 subtransaction.close()
 
-         boundary = self
 
-         rollback_err = None
 
-         if self._state in (ACTIVE, PREPARED):
 
-             for transaction in self._iterate_self_and_parents():
 
-                 if transaction._parent is None or transaction.nested:
 
-                     try:
 
-                         transaction._rollback_impl()
 
-                     except:
 
-                         rollback_err = sys.exc_info()
 
-                     transaction._state = DEACTIVE
 
-                     boundary = transaction
 
-                     break
 
-                 else:
 
-                     transaction._state = DEACTIVE
 
-         sess = self.session
 
-         if not rollback_err and sess._enable_transaction_accounting and \
 
-                 not sess._is_clean():
 
-             # if items were added, deleted, or mutated
 
-             # here, we need to re-restore the snapshot
 
-             util.warn(
 
-                 "Session's state has been changed on "
 
-                 "a non-active transaction - this state "
 
-                 "will be discarded.")
 
-             boundary._restore_snapshot(dirty_only=boundary.nested)
 
-         self.close()
 
-         if self._parent and _capture_exception:
 
-             self._parent._rollback_exception = sys.exc_info()[1]
 
-         if rollback_err:
 
-             util.reraise(*rollback_err)
 
-         sess.dispatch.after_soft_rollback(sess, self)
 
-         return self._parent
 
-     def _rollback_impl(self):
 
-         try:
 
-             for t in set(self._connections.values()):
 
-                 t[1].rollback()
 
-         finally:
 
-             if self.session._enable_transaction_accounting:
 
-                 self._restore_snapshot(dirty_only=self.nested)
 
-         self.session.dispatch.after_rollback(self.session)
 
-     def close(self, invalidate=False):
 
-         self.session.transaction = self._parent
 
-         if self._parent is None:
 
-             for connection, transaction, autoclose in \
 
-                     set(self._connections.values()):
 
-                 if invalidate:
 
-                     connection.invalidate()
 
-                 if autoclose:
 
-                     connection.close()
 
-                 else:
 
-                     transaction.close()
 
-         self._state = CLOSED
 
-         self.session.dispatch.after_transaction_end(self.session, self)
 
-         if self._parent is None:
 
-             if not self.session.autocommit:
 
-                 self.session.begin()
 
-         self.session = None
 
-         self._connections = None
 
-     def __enter__(self):
 
-         return self
 
-     def __exit__(self, type, value, traceback):
 
-         self._assert_active(deactive_ok=True, prepared_ok=True)
 
-         if self.session.transaction is None:
 
-             return
 
-         if type is None:
 
-             try:
 
-                 self.commit()
 
-             except:
 
-                 with util.safe_reraise():
 
-                     self.rollback()
 
-         else:
 
-             self.rollback()
 
- class Session(_SessionClassMethods):
 
-     """Manages persistence operations for ORM-mapped objects.
 
-     The Session's usage paradigm is described at :doc:`/orm/session`.
 
-     """
 
-     public_methods = (
 
-         '__contains__', '__iter__', 'add', 'add_all', 'begin', 'begin_nested',
 
-         'close', 'commit', 'connection', 'delete', 'execute', 'expire',
 
-         'expire_all', 'expunge', 'expunge_all', 'flush', 'get_bind',
 
-         'is_modified', 'bulk_save_objects', 'bulk_insert_mappings',
 
-         'bulk_update_mappings',
 
-         'merge', 'query', 'refresh', 'rollback',
 
-         'scalar')
 
-     def __init__(self, bind=None, autoflush=True, expire_on_commit=True,
 
-                  _enable_transaction_accounting=True,
 
-                  autocommit=False, twophase=False,
 
-                  weak_identity_map=True, binds=None, extension=None,
 
-                  info=None,
 
-                  query_cls=query.Query):
 
-         r"""Construct a new Session.
 
-         See also the :class:`.sessionmaker` function which is used to
 
-         generate a :class:`.Session`-producing callable with a given
 
-         set of arguments.
 
-         :param autocommit:
 
-           .. warning::
 
-              The autocommit flag is **not for general use**, and if it is
 
-              used, queries should only be invoked within the span of a
 
-              :meth:`.Session.begin` / :meth:`.Session.commit` pair.  Executing
 
-              queries outside of a demarcated transaction is a legacy mode
 
-              of usage, and can in some cases lead to concurrent connection
 
-              checkouts.
 
-           Defaults to ``False``. When ``True``, the
 
-           :class:`.Session` does not keep a persistent transaction running,
 
-           and will acquire connections from the engine on an as-needed basis,
 
-           returning them immediately after their use. Flushes will begin and
 
-           commit (or possibly rollback) their own transaction if no
 
-           transaction is present. When using this mode, the
 
-           :meth:`.Session.begin` method is used to explicitly start
 
-           transactions.
 
-           .. seealso::
 
-             :ref:`session_autocommit`
 
-         :param autoflush: When ``True``, all query operations will issue a
 
-            :meth:`~.Session.flush` call to this ``Session`` before proceeding.
 
-            This is a convenience feature so that :meth:`~.Session.flush` need
 
-            not be called repeatedly in order for database queries to retrieve
 
-            results. It's typical that ``autoflush`` is used in conjunction
 
-            with ``autocommit=False``. In this scenario, explicit calls to
 
-            :meth:`~.Session.flush` are rarely needed; you usually only need to
 
-            call :meth:`~.Session.commit` (which flushes) to finalize changes.
 
-         :param bind: An optional :class:`.Engine` or :class:`.Connection` to
 
-            which this ``Session`` should be bound. When specified, all SQL
 
-            operations performed by this session will execute via this
 
-            connectable.
 
-         :param binds: An optional dictionary which contains more granular
 
-            "bind" information than the ``bind`` parameter provides. This
 
-            dictionary can map individual :class`.Table`
 
-            instances as well as :class:`~.Mapper` instances to individual
 
-            :class:`.Engine` or :class:`.Connection` objects. Operations which
 
-            proceed relative to a particular :class:`.Mapper` will consult this
 
-            dictionary for the direct :class:`.Mapper` instance as
 
-            well as the mapper's ``mapped_table`` attribute in order to locate
 
-            a connectable to use. The full resolution is described in the
 
-            :meth:`.Session.get_bind`.
 
-            Usage looks like::
 
-             Session = sessionmaker(binds={
 
-                 SomeMappedClass: create_engine('postgresql://engine1'),
 
-                 somemapper: create_engine('postgresql://engine2'),
 
-                 some_table: create_engine('postgresql://engine3'),
 
-                 })
 
-           Also see the :meth:`.Session.bind_mapper`
 
-           and :meth:`.Session.bind_table` methods.
 
-         :param \class_: Specify an alternate class other than
 
-            ``sqlalchemy.orm.session.Session`` which should be used by the
 
-            returned class. This is the only argument that is local to the
 
-            :class:`.sessionmaker` function, and is not sent directly to the
 
-            constructor for ``Session``.
 
-         :param _enable_transaction_accounting:  Defaults to ``True``.  A
 
-            legacy-only flag which when ``False`` disables *all* 0.5-style
 
-            object accounting on transaction boundaries, including auto-expiry
 
-            of instances on rollback and commit, maintenance of the "new" and
 
-            "deleted" lists upon rollback, and autoflush of pending changes
 
-            upon :meth:`~.Session.begin`, all of which are interdependent.
 
-         :param expire_on_commit:  Defaults to ``True``. When ``True``, all
 
-            instances will be fully expired after each :meth:`~.commit`,
 
-            so that all attribute/object access subsequent to a completed
 
-            transaction will load from the most recent database state.
 
-         :param extension: An optional
 
-            :class:`~.SessionExtension` instance, or a list
 
-            of such instances, which will receive pre- and post- commit and
 
-            flush events, as well as a post-rollback event. **Deprecated.**
 
-            Please see :class:`.SessionEvents`.
 
-         :param info: optional dictionary of arbitrary data to be associated
 
-            with this :class:`.Session`.  Is available via the
 
-            :attr:`.Session.info` attribute.  Note the dictionary is copied at
 
-            construction time so that modifications to the per-
 
-            :class:`.Session` dictionary will be local to that
 
-            :class:`.Session`.
 
-            .. versionadded:: 0.9.0
 
-         :param query_cls:  Class which should be used to create new Query
 
-           objects, as returned by the :meth:`~.Session.query` method.
 
-           Defaults to :class:`.Query`.
 
-         :param twophase:  When ``True``, all transactions will be started as
 
-             a "two phase" transaction, i.e. using the "two phase" semantics
 
-             of the database in use along with an XID.  During a
 
-             :meth:`~.commit`, after :meth:`~.flush` has been issued for all
 
-             attached databases, the :meth:`~.TwoPhaseTransaction.prepare`
 
-             method on each database's :class:`.TwoPhaseTransaction` will be
 
-             called. This allows each database to roll back the entire
 
-             transaction, before each transaction is committed.
 
-         :param weak_identity_map:  Defaults to ``True`` - when set to
 
-            ``False``, objects placed in the :class:`.Session` will be
 
-            strongly referenced until explicitly removed or the
 
-            :class:`.Session` is closed.  **Deprecated** - The strong
 
-            reference identity map is legacy.  See the
 
-            recipe at :ref:`session_referencing_behavior` for
 
-            an event-based approach to maintaining strong identity
 
-            references.
 
-         """
 
-         if weak_identity_map:
 
-             self._identity_cls = identity.WeakInstanceDict
 
-         else:
 
-             util.warn_deprecated(
 
-                 "weak_identity_map=False is deprecated.  "
 
-                 "See the documentation on 'Session Referencing Behavior' "
 
-                 "for an event-based approach to maintaining strong identity "
 
-                 "references.")
 
-             self._identity_cls = identity.StrongInstanceDict
 
-         self.identity_map = self._identity_cls()
 
-         self._new = {}   # InstanceState->object, strong refs object
 
-         self._deleted = {}  # same
 
-         self.bind = bind
 
-         self.__binds = {}
 
-         self._flushing = False
 
-         self._warn_on_events = False
 
-         self.transaction = None
 
-         self.hash_key = _new_sessionid()
 
-         self.autoflush = autoflush
 
-         self.autocommit = autocommit
 
-         self.expire_on_commit = expire_on_commit
 
-         self._enable_transaction_accounting = _enable_transaction_accounting
 
-         self.twophase = twophase
 
-         self._query_cls = query_cls
 
-         if info:
 
-             self.info.update(info)
 
-         if extension:
 
-             for ext in util.to_list(extension):
 
-                 SessionExtension._adapt_listener(self, ext)
 
-         if binds is not None:
 
-             for key, bind in binds.items():
 
-                 self._add_bind(key, bind)
 
-         if not self.autocommit:
 
-             self.begin()
 
-         _sessions[self.hash_key] = self
 
-     connection_callable = None
 
-     transaction = None
 
-     """The current active or inactive :class:`.SessionTransaction`."""
 
-     @util.memoized_property
 
-     def info(self):
 
-         """A user-modifiable dictionary.
 
-         The initial value of this dictionary can be populated using the
 
-         ``info`` argument to the :class:`.Session` constructor or
 
-         :class:`.sessionmaker` constructor or factory methods.  The dictionary
 
-         here is always local to this :class:`.Session` and can be modified
 
-         independently of all other :class:`.Session` objects.
 
-         .. versionadded:: 0.9.0
 
-         """
 
-         return {}
 
-     def begin(self, subtransactions=False, nested=False):
 
-         """Begin a transaction on this :class:`.Session`.
 
-         The :meth:`.Session.begin` method is only
 
-         meaningful if this session is in **autocommit mode** prior to
 
-         it being called; see :ref:`session_autocommit` for background
 
-         on this setting.
 
-         The method will raise an error if this :class:`.Session`
 
-         is already inside of a transaction, unless
 
-         :paramref:`.Session.begin.subtransactions` or
 
-         :paramref:`.Session.begin.nested` are specified.
 
-         :param subtransactions: if True, indicates that this
 
-          :meth:`~.Session.begin` can create a subtransaction if a transaction
 
-          is already in progress. For documentation on subtransactions, please
 
-          see :ref:`session_subtransactions`.
 
-         :param nested: if True, begins a SAVEPOINT transaction and is equivalent
 
-          to calling :meth:`~.Session.begin_nested`. For documentation on
 
-          SAVEPOINT transactions, please see :ref:`session_begin_nested`.
 
-         :return: the :class:`.SessionTransaction` object.  Note that
 
-          :class:`.SessionTransaction`
 
-          acts as a Python context manager, allowing :meth:`.Session.begin`
 
-          to be used in a "with" block.  See :ref:`session_autocommit` for
 
-          an example.
 
-         .. seealso::
 
-             :ref:`session_autocommit`
 
-             :meth:`.Session.begin_nested`
 
-         """
 
-         if self.transaction is not None:
 
-             if subtransactions or nested:
 
-                 self.transaction = self.transaction._begin(
 
-                     nested=nested)
 
-             else:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "A transaction is already begun.  Use "
 
-                     "subtransactions=True to allow subtransactions.")
 
-         else:
 
-             self.transaction = SessionTransaction(
 
-                 self, nested=nested)
 
-         return self.transaction  # needed for __enter__/__exit__ hook
 
-     def begin_nested(self):
 
-         """Begin a "nested" transaction on this Session, e.g. SAVEPOINT.
 
-         The target database(s) and associated drivers must support SQL
 
-         SAVEPOINT for this method to function correctly.
 
-         For documentation on SAVEPOINT
 
-         transactions, please see :ref:`session_begin_nested`.
 
-         :return: the :class:`.SessionTransaction` object.  Note that
 
-          :class:`.SessionTransaction` acts as a context manager, allowing
 
-          :meth:`.Session.begin_nested` to be used in a "with" block.
 
-          See :ref:`session_begin_nested` for a usage example.
 
-         .. seealso::
 
-             :ref:`session_begin_nested`
 
-             :ref:`pysqlite_serializable` - special workarounds required
 
-             with the SQLite driver in order for SAVEPOINT to work
 
-             correctly.
 
-         """
 
-         return self.begin(nested=True)
 
-     def rollback(self):
 
-         """Rollback the current transaction in progress.
 
-         If no transaction is in progress, this method is a pass-through.
 
-         This method rolls back the current transaction or nested transaction
 
-         regardless of subtransactions being in effect.  All subtransactions up
 
-         to the first real transaction are closed.  Subtransactions occur when
 
-         :meth:`.begin` is called multiple times.
 
-         .. seealso::
 
-             :ref:`session_rollback`
 
-         """
 
-         if self.transaction is None:
 
-             pass
 
-         else:
 
-             self.transaction.rollback()
 
-     def commit(self):
 
-         """Flush pending changes and commit the current transaction.
 
-         If no transaction is in progress, this method raises an
 
-         :exc:`~sqlalchemy.exc.InvalidRequestError`.
 
-         By default, the :class:`.Session` also expires all database
 
-         loaded state on all ORM-managed attributes after transaction commit.
 
-         This so that subsequent operations load the most recent
 
-         data from the database.   This behavior can be disabled using
 
-         the ``expire_on_commit=False`` option to :class:`.sessionmaker` or
 
-         the :class:`.Session` constructor.
 
-         If a subtransaction is in effect (which occurs when begin() is called
 
-         multiple times), the subtransaction will be closed, and the next call
 
-         to ``commit()`` will operate on the enclosing transaction.
 
-         When using the :class:`.Session` in its default mode of
 
-         ``autocommit=False``, a new transaction will
 
-         be begun immediately after the commit, but note that the newly begun
 
-         transaction does *not* use any connection resources until the first
 
-         SQL is actually emitted.
 
-         .. seealso::
 
-             :ref:`session_committing`
 
-         """
 
-         if self.transaction is None:
 
-             if not self.autocommit:
 
-                 self.begin()
 
-             else:
 
-                 raise sa_exc.InvalidRequestError("No transaction is begun.")
 
-         self.transaction.commit()
 
-     def prepare(self):
 
-         """Prepare the current transaction in progress for two phase commit.
 
-         If no transaction is in progress, this method raises an
 
-         :exc:`~sqlalchemy.exc.InvalidRequestError`.
 
-         Only root transactions of two phase sessions can be prepared. If the
 
-         current transaction is not such, an
 
-         :exc:`~sqlalchemy.exc.InvalidRequestError` is raised.
 
-         """
 
-         if self.transaction is None:
 
-             if not self.autocommit:
 
-                 self.begin()
 
-             else:
 
-                 raise sa_exc.InvalidRequestError("No transaction is begun.")
 
-         self.transaction.prepare()
 
-     def connection(self, mapper=None, clause=None,
 
-                    bind=None,
 
-                    close_with_result=False,
 
-                    execution_options=None,
 
-                    **kw):
 
-         r"""Return a :class:`.Connection` object corresponding to this
 
-         :class:`.Session` object's transactional state.
 
-         If this :class:`.Session` is configured with ``autocommit=False``,
 
-         either the :class:`.Connection` corresponding to the current
 
-         transaction is returned, or if no transaction is in progress, a new
 
-         one is begun and the :class:`.Connection` returned (note that no
 
-         transactional state is established with the DBAPI until the first
 
-         SQL statement is emitted).
 
-         Alternatively, if this :class:`.Session` is configured with
 
-         ``autocommit=True``, an ad-hoc :class:`.Connection` is returned
 
-         using :meth:`.Engine.contextual_connect` on the underlying
 
-         :class:`.Engine`.
 
-         Ambiguity in multi-bind or unbound :class:`.Session` objects can be
 
-         resolved through any of the optional keyword arguments.   This
 
-         ultimately makes usage of the :meth:`.get_bind` method for resolution.
 
-         :param bind:
 
-           Optional :class:`.Engine` to be used as the bind.  If
 
-           this engine is already involved in an ongoing transaction,
 
-           that connection will be used.  This argument takes precedence
 
-           over ``mapper``, ``clause``.
 
-         :param mapper:
 
-           Optional :func:`.mapper` mapped class, used to identify
 
-           the appropriate bind.  This argument takes precedence over
 
-           ``clause``.
 
-         :param clause:
 
-             A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
 
-             :func:`~.sql.expression.text`,
 
-             etc.) which will be used to locate a bind, if a bind
 
-             cannot otherwise be identified.
 
-         :param close_with_result: Passed to :meth:`.Engine.connect`,
 
-           indicating the :class:`.Connection` should be considered
 
-           "single use", automatically closing when the first result set is
 
-           closed.  This flag only has an effect if this :class:`.Session` is
 
-           configured with ``autocommit=True`` and does not already have a
 
-           transaction in progress.
 
-         :param execution_options: a dictionary of execution options that will
 
-          be passed to :meth:`.Connection.execution_options`, **when the
 
-          connection is first procured only**.   If the connection is already
 
-          present within the :class:`.Session`, a warning is emitted and
 
-          the arguments are ignored.
 
-          .. versionadded:: 0.9.9
 
-          .. seealso::
 
-             :ref:`session_transaction_isolation`
 
-         :param \**kw:
 
-           Additional keyword arguments are sent to :meth:`get_bind()`,
 
-           allowing additional arguments to be passed to custom
 
-           implementations of :meth:`get_bind`.
 
-         """
 
-         if bind is None:
 
-             bind = self.get_bind(mapper, clause=clause, **kw)
 
-         return self._connection_for_bind(bind,
 
-                                          close_with_result=close_with_result,
 
-                                          execution_options=execution_options)
 
-     def _connection_for_bind(self, engine, execution_options=None, **kw):
 
-         if self.transaction is not None:
 
-             return self.transaction._connection_for_bind(
 
-                 engine, execution_options)
 
-         else:
 
-             conn = engine.contextual_connect(**kw)
 
-             if execution_options:
 
-                 conn = conn.execution_options(**execution_options)
 
-             return conn
 
-     def execute(self, clause, params=None, mapper=None, bind=None, **kw):
 
-         r"""Execute a SQL expression construct or string statement within
 
-         the current transaction.
 
-         Returns a :class:`.ResultProxy` representing
 
-         results of the statement execution, in the same manner as that of an
 
-         :class:`.Engine` or
 
-         :class:`.Connection`.
 
-         E.g.::
 
-             result = session.execute(
 
-                         user_table.select().where(user_table.c.id == 5)
 
-                     )
 
-         :meth:`~.Session.execute` accepts any executable clause construct,
 
-         such as :func:`~.sql.expression.select`,
 
-         :func:`~.sql.expression.insert`,
 
-         :func:`~.sql.expression.update`,
 
-         :func:`~.sql.expression.delete`, and
 
-         :func:`~.sql.expression.text`.  Plain SQL strings can be passed
 
-         as well, which in the case of :meth:`.Session.execute` only
 
-         will be interpreted the same as if it were passed via a
 
-         :func:`~.expression.text` construct.  That is, the following usage::
 
-             result = session.execute(
 
-                         "SELECT * FROM user WHERE id=:param",
 
-                         {"param":5}
 
-                     )
 
-         is equivalent to::
 
-             from sqlalchemy import text
 
-             result = session.execute(
 
-                         text("SELECT * FROM user WHERE id=:param"),
 
-                         {"param":5}
 
-                     )
 
-         The second positional argument to :meth:`.Session.execute` is an
 
-         optional parameter set.  Similar to that of
 
-         :meth:`.Connection.execute`, whether this is passed as a single
 
-         dictionary, or a list of dictionaries, determines whether the DBAPI
 
-         cursor's ``execute()`` or ``executemany()`` is used to execute the
 
-         statement.   An INSERT construct may be invoked for a single row::
 
-             result = session.execute(
 
-                 users.insert(), {"id": 7, "name": "somename"})
 
-         or for multiple rows::
 
-             result = session.execute(users.insert(), [
 
-                                     {"id": 7, "name": "somename7"},
 
-                                     {"id": 8, "name": "somename8"},
 
-                                     {"id": 9, "name": "somename9"}
 
-                                 ])
 
-         The statement is executed within the current transactional context of
 
-         this :class:`.Session`.   The :class:`.Connection` which is used
 
-         to execute the statement can also be acquired directly by
 
-         calling the :meth:`.Session.connection` method.  Both methods use
 
-         a rule-based resolution scheme in order to determine the
 
-         :class:`.Connection`, which in the average case is derived directly
 
-         from the "bind" of the :class:`.Session` itself, and in other cases
 
-         can be based on the :func:`.mapper`
 
-         and :class:`.Table` objects passed to the method; see the
 
-         documentation for :meth:`.Session.get_bind` for a full description of
 
-         this scheme.
 
-         The :meth:`.Session.execute` method does *not* invoke autoflush.
 
-         The :class:`.ResultProxy` returned by the :meth:`.Session.execute`
 
-         method is returned with the "close_with_result" flag set to true;
 
-         the significance of this flag is that if this :class:`.Session` is
 
-         autocommitting and does not have a transaction-dedicated
 
-         :class:`.Connection` available, a temporary :class:`.Connection` is
 
-         established for the statement execution, which is closed (meaning,
 
-         returned to the connection pool) when the :class:`.ResultProxy` has
 
-         consumed all available data. This applies *only* when the
 
-         :class:`.Session` is configured with autocommit=True and no
 
-         transaction has been started.
 
-         :param clause:
 
-             An executable statement (i.e. an :class:`.Executable` expression
 
-             such as :func:`.expression.select`) or string SQL statement
 
-             to be executed.
 
-         :param params:
 
-             Optional dictionary, or list of dictionaries, containing
 
-             bound parameter values.   If a single dictionary, single-row
 
-             execution occurs; if a list of dictionaries, an
 
-             "executemany" will be invoked.  The keys in each dictionary
 
-             must correspond to parameter names present in the statement.
 
-         :param mapper:
 
-           Optional :func:`.mapper` or mapped class, used to identify
 
-           the appropriate bind.  This argument takes precedence over
 
-           ``clause`` when locating a bind.   See :meth:`.Session.get_bind`
 
-           for more details.
 
-         :param bind:
 
-           Optional :class:`.Engine` to be used as the bind.  If
 
-           this engine is already involved in an ongoing transaction,
 
-           that connection will be used.  This argument takes
 
-           precedence over ``mapper`` and ``clause`` when locating
 
-           a bind.
 
-         :param \**kw:
 
-           Additional keyword arguments are sent to :meth:`.Session.get_bind()`
 
-           to allow extensibility of "bind" schemes.
 
-         .. seealso::
 
-             :ref:`sqlexpression_toplevel` - Tutorial on using Core SQL
 
-             constructs.
 
-             :ref:`connections_toplevel` - Further information on direct
 
-             statement execution.
 
-             :meth:`.Connection.execute` - core level statement execution
 
-             method, which is :meth:`.Session.execute` ultimately uses
 
-             in order to execute the statement.
 
-         """
 
-         clause = expression._literal_as_text(clause)
 
-         if bind is None:
 
-             bind = self.get_bind(mapper, clause=clause, **kw)
 
-         return self._connection_for_bind(
 
-             bind, close_with_result=True).execute(clause, params or {})
 
-     def scalar(self, clause, params=None, mapper=None, bind=None, **kw):
 
-         """Like :meth:`~.Session.execute` but return a scalar result."""
 
-         return self.execute(
 
-             clause, params=params, mapper=mapper, bind=bind, **kw).scalar()
 
-     def close(self):
 
-         """Close this Session.
 
-         This clears all items and ends any transaction in progress.
 
-         If this session were created with ``autocommit=False``, a new
 
-         transaction is immediately begun.  Note that this new transaction does
 
-         not use any connection resources until they are first needed.
 
-         """
 
-         self._close_impl(invalidate=False)
 
-     def invalidate(self):
 
-         """Close this Session, using connection invalidation.
 
-         This is a variant of :meth:`.Session.close` that will additionally
 
-         ensure that the :meth:`.Connection.invalidate` method will be called
 
-         on all :class:`.Connection` objects.  This can be called when
 
-         the database is known to be in a state where the connections are
 
-         no longer safe to be used.
 
-         E.g.::
 
-             try:
 
-                 sess = Session()
 
-                 sess.add(User())
 
-                 sess.commit()
 
-             except gevent.Timeout:
 
-                 sess.invalidate()
 
-                 raise
 
-             except:
 
-                 sess.rollback()
 
-                 raise
 
-         This clears all items and ends any transaction in progress.
 
-         If this session were created with ``autocommit=False``, a new
 
-         transaction is immediately begun.  Note that this new transaction does
 
-         not use any connection resources until they are first needed.
 
-         .. versionadded:: 0.9.9
 
-         """
 
-         self._close_impl(invalidate=True)
 
-     def _close_impl(self, invalidate):
 
-         self.expunge_all()
 
-         if self.transaction is not None:
 
-             for transaction in self.transaction._iterate_self_and_parents():
 
-                 transaction.close(invalidate)
 
-     def expunge_all(self):
 
-         """Remove all object instances from this ``Session``.
 
-         This is equivalent to calling ``expunge(obj)`` on all objects in this
 
-         ``Session``.
 
-         """
 
-         all_states = self.identity_map.all_states() + list(self._new)
 
-         self.identity_map = self._identity_cls()
 
-         self._new = {}
 
-         self._deleted = {}
 
-         statelib.InstanceState._detach_states(
 
-             all_states, self
 
-         )
 
-     def _add_bind(self, key, bind):
 
-         try:
 
-             insp = inspect(key)
 
-         except sa_exc.NoInspectionAvailable:
 
-             if not isinstance(key, type):
 
-                 raise sa_exc.ArgumentError(
 
-                     "Not an acceptable bind target: %s" % key)
 
-             else:
 
-                 self.__binds[key] = bind
 
-         else:
 
-             if insp.is_selectable:
 
-                 self.__binds[insp] = bind
 
-             elif insp.is_mapper:
 
-                 self.__binds[insp.class_] = bind
 
-                 for selectable in insp._all_tables:
 
-                     self.__binds[selectable] = bind
 
-             else:
 
-                 raise sa_exc.ArgumentError(
 
-                     "Not an acceptable bind target: %s" % key)
 
-     def bind_mapper(self, mapper, bind):
 
-         """Associate a :class:`.Mapper` with a "bind", e.g. a :class:`.Engine`
 
-         or :class:`.Connection`.
 
-         The given mapper is added to a lookup used by the
 
-         :meth:`.Session.get_bind` method.
 
-         """
 
-         self._add_bind(mapper, bind)
 
-     def bind_table(self, table, bind):
 
-         """Associate a :class:`.Table` with a "bind", e.g. a :class:`.Engine`
 
-         or :class:`.Connection`.
 
-         The given mapper is added to a lookup used by the
 
-         :meth:`.Session.get_bind` method.
 
-         """
 
-         self._add_bind(table, bind)
 
-     def get_bind(self, mapper=None, clause=None):
 
-         """Return a "bind" to which this :class:`.Session` is bound.
 
-         The "bind" is usually an instance of :class:`.Engine`,
 
-         except in the case where the :class:`.Session` has been
 
-         explicitly bound directly to a :class:`.Connection`.
 
-         For a multiply-bound or unbound :class:`.Session`, the
 
-         ``mapper`` or ``clause`` arguments are used to determine the
 
-         appropriate bind to return.
 
-         Note that the "mapper" argument is usually present
 
-         when :meth:`.Session.get_bind` is called via an ORM
 
-         operation such as a :meth:`.Session.query`, each
 
-         individual INSERT/UPDATE/DELETE operation within a
 
-         :meth:`.Session.flush`, call, etc.
 
-         The order of resolution is:
 
-         1. if mapper given and session.binds is present,
 
-            locate a bind based on mapper.
 
-         2. if clause given and session.binds is present,
 
-            locate a bind based on :class:`.Table` objects
 
-            found in the given clause present in session.binds.
 
-         3. if session.bind is present, return that.
 
-         4. if clause given, attempt to return a bind
 
-            linked to the :class:`.MetaData` ultimately
 
-            associated with the clause.
 
-         5. if mapper given, attempt to return a bind
 
-            linked to the :class:`.MetaData` ultimately
 
-            associated with the :class:`.Table` or other
 
-            selectable to which the mapper is mapped.
 
-         6. No bind can be found, :exc:`~sqlalchemy.exc.UnboundExecutionError`
 
-            is raised.
 
-         :param mapper:
 
-           Optional :func:`.mapper` mapped class or instance of
 
-           :class:`.Mapper`.   The bind can be derived from a :class:`.Mapper`
 
-           first by consulting the "binds" map associated with this
 
-           :class:`.Session`, and secondly by consulting the :class:`.MetaData`
 
-           associated with the :class:`.Table` to which the :class:`.Mapper`
 
-           is mapped for a bind.
 
-         :param clause:
 
-             A :class:`.ClauseElement` (i.e. :func:`~.sql.expression.select`,
 
-             :func:`~.sql.expression.text`,
 
-             etc.).  If the ``mapper`` argument is not present or could not
 
-             produce a bind, the given expression construct will be searched
 
-             for a bound element, typically a :class:`.Table` associated with
 
-             bound :class:`.MetaData`.
 
-         """
 
-         if mapper is clause is None:
 
-             if self.bind:
 
-                 return self.bind
 
-             else:
 
-                 raise sa_exc.UnboundExecutionError(
 
-                     "This session is not bound to a single Engine or "
 
-                     "Connection, and no context was provided to locate "
 
-                     "a binding.")
 
-         if mapper is not None:
 
-             try:
 
-                 mapper = inspect(mapper)
 
-             except sa_exc.NoInspectionAvailable:
 
-                 if isinstance(mapper, type):
 
-                     raise exc.UnmappedClassError(mapper)
 
-                 else:
 
-                     raise
 
-         if self.__binds:
 
-             if mapper:
 
-                 for cls in mapper.class_.__mro__:
 
-                     if cls in self.__binds:
 
-                         return self.__binds[cls]
 
-                 if clause is None:
 
-                     clause = mapper.mapped_table
 
-             if clause is not None:
 
-                 for t in sql_util.find_tables(clause, include_crud=True):
 
-                     if t in self.__binds:
 
-                         return self.__binds[t]
 
-         if self.bind:
 
-             return self.bind
 
-         if isinstance(clause, sql.expression.ClauseElement) and clause.bind:
 
-             return clause.bind
 
-         if mapper and mapper.mapped_table.bind:
 
-             return mapper.mapped_table.bind
 
-         context = []
 
-         if mapper is not None:
 
-             context.append('mapper %s' % mapper)
 
-         if clause is not None:
 
-             context.append('SQL expression')
 
-         raise sa_exc.UnboundExecutionError(
 
-             "Could not locate a bind configured on %s or this Session" % (
 
-                 ', '.join(context)))
 
-     def query(self, *entities, **kwargs):
 
-         """Return a new :class:`.Query` object corresponding to this
 
-         :class:`.Session`."""
 
-         return self._query_cls(entities, self, **kwargs)
 
-     @property
 
-     @util.contextmanager
 
-     def no_autoflush(self):
 
-         """Return a context manager that disables autoflush.
 
-         e.g.::
 
-             with session.no_autoflush:
 
-                 some_object = SomeClass()
 
-                 session.add(some_object)
 
-                 # won't autoflush
 
-                 some_object.related_thing = session.query(SomeRelated).first()
 
-         Operations that proceed within the ``with:`` block
 
-         will not be subject to flushes occurring upon query
 
-         access.  This is useful when initializing a series
 
-         of objects which involve existing database queries,
 
-         where the uncompleted object should not yet be flushed.
 
-         .. versionadded:: 0.7.6
 
-         """
 
-         autoflush = self.autoflush
 
-         self.autoflush = False
 
-         try:
 
-             yield self
 
-         finally:
 
-             self.autoflush = autoflush
 
-     def _autoflush(self):
 
-         if self.autoflush and not self._flushing:
 
-             try:
 
-                 self.flush()
 
-             except sa_exc.StatementError as e:
 
-                 # note we are reraising StatementError as opposed to
 
-                 # raising FlushError with "chaining" to remain compatible
 
-                 # with code that catches StatementError, IntegrityError,
 
-                 # etc.
 
-                 e.add_detail(
 
-                     "raised as a result of Query-invoked autoflush; "
 
-                     "consider using a session.no_autoflush block if this "
 
-                     "flush is occurring prematurely")
 
-                 util.raise_from_cause(e)
 
-     def refresh(self, instance, attribute_names=None, lockmode=None):
 
-         """Expire and refresh the attributes on the given instance.
 
-         A query will be issued to the database and all attributes will be
 
-         refreshed with their current database value.
 
-         Lazy-loaded relational attributes will remain lazily loaded, so that
 
-         the instance-wide refresh operation will be followed immediately by
 
-         the lazy load of that attribute.
 
-         Eagerly-loaded relational attributes will eagerly load within the
 
-         single refresh operation.
 
-         Note that a highly isolated transaction will return the same values as
 
-         were previously read in that same transaction, regardless of changes
 
-         in database state outside of that transaction - usage of
 
-         :meth:`~Session.refresh` usually only makes sense if non-ORM SQL
 
-         statement were emitted in the ongoing transaction, or if autocommit
 
-         mode is turned on.
 
-         :param attribute_names: optional.  An iterable collection of
 
-           string attribute names indicating a subset of attributes to
 
-           be refreshed.
 
-         :param lockmode: Passed to the :class:`~sqlalchemy.orm.query.Query`
 
-           as used by :meth:`~sqlalchemy.orm.query.Query.with_lockmode`.
 
-         .. seealso::
 
-             :ref:`session_expire` - introductory material
 
-             :meth:`.Session.expire`
 
-             :meth:`.Session.expire_all`
 
-         """
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         self._expire_state(state, attribute_names)
 
-         if loading.load_on_ident(
 
-                 self.query(object_mapper(instance)),
 
-                 state.key, refresh_state=state,
 
-                 lockmode=lockmode,
 
-                 only_load_props=attribute_names) is None:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Could not refresh instance '%s'" %
 
-                 instance_str(instance))
 
-     def expire_all(self):
 
-         """Expires all persistent instances within this Session.
 
-         When any attributes on a persistent instance is next accessed,
 
-         a query will be issued using the
 
-         :class:`.Session` object's current transactional context in order to
 
-         load all expired attributes for the given instance.   Note that
 
-         a highly isolated transaction will return the same values as were
 
-         previously read in that same transaction, regardless of changes
 
-         in database state outside of that transaction.
 
-         To expire individual objects and individual attributes
 
-         on those objects, use :meth:`Session.expire`.
 
-         The :class:`.Session` object's default behavior is to
 
-         expire all state whenever the :meth:`Session.rollback`
 
-         or :meth:`Session.commit` methods are called, so that new
 
-         state can be loaded for the new transaction.   For this reason,
 
-         calling :meth:`Session.expire_all` should not be needed when
 
-         autocommit is ``False``, assuming the transaction is isolated.
 
-         .. seealso::
 
-             :ref:`session_expire` - introductory material
 
-             :meth:`.Session.expire`
 
-             :meth:`.Session.refresh`
 
-         """
 
-         for state in self.identity_map.all_states():
 
-             state._expire(state.dict, self.identity_map._modified)
 
-     def expire(self, instance, attribute_names=None):
 
-         """Expire the attributes on an instance.
 
-         Marks the attributes of an instance as out of date. When an expired
 
-         attribute is next accessed, a query will be issued to the
 
-         :class:`.Session` object's current transactional context in order to
 
-         load all expired attributes for the given instance.   Note that
 
-         a highly isolated transaction will return the same values as were
 
-         previously read in that same transaction, regardless of changes
 
-         in database state outside of that transaction.
 
-         To expire all objects in the :class:`.Session` simultaneously,
 
-         use :meth:`Session.expire_all`.
 
-         The :class:`.Session` object's default behavior is to
 
-         expire all state whenever the :meth:`Session.rollback`
 
-         or :meth:`Session.commit` methods are called, so that new
 
-         state can be loaded for the new transaction.   For this reason,
 
-         calling :meth:`Session.expire` only makes sense for the specific
 
-         case that a non-ORM SQL statement was emitted in the current
 
-         transaction.
 
-         :param instance: The instance to be refreshed.
 
-         :param attribute_names: optional list of string attribute names
 
-           indicating a subset of attributes to be expired.
 
-         .. seealso::
 
-             :ref:`session_expire` - introductory material
 
-             :meth:`.Session.expire`
 
-             :meth:`.Session.refresh`
 
-         """
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         self._expire_state(state, attribute_names)
 
-     def _expire_state(self, state, attribute_names):
 
-         self._validate_persistent(state)
 
-         if attribute_names:
 
-             state._expire_attributes(state.dict, attribute_names)
 
-         else:
 
-             # pre-fetch the full cascade since the expire is going to
 
-             # remove associations
 
-             cascaded = list(state.manager.mapper.cascade_iterator(
 
-                 'refresh-expire', state))
 
-             self._conditional_expire(state)
 
-             for o, m, st_, dct_ in cascaded:
 
-                 self._conditional_expire(st_)
 
-     def _conditional_expire(self, state):
 
-         """Expire a state if persistent, else expunge if pending"""
 
-         if state.key:
 
-             state._expire(state.dict, self.identity_map._modified)
 
-         elif state in self._new:
 
-             self._new.pop(state)
 
-             state._detach(self)
 
-     @util.deprecated("0.7", "The non-weak-referencing identity map "
 
-                      "feature is no longer needed.")
 
-     def prune(self):
 
-         """Remove unreferenced instances cached in the identity map.
 
-         Note that this method is only meaningful if "weak_identity_map" is set
 
-         to False.  The default weak identity map is self-pruning.
 
-         Removes any object in this Session's identity map that is not
 
-         referenced in user code, modified, new or scheduled for deletion.
 
-         Returns the number of objects pruned.
 
-         """
 
-         return self.identity_map.prune()
 
-     def expunge(self, instance):
 
-         """Remove the `instance` from this ``Session``.
 
-         This will free all internal references to the instance.  Cascading
 
-         will be applied according to the *expunge* cascade rule.
 
-         """
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         if state.session_id is not self.hash_key:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Instance %s is not present in this Session" %
 
-                 state_str(state))
 
-         cascaded = list(state.manager.mapper.cascade_iterator(
 
-             'expunge', state))
 
-         self._expunge_states(
 
-             [state] + [st_ for o, m, st_, dct_ in cascaded]
 
-         )
 
-     def _expunge_states(self, states, to_transient=False):
 
-         for state in states:
 
-             if state in self._new:
 
-                 self._new.pop(state)
 
-             elif self.identity_map.contains_state(state):
 
-                 self.identity_map.safe_discard(state)
 
-                 self._deleted.pop(state, None)
 
-             elif self.transaction:
 
-                 # state is "detached" from being deleted, but still present
 
-                 # in the transaction snapshot
 
-                 self.transaction._deleted.pop(state, None)
 
-         statelib.InstanceState._detach_states(
 
-             states, self, to_transient=to_transient)
 
-     def _register_newly_persistent(self, states):
 
-         pending_to_persistent = self.dispatch.pending_to_persistent or None
 
-         for state in states:
 
-             mapper = _state_mapper(state)
 
-             # prevent against last minute dereferences of the object
 
-             obj = state.obj()
 
-             if obj is not None:
 
-                 instance_key = mapper._identity_key_from_state(state)
 
-                 if _none_set.intersection(instance_key[1]) and \
 
-                         not mapper.allow_partial_pks or \
 
-                         _none_set.issuperset(instance_key[1]):
 
-                     raise exc.FlushError(
 
-                         "Instance %s has a NULL identity key.  If this is an "
 
-                         "auto-generated value, check that the database table "
 
-                         "allows generation of new primary key values, and "
 
-                         "that the mapped Column object is configured to "
 
-                         "expect these generated values.  Ensure also that "
 
-                         "this flush() is not occurring at an inappropriate "
 
-                         "time, such as within a load() event."
 
-                         % state_str(state)
 
-                     )
 
-                 if state.key is None:
 
-                     state.key = instance_key
 
-                 elif state.key != instance_key:
 
-                     # primary key switch. use safe_discard() in case another
 
-                     # state has already replaced this one in the identity
 
-                     # map (see test/orm/test_naturalpks.py ReversePKsTest)
 
-                     self.identity_map.safe_discard(state)
 
-                     if state in self.transaction._key_switches:
 
-                         orig_key = self.transaction._key_switches[state][0]
 
-                     else:
 
-                         orig_key = state.key
 
-                     self.transaction._key_switches[state] = (
 
-                         orig_key, instance_key)
 
-                     state.key = instance_key
 
-                 self.identity_map.replace(state)
 
-         statelib.InstanceState._commit_all_states(
 
-             ((state, state.dict) for state in states),
 
-             self.identity_map
 
-         )
 
-         self._register_altered(states)
 
-         if pending_to_persistent is not None:
 
-             for state in states:
 
-                 pending_to_persistent(self, state.obj())
 
-         # remove from new last, might be the last strong ref
 
-         for state in set(states).intersection(self._new):
 
-             self._new.pop(state)
 
-     def _register_altered(self, states):
 
-         if self._enable_transaction_accounting and self.transaction:
 
-             for state in states:
 
-                 if state in self._new:
 
-                     self.transaction._new[state] = True
 
-                 else:
 
-                     self.transaction._dirty[state] = True
 
-     def _remove_newly_deleted(self, states):
 
-         persistent_to_deleted = self.dispatch.persistent_to_deleted or None
 
-         for state in states:
 
-             if self._enable_transaction_accounting and self.transaction:
 
-                 self.transaction._deleted[state] = True
 
-             if persistent_to_deleted is not None:
 
-                 # get a strong reference before we pop out of
 
-                 # self._deleted
 
-                 obj = state.obj()
 
-             self.identity_map.safe_discard(state)
 
-             self._deleted.pop(state, None)
 
-             state._deleted = True
 
-             # can't call state._detach() here, because this state
 
-             # is still in the transaction snapshot and needs to be
 
-             # tracked as part of that
 
-             if persistent_to_deleted is not None:
 
-                 persistent_to_deleted(self, obj)
 
-     def add(self, instance, _warn=True):
 
-         """Place an object in the ``Session``.
 
-         Its state will be persisted to the database on the next flush
 
-         operation.
 
-         Repeated calls to ``add()`` will be ignored. The opposite of ``add()``
 
-         is ``expunge()``.
 
-         """
 
-         if _warn and self._warn_on_events:
 
-             self._flush_warning("Session.add()")
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         self._save_or_update_state(state)
 
-     def add_all(self, instances):
 
-         """Add the given collection of instances to this ``Session``."""
 
-         if self._warn_on_events:
 
-             self._flush_warning("Session.add_all()")
 
-         for instance in instances:
 
-             self.add(instance, _warn=False)
 
-     def _save_or_update_state(self, state):
 
-         self._save_or_update_impl(state)
 
-         mapper = _state_mapper(state)
 
-         for o, m, st_, dct_ in mapper.cascade_iterator(
 
-                 'save-update',
 
-                 state,
 
-                 halt_on=self._contains_state):
 
-             self._save_or_update_impl(st_)
 
-     def delete(self, instance):
 
-         """Mark an instance as deleted.
 
-         The database delete operation occurs upon ``flush()``.
 
-         """
 
-         if self._warn_on_events:
 
-             self._flush_warning("Session.delete()")
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         self._delete_impl(state, instance, head=True)
 
-     def _delete_impl(self, state, obj, head):
 
-         if state.key is None:
 
-             if head:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "Instance '%s' is not persisted" %
 
-                     state_str(state))
 
-             else:
 
-                 return
 
-         to_attach = self._before_attach(state, obj)
 
-         if state in self._deleted:
 
-             return
 
-         self.identity_map.add(state)
 
-         if to_attach:
 
-             self._after_attach(state, obj)
 
-         if head:
 
-             # grab the cascades before adding the item to the deleted list
 
-             # so that autoflush does not delete the item
 
-             # the strong reference to the instance itself is significant here
 
-             cascade_states = list(state.manager.mapper.cascade_iterator(
 
-                 'delete', state))
 
-         self._deleted[state] = obj
 
-         if head:
 
-             for o, m, st_, dct_ in cascade_states:
 
-                 self._delete_impl(st_, o, False)
 
-     def merge(self, instance, load=True):
 
-         """Copy the state of a given instance into a corresponding instance
 
-         within this :class:`.Session`.
 
-         :meth:`.Session.merge` examines the primary key attributes of the
 
-         source instance, and attempts to reconcile it with an instance of the
 
-         same primary key in the session.   If not found locally, it attempts
 
-         to load the object from the database based on primary key, and if
 
-         none can be located, creates a new instance.  The state of each
 
-         attribute on the source instance is then copied to the target
 
-         instance.  The resulting target instance is then returned by the
 
-         method; the original source instance is left unmodified, and
 
-         un-associated with the :class:`.Session` if not already.
 
-         This operation cascades to associated instances if the association is
 
-         mapped with ``cascade="merge"``.
 
-         See :ref:`unitofwork_merging` for a detailed discussion of merging.
 
-         .. versionchanged:: 1.1 - :meth:`.Session.merge` will now reconcile
 
-            pending objects with overlapping primary keys in the same way
 
-            as persistent.  See :ref:`change_3601` for discussion.
 
-         :param instance: Instance to be merged.
 
-         :param load: Boolean, when False, :meth:`.merge` switches into
 
-          a "high performance" mode which causes it to forego emitting history
 
-          events as well as all database access.  This flag is used for
 
-          cases such as transferring graphs of objects into a :class:`.Session`
 
-          from a second level cache, or to transfer just-loaded objects
 
-          into the :class:`.Session` owned by a worker thread or process
 
-          without re-querying the database.
 
-          The ``load=False`` use case adds the caveat that the given
 
-          object has to be in a "clean" state, that is, has no pending changes
 
-          to be flushed - even if the incoming object is detached from any
 
-          :class:`.Session`.   This is so that when
 
-          the merge operation populates local attributes and
 
-          cascades to related objects and
 
-          collections, the values can be "stamped" onto the
 
-          target object as is, without generating any history or attribute
 
-          events, and without the need to reconcile the incoming data with
 
-          any existing related objects or collections that might not
 
-          be loaded.  The resulting objects from ``load=False`` are always
 
-          produced as "clean", so it is only appropriate that the given objects
 
-          should be "clean" as well, else this suggests a mis-use of the
 
-          method.
 
-         """
 
-         if self._warn_on_events:
 
-             self._flush_warning("Session.merge()")
 
-         _recursive = {}
 
-         _resolve_conflict_map = {}
 
-         if load:
 
-             # flush current contents if we expect to load data
 
-             self._autoflush()
 
-         object_mapper(instance)  # verify mapped
 
-         autoflush = self.autoflush
 
-         try:
 
-             self.autoflush = False
 
-             return self._merge(
 
-                 attributes.instance_state(instance),
 
-                 attributes.instance_dict(instance),
 
-                 load=load, _recursive=_recursive,
 
-                 _resolve_conflict_map=_resolve_conflict_map)
 
-         finally:
 
-             self.autoflush = autoflush
 
-     def _merge(self, state, state_dict, load=True, _recursive=None,
 
-                _resolve_conflict_map=None):
 
-         mapper = _state_mapper(state)
 
-         if state in _recursive:
 
-             return _recursive[state]
 
-         new_instance = False
 
-         key = state.key
 
-         if key is None:
 
-             if not load:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "merge() with load=False option does not support "
 
-                     "objects transient (i.e. unpersisted) objects.  flush() "
 
-                     "all changes on mapped instances before merging with "
 
-                     "load=False.")
 
-             key = mapper._identity_key_from_state(state)
 
-             key_is_persistent = attributes.NEVER_SET not in key[1]
 
-         else:
 
-             key_is_persistent = True
 
-         if key in self.identity_map:
 
-             merged = self.identity_map[key]
 
-         elif key_is_persistent and key in _resolve_conflict_map:
 
-             merged = _resolve_conflict_map[key]
 
-         elif not load:
 
-             if state.modified:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "merge() with load=False option does not support "
 
-                     "objects marked as 'dirty'.  flush() all changes on "
 
-                     "mapped instances before merging with load=False.")
 
-             merged = mapper.class_manager.new_instance()
 
-             merged_state = attributes.instance_state(merged)
 
-             merged_state.key = key
 
-             self._update_impl(merged_state)
 
-             new_instance = True
 
-         elif key_is_persistent and (
 
-             not _none_set.intersection(key[1]) or
 
-             (mapper.allow_partial_pks and
 
-              not _none_set.issuperset(key[1]))):
 
-             merged = self.query(mapper.class_).get(key[1])
 
-         else:
 
-             merged = None
 
-         if merged is None:
 
-             merged = mapper.class_manager.new_instance()
 
-             merged_state = attributes.instance_state(merged)
 
-             merged_dict = attributes.instance_dict(merged)
 
-             new_instance = True
 
-             self._save_or_update_state(merged_state)
 
-         else:
 
-             merged_state = attributes.instance_state(merged)
 
-             merged_dict = attributes.instance_dict(merged)
 
-         _recursive[state] = merged
 
-         _resolve_conflict_map[key] = merged
 
-         # check that we didn't just pull the exact same
 
-         # state out.
 
-         if state is not merged_state:
 
-             # version check if applicable
 
-             if mapper.version_id_col is not None:
 
-                 existing_version = mapper._get_state_attr_by_column(
 
-                     state,
 
-                     state_dict,
 
-                     mapper.version_id_col,
 
-                     passive=attributes.PASSIVE_NO_INITIALIZE)
 
-                 merged_version = mapper._get_state_attr_by_column(
 
-                     merged_state,
 
-                     merged_dict,
 
-                     mapper.version_id_col,
 
-                     passive=attributes.PASSIVE_NO_INITIALIZE)
 
-                 if existing_version is not attributes.PASSIVE_NO_RESULT and \
 
-                         merged_version is not attributes.PASSIVE_NO_RESULT and \
 
-                         existing_version != merged_version:
 
-                     raise exc.StaleDataError(
 
-                         "Version id '%s' on merged state %s "
 
-                         "does not match existing version '%s'. "
 
-                         "Leave the version attribute unset when "
 
-                         "merging to update the most recent version."
 
-                         % (
 
-                             existing_version,
 
-                             state_str(merged_state),
 
-                             merged_version
 
-                         ))
 
-             merged_state.load_path = state.load_path
 
-             merged_state.load_options = state.load_options
 
-             # since we are copying load_options, we need to copy
 
-             # the callables_ that would have been generated by those
 
-             # load_options.
 
-             # assumes that the callables we put in state.callables_
 
-             # are not instance-specific (which they should not be)
 
-             merged_state._copy_callables(state)
 
-             for prop in mapper.iterate_properties:
 
-                 prop.merge(self, state, state_dict,
 
-                            merged_state, merged_dict,
 
-                            load, _recursive, _resolve_conflict_map)
 
-         if not load:
 
-             # remove any history
 
-             merged_state._commit_all(merged_dict, self.identity_map)
 
-         if new_instance:
 
-             merged_state.manager.dispatch.load(merged_state, None)
 
-         return merged
 
-     def _validate_persistent(self, state):
 
-         if not self.identity_map.contains_state(state):
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Instance '%s' is not persistent within this Session" %
 
-                 state_str(state))
 
-     def _save_impl(self, state):
 
-         if state.key is not None:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Object '%s' already has an identity - "
 
-                 "it can't be registered as pending" % state_str(state))
 
-         obj = state.obj()
 
-         to_attach = self._before_attach(state, obj)
 
-         if state not in self._new:
 
-             self._new[state] = obj
 
-             state.insert_order = len(self._new)
 
-         if to_attach:
 
-             self._after_attach(state, obj)
 
-     def _update_impl(self, state, revert_deletion=False):
 
-         if state.key is None:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Instance '%s' is not persisted" %
 
-                 state_str(state))
 
-         if state._deleted:
 
-             if revert_deletion:
 
-                 if not state._attached:
 
-                     return
 
-                 del state._deleted
 
-             else:
 
-                 raise sa_exc.InvalidRequestError(
 
-                     "Instance '%s' has been deleted.  "
 
-                     "Use the make_transient() "
 
-                     "function to send this object back "
 
-                     "to the transient state." %
 
-                     state_str(state)
 
-                 )
 
-         obj = state.obj()
 
-         # check for late gc
 
-         if obj is None:
 
-             return
 
-         to_attach = self._before_attach(state, obj)
 
-         self._deleted.pop(state, None)
 
-         if revert_deletion:
 
-             self.identity_map.replace(state)
 
-         else:
 
-             self.identity_map.add(state)
 
-         if to_attach:
 
-             self._after_attach(state, obj)
 
-         elif revert_deletion:
 
-             self.dispatch.deleted_to_persistent(self, obj)
 
-     def _save_or_update_impl(self, state):
 
-         if state.key is None:
 
-             self._save_impl(state)
 
-         else:
 
-             self._update_impl(state)
 
-     def enable_relationship_loading(self, obj):
 
-         """Associate an object with this :class:`.Session` for related
 
-         object loading.
 
-         .. warning::
 
-             :meth:`.enable_relationship_loading` exists to serve special
 
-             use cases and is not recommended for general use.
 
-         Accesses of attributes mapped with :func:`.relationship`
 
-         will attempt to load a value from the database using this
 
-         :class:`.Session` as the source of connectivity.  The values
 
-         will be loaded based on foreign key values present on this
 
-         object - it follows that this functionality
 
-         generally only works for many-to-one-relationships.
 
-         The object will be attached to this session, but will
 
-         **not** participate in any persistence operations; its state
 
-         for almost all purposes will remain either "transient" or
 
-         "detached", except for the case of relationship loading.
 
-         Also note that backrefs will often not work as expected.
 
-         Altering a relationship-bound attribute on the target object
 
-         may not fire off a backref event, if the effective value
 
-         is what was already loaded from a foreign-key-holding value.
 
-         The :meth:`.Session.enable_relationship_loading` method is
 
-         similar to the ``load_on_pending`` flag on :func:`.relationship`.
 
-         Unlike that flag, :meth:`.Session.enable_relationship_loading` allows
 
-         an object to remain transient while still being able to load
 
-         related items.
 
-         To make a transient object associated with a :class:`.Session`
 
-         via :meth:`.Session.enable_relationship_loading` pending, add
 
-         it to the :class:`.Session` using :meth:`.Session.add` normally.
 
-         :meth:`.Session.enable_relationship_loading` does not improve
 
-         behavior when the ORM is used normally - object references should be
 
-         constructed at the object level, not at the foreign key level, so
 
-         that they are present in an ordinary way before flush()
 
-         proceeds.  This method is not intended for general use.
 
-         .. versionadded:: 0.8
 
-         .. seealso::
 
-             ``load_on_pending`` at :func:`.relationship` - this flag
 
-             allows per-relationship loading of many-to-ones on items that
 
-             are pending.
 
-         """
 
-         state = attributes.instance_state(obj)
 
-         to_attach = self._before_attach(state, obj)
 
-         state._load_pending = True
 
-         if to_attach:
 
-             self._after_attach(state, obj)
 
-     def _before_attach(self, state, obj):
 
-         if state.session_id == self.hash_key:
 
-             return False
 
-         if state.session_id and state.session_id in _sessions:
 
-             raise sa_exc.InvalidRequestError(
 
-                 "Object '%s' is already attached to session '%s' "
 
-                 "(this is '%s')" % (state_str(state),
 
-                                     state.session_id, self.hash_key))
 
-         self.dispatch.before_attach(self, obj)
 
-         return True
 
-     def _after_attach(self, state, obj):
 
-         state.session_id = self.hash_key
 
-         if state.modified and state._strong_obj is None:
 
-             state._strong_obj = obj
 
-         self.dispatch.after_attach(self, obj)
 
-         if state.key:
 
-             self.dispatch.detached_to_persistent(self, obj)
 
-         else:
 
-             self.dispatch.transient_to_pending(self, obj)
 
-     def __contains__(self, instance):
 
-         """Return True if the instance is associated with this session.
 
-         The instance may be pending or persistent within the Session for a
 
-         result of True.
 
-         """
 
-         try:
 
-             state = attributes.instance_state(instance)
 
-         except exc.NO_STATE:
 
-             raise exc.UnmappedInstanceError(instance)
 
-         return self._contains_state(state)
 
-     def __iter__(self):
 
-         """Iterate over all pending or persistent instances within this
 
-         Session.
 
-         """
 
-         return iter(
 
-             list(self._new.values()) + list(self.identity_map.values()))
 
-     def _contains_state(self, state):
 
-         return state in self._new or self.identity_map.contains_state(state)
 
-     def flush(self, objects=None):
 
-         """Flush all the object changes to the database.
 
-         Writes out all pending object creations, deletions and modifications
 
-         to the database as INSERTs, DELETEs, UPDATEs, etc.  Operations are
 
-         automatically ordered by the Session's unit of work dependency
 
-         solver.
 
-         Database operations will be issued in the current transactional
 
-         context and do not affect the state of the transaction, unless an
 
-         error occurs, in which case the entire transaction is rolled back.
 
-         You may flush() as often as you like within a transaction to move
 
-         changes from Python to the database's transaction buffer.
 
-         For ``autocommit`` Sessions with no active manual transaction, flush()
 
-         will create a transaction on the fly that surrounds the entire set of
 
-         operations into the flush.
 
-         :param objects: Optional; restricts the flush operation to operate
 
-           only on elements that are in the given collection.
 
-           This feature is for an extremely narrow set of use cases where
 
-           particular objects may need to be operated upon before the
 
-           full flush() occurs.  It is not intended for general use.
 
-         """
 
-         if self._flushing:
 
-             raise sa_exc.InvalidRequestError("Session is already flushing")
 
-         if self._is_clean():
 
-             return
 
-         try:
 
-             self._flushing = True
 
-             self._flush(objects)
 
-         finally:
 
-             self._flushing = False
 
-     def _flush_warning(self, method):
 
-         util.warn(
 
-             "Usage of the '%s' operation is not currently supported "
 
-             "within the execution stage of the flush process. "
 
-             "Results may not be consistent.  Consider using alternative "
 
-             "event listeners or connection-level operations instead."
 
-             % method)
 
-     def _is_clean(self):
 
-         return not self.identity_map.check_modified() and \
 
-             not self._deleted and \
 
-             not self._new
 
-     def _flush(self, objects=None):
 
-         dirty = self._dirty_states
 
-         if not dirty and not self._deleted and not self._new:
 
-             self.identity_map._modified.clear()
 
-             return
 
-         flush_context = UOWTransaction(self)
 
-         if self.dispatch.before_flush:
 
-             self.dispatch.before_flush(self, flush_context, objects)
 
-             # re-establish "dirty states" in case the listeners
 
-             # added
 
-             dirty = self._dirty_states
 
-         deleted = set(self._deleted)
 
-         new = set(self._new)
 
-         dirty = set(dirty).difference(deleted)
 
-         # create the set of all objects we want to operate upon
 
-         if objects:
 
-             # specific list passed in
 
-             objset = set()
 
-             for o in objects:
 
-                 try:
 
-                     state = attributes.instance_state(o)
 
-                 except exc.NO_STATE:
 
-                     raise exc.UnmappedInstanceError(o)
 
-                 objset.add(state)
 
-         else:
 
-             objset = None
 
-         # store objects whose fate has been decided
 
-         processed = set()
 
-         # put all saves/updates into the flush context.  detect top-level
 
-         # orphans and throw them into deleted.
 
-         if objset:
 
-             proc = new.union(dirty).intersection(objset).difference(deleted)
 
-         else:
 
-             proc = new.union(dirty).difference(deleted)
 
-         for state in proc:
 
-             is_orphan = (
 
-                 _state_mapper(state)._is_orphan(state) and state.has_identity)
 
-             _reg = flush_context.register_object(state, isdelete=is_orphan)
 
-             assert _reg, "Failed to add object to the flush context!"
 
-             processed.add(state)
 
-         # put all remaining deletes into the flush context.
 
-         if objset:
 
-             proc = deleted.intersection(objset).difference(processed)
 
-         else:
 
-             proc = deleted.difference(processed)
 
-         for state in proc:
 
-             _reg = flush_context.register_object(state, isdelete=True)
 
-             assert _reg, "Failed to add object to the flush context!"
 
-         if not flush_context.has_work:
 
-             return
 
-         flush_context.transaction = transaction = self.begin(
 
-             subtransactions=True)
 
-         try:
 
-             self._warn_on_events = True
 
-             try:
 
-                 flush_context.execute()
 
-             finally:
 
-                 self._warn_on_events = False
 
-             self.dispatch.after_flush(self, flush_context)
 
-             flush_context.finalize_flush_changes()
 
-             if not objects and self.identity_map._modified:
 
-                 len_ = len(self.identity_map._modified)
 
-                 statelib.InstanceState._commit_all_states(
 
-                     [(state, state.dict) for state in
 
-                      self.identity_map._modified],
 
-                     instance_dict=self.identity_map)
 
-                 util.warn("Attribute history events accumulated on %d "
 
-                           "previously clean instances "
 
-                           "within inner-flush event handlers have been "
 
-                           "reset, and will not result in database updates. "
 
-                           "Consider using set_committed_value() within "
 
-                           "inner-flush event handlers to avoid this warning."
 
-                           % len_)
 
-             # useful assertions:
 
-             # if not objects:
 
-             #    assert not self.identity_map._modified
 
-             # else:
 
-             #    assert self.identity_map._modified == \
 
-             #            self.identity_map._modified.difference(objects)
 
-             self.dispatch.after_flush_postexec(self, flush_context)
 
-             transaction.commit()
 
-         except:
 
-             with util.safe_reraise():
 
-                 transaction.rollback(_capture_exception=True)
 
-     def bulk_save_objects(
 
-             self, objects, return_defaults=False, update_changed_only=True):
 
-         """Perform a bulk save of the given list of objects.
 
-         The bulk save feature allows mapped objects to be used as the
 
-         source of simple INSERT and UPDATE operations which can be more easily
 
-         grouped together into higher performing "executemany"
 
-         operations; the extraction of data from the objects is also performed
 
-         using a lower-latency process that ignores whether or not attributes
 
-         have actually been modified in the case of UPDATEs, and also ignores
 
-         SQL expressions.
 
-         The objects as given are not added to the session and no additional
 
-         state is established on them, unless the ``return_defaults`` flag
 
-         is also set, in which case primary key attributes and server-side
 
-         default values will be populated.
 
-         .. versionadded:: 1.0.0
 
-         .. warning::
 
-             The bulk save feature allows for a lower-latency INSERT/UPDATE
 
-             of rows at the expense of most other unit-of-work features.
 
-             Features such as object management, relationship handling,
 
-             and SQL clause support are **silently omitted** in favor of raw
 
-             INSERT/UPDATES of records.
 
-             **Please read the list of caveats at** :ref:`bulk_operations`
 
-             **before using this method, and fully test and confirm the
 
-             functionality of all code developed using these systems.**
 
-         :param objects: a list of mapped object instances.  The mapped
 
-          objects are persisted as is, and are **not** associated with the
 
-          :class:`.Session` afterwards.
 
-          For each object, whether the object is sent as an INSERT or an
 
-          UPDATE is dependent on the same rules used by the :class:`.Session`
 
-          in traditional operation; if the object has the
 
-          :attr:`.InstanceState.key`
 
-          attribute set, then the object is assumed to be "detached" and
 
-          will result in an UPDATE.  Otherwise, an INSERT is used.
 
-          In the case of an UPDATE, statements are grouped based on which
 
-          attributes have changed, and are thus to be the subject of each
 
-          SET clause.  If ``update_changed_only`` is False, then all
 
-          attributes present within each object are applied to the UPDATE
 
-          statement, which may help in allowing the statements to be grouped
 
-          together into a larger executemany(), and will also reduce the
 
-          overhead of checking history on attributes.
 
-         :param return_defaults: when True, rows that are missing values which
 
-          generate defaults, namely integer primary key defaults and sequences,
 
-          will be inserted **one at a time**, so that the primary key value
 
-          is available.  In particular this will allow joined-inheritance
 
-          and other multi-table mappings to insert correctly without the need
 
-          to provide primary key values ahead of time; however,
 
-          :paramref:`.Session.bulk_save_objects.return_defaults` **greatly
 
-          reduces the performance gains** of the method overall.
 
-         :param update_changed_only: when True, UPDATE statements are rendered
 
-          based on those attributes in each state that have logged changes.
 
-          When False, all attributes present are rendered into the SET clause
 
-          with the exception of primary key attributes.
 
-         .. seealso::
 
-             :ref:`bulk_operations`
 
-             :meth:`.Session.bulk_insert_mappings`
 
-             :meth:`.Session.bulk_update_mappings`
 
-         """
 
-         for (mapper, isupdate), states in itertools.groupby(
 
-             (attributes.instance_state(obj) for obj in objects),
 
-             lambda state: (state.mapper, state.key is not None)
 
-         ):
 
-             self._bulk_save_mappings(
 
-                 mapper, states, isupdate, True,
 
-                 return_defaults, update_changed_only, False)
 
-     def bulk_insert_mappings(
 
-             self, mapper, mappings, return_defaults=False, render_nulls=False):
 
-         """Perform a bulk insert of the given list of mapping dictionaries.
 
-         The bulk insert feature allows plain Python dictionaries to be used as
 
-         the source of simple INSERT operations which can be more easily
 
-         grouped together into higher performing "executemany"
 
-         operations.  Using dictionaries, there is no "history" or session
 
-         state management features in use, reducing latency when inserting
 
-         large numbers of simple rows.
 
-         The values within the dictionaries as given are typically passed
 
-         without modification into Core :meth:`.Insert` constructs, after
 
-         organizing the values within them across the tables to which
 
-         the given mapper is mapped.
 
-         .. versionadded:: 1.0.0
 
-         .. warning::
 
-             The bulk insert feature allows for a lower-latency INSERT
 
-             of rows at the expense of most other unit-of-work features.
 
-             Features such as object management, relationship handling,
 
-             and SQL clause support are **silently omitted** in favor of raw
 
-             INSERT of records.
 
-             **Please read the list of caveats at** :ref:`bulk_operations`
 
-             **before using this method, and fully test and confirm the
 
-             functionality of all code developed using these systems.**
 
-         :param mapper: a mapped class, or the actual :class:`.Mapper` object,
 
-          representing the single kind of object represented within the mapping
 
-          list.
 
-         :param mappings: a list of dictionaries, each one containing the state
 
-          of the mapped row to be inserted, in terms of the attribute names
 
-          on the mapped class.   If the mapping refers to multiple tables,
 
-          such as a joined-inheritance mapping, each dictionary must contain
 
-          all keys to be populated into all tables.
 
-         :param return_defaults: when True, rows that are missing values which
 
-          generate defaults, namely integer primary key defaults and sequences,
 
-          will be inserted **one at a time**, so that the primary key value
 
-          is available.  In particular this will allow joined-inheritance
 
-          and other multi-table mappings to insert correctly without the need
 
-          to provide primary
 
-          key values ahead of time; however,
 
-          :paramref:`.Session.bulk_insert_mappings.return_defaults`
 
-          **greatly reduces the performance gains** of the method overall.
 
-          If the rows
 
-          to be inserted only refer to a single table, then there is no
 
-          reason this flag should be set as the returned default information
 
-          is not used.
 
-         :param render_nulls: When True, a value of ``None`` will result
 
-          in a NULL value being included in the INSERT statement, rather
 
-          than the column being omitted from the INSERT.   This allows all
 
-          the rows being INSERTed to have the identical set of columns which
 
-          allows the full set of rows to be batched to the DBAPI.  Normally,
 
-          each column-set that contains a different combination of NULL values
 
-          than the previous row must omit a different series of columns from
 
-          the rendered INSERT statement, which means it must be emitted as a
 
-          separate statement.   By passing this flag, the full set of rows
 
-          are guaranteed to be batchable into one batch; the cost however is
 
-          that server-side defaults which are invoked by an omitted column will
 
-          be skipped, so care must be taken to ensure that these are not
 
-          necessary.
 
-          .. warning::
 
-             When this flag is set, **server side default SQL values will
 
-             not be invoked** for those columns that are inserted as NULL;
 
-             the NULL value will be sent explicitly.   Care must be taken
 
-             to ensure that no server-side default functions need to be
 
-             invoked for the operation as a whole.
 
-          .. versionadded:: 1.1
 
-         .. seealso::
 
-             :ref:`bulk_operations`
 
-             :meth:`.Session.bulk_save_objects`
 
-             :meth:`.Session.bulk_update_mappings`
 
-         """
 
-         self._bulk_save_mappings(
 
-             mapper, mappings, False, False,
 
-             return_defaults, False, render_nulls)
 
-     def bulk_update_mappings(self, mapper, mappings):
 
-         """Perform a bulk update of the given list of mapping dictionaries.
 
-         The bulk update feature allows plain Python dictionaries to be used as
 
-         the source of simple UPDATE operations which can be more easily
 
-         grouped together into higher performing "executemany"
 
-         operations.  Using dictionaries, there is no "history" or session
 
-         state management features in use, reducing latency when updating
 
-         large numbers of simple rows.
 
-         .. versionadded:: 1.0.0
 
-         .. warning::
 
-             The bulk update feature allows for a lower-latency UPDATE
 
-             of rows at the expense of most other unit-of-work features.
 
-             Features such as object management, relationship handling,
 
-             and SQL clause support are **silently omitted** in favor of raw
 
-             UPDATES of records.
 
-             **Please read the list of caveats at** :ref:`bulk_operations`
 
-             **before using this method, and fully test and confirm the
 
-             functionality of all code developed using these systems.**
 
-         :param mapper: a mapped class, or the actual :class:`.Mapper` object,
 
-          representing the single kind of object represented within the mapping
 
-          list.
 
-         :param mappings: a list of dictionaries, each one containing the state
 
-          of the mapped row to be updated, in terms of the attribute names
 
-          on the mapped class.   If the mapping refers to multiple tables,
 
-          such as a joined-inheritance mapping, each dictionary may contain
 
-          keys corresponding to all tables.   All those keys which are present
 
-          and are not part of the primary key are applied to the SET clause
 
-          of the UPDATE statement; the primary key values, which are required,
 
-          are applied to the WHERE clause.
 
-         .. seealso::
 
-             :ref:`bulk_operations`
 
-             :meth:`.Session.bulk_insert_mappings`
 
-             :meth:`.Session.bulk_save_objects`
 
-         """
 
-         self._bulk_save_mappings(
 
-             mapper, mappings, True, False, False, False, False)
 
-     def _bulk_save_mappings(
 
-             self, mapper, mappings, isupdate, isstates,
 
-             return_defaults, update_changed_only, render_nulls):
 
-         mapper = _class_to_mapper(mapper)
 
-         self._flushing = True
 
-         transaction = self.begin(
 
-             subtransactions=True)
 
-         try:
 
-             if isupdate:
 
-                 persistence._bulk_update(
 
-                     mapper, mappings, transaction,
 
-                     isstates, update_changed_only)
 
-             else:
 
-                 persistence._bulk_insert(
 
-                     mapper, mappings, transaction,
 
-                     isstates, return_defaults, render_nulls)
 
-             transaction.commit()
 
-         except:
 
-             with util.safe_reraise():
 
-                 transaction.rollback(_capture_exception=True)
 
-         finally:
 
-             self._flushing = False
 
-     def is_modified(self, instance, include_collections=True,
 
-                     passive=True):
 
-         r"""Return ``True`` if the given instance has locally
 
-         modified attributes.
 
-         This method retrieves the history for each instrumented
 
-         attribute on the instance and performs a comparison of the current
 
-         value to its previously committed value, if any.
 
-         It is in effect a more expensive and accurate
 
-         version of checking for the given instance in the
 
-         :attr:`.Session.dirty` collection; a full test for
 
-         each attribute's net "dirty" status is performed.
 
-         E.g.::
 
-             return session.is_modified(someobject)
 
-         .. versionchanged:: 0.8
 
-             When using SQLAlchemy 0.7 and earlier, the ``passive``
 
-             flag should **always** be explicitly set to ``True``,
 
-             else SQL loads/autoflushes may proceed which can affect
 
-             the modified state itself:
 
-             ``session.is_modified(someobject, passive=True)``\ .
 
-             In 0.8 and above, the behavior is corrected and
 
-             this flag is ignored.
 
-         A few caveats to this method apply:
 
-         * Instances present in the :attr:`.Session.dirty` collection may
 
-           report ``False`` when tested with this method.  This is because
 
-           the object may have received change events via attribute mutation,
 
-           thus placing it in :attr:`.Session.dirty`, but ultimately the state
 
-           is the same as that loaded from the database, resulting in no net
 
-           change here.
 
-         * Scalar attributes may not have recorded the previously set
 
-           value when a new value was applied, if the attribute was not loaded,
 
-           or was expired, at the time the new value was received - in these
 
-           cases, the attribute is assumed to have a change, even if there is
 
-           ultimately no net change against its database value. SQLAlchemy in
 
-           most cases does not need the "old" value when a set event occurs, so
 
-           it skips the expense of a SQL call if the old value isn't present,
 
-           based on the assumption that an UPDATE of the scalar value is
 
-           usually needed, and in those few cases where it isn't, is less
 
-           expensive on average than issuing a defensive SELECT.
 
-           The "old" value is fetched unconditionally upon set only if the
 
-           attribute container has the ``active_history`` flag set to ``True``.
 
-           This flag is set typically for primary key attributes and scalar
 
-           object references that are not a simple many-to-one.  To set this
 
-           flag for any arbitrary mapped column, use the ``active_history``
 
-           argument with :func:`.column_property`.
 
-         :param instance: mapped instance to be tested for pending changes.
 
-         :param include_collections: Indicates if multivalued collections
 
-          should be included in the operation.  Setting this to ``False`` is a
 
-          way to detect only local-column based properties (i.e. scalar columns
 
-          or many-to-one foreign keys) that would result in an UPDATE for this
 
-          instance upon flush.
 
-         :param passive:
 
-          .. versionchanged:: 0.8
 
-              Ignored for backwards compatibility.
 
-              When using SQLAlchemy 0.7 and earlier, this flag should always
 
-              be set to ``True``.
 
-         """
 
-         state = object_state(instance)
 
-         if not state.modified:
 
-             return False
 
-         dict_ = state.dict
 
-         for attr in state.manager.attributes:
 
-             if \
 
-                     (
 
-                         not include_collections and
 
-                         hasattr(attr.impl, 'get_collection')
 
-                     ) or not hasattr(attr.impl, 'get_history'):
 
-                 continue
 
-             (added, unchanged, deleted) = \
 
-                 attr.impl.get_history(state, dict_,
 
-                                       passive=attributes.NO_CHANGE)
 
-             if added or deleted:
 
-                 return True
 
-         else:
 
-             return False
 
-     @property
 
-     def is_active(self):
 
-         """True if this :class:`.Session` is in "transaction mode" and
 
-         is not in "partial rollback" state.
 
-         The :class:`.Session` in its default mode of ``autocommit=False``
 
-         is essentially always in "transaction mode", in that a
 
-         :class:`.SessionTransaction` is associated with it as soon as
 
-         it is instantiated.  This :class:`.SessionTransaction` is immediately
 
-         replaced with a new one as soon as it is ended, due to a rollback,
 
-         commit, or close operation.
 
-         "Transaction mode" does *not* indicate whether
 
-         or not actual database connection resources are in use;  the
 
-         :class:`.SessionTransaction` object coordinates among zero or more
 
-         actual database transactions, and starts out with none, accumulating
 
-         individual DBAPI connections as different data sources are used
 
-         within its scope.   The best way to track when a particular
 
-         :class:`.Session` has actually begun to use DBAPI resources is to
 
-         implement a listener using the :meth:`.SessionEvents.after_begin`
 
-         method, which will deliver both the :class:`.Session` as well as the
 
-         target :class:`.Connection` to a user-defined event listener.
 
-         The "partial rollback" state refers to when an "inner" transaction,
 
-         typically used during a flush, encounters an error and emits a
 
-         rollback of the DBAPI connection.  At this point, the
 
-         :class:`.Session` is in "partial rollback" and awaits for the user to
 
-         call :meth:`.Session.rollback`, in order to close out the
 
-         transaction stack.  It is in this "partial rollback" period that the
 
-         :attr:`.is_active` flag returns False.  After the call to
 
-         :meth:`.Session.rollback`, the :class:`.SessionTransaction` is
 
-         replaced with a new one and :attr:`.is_active` returns ``True`` again.
 
-         When a :class:`.Session` is used in ``autocommit=True`` mode, the
 
-         :class:`.SessionTransaction` is only instantiated within the scope
 
-         of a flush call, or when :meth:`.Session.begin` is called.  So
 
-         :attr:`.is_active` will always be ``False`` outside of a flush or
 
-         :meth:`.Session.begin` block in this mode, and will be ``True``
 
-         within the :meth:`.Session.begin` block as long as it doesn't enter
 
-         "partial rollback" state.
 
-         From all the above, it follows that the only purpose to this flag is
 
-         for application frameworks that wish to detect is a "rollback" is
 
-         necessary within a generic error handling routine, for
 
-         :class:`.Session` objects that would otherwise be in
 
-         "partial rollback" mode.  In a typical integration case, this is also
 
-         not necessary as it is standard practice to emit
 
-         :meth:`.Session.rollback` unconditionally within the outermost
 
-         exception catch.
 
-         To track the transactional state of a :class:`.Session` fully,
 
-         use event listeners, primarily the :meth:`.SessionEvents.after_begin`,
 
-         :meth:`.SessionEvents.after_commit`,
 
-         :meth:`.SessionEvents.after_rollback` and related events.
 
-         """
 
-         return self.transaction and self.transaction.is_active
 
-     identity_map = None
 
-     """A mapping of object identities to objects themselves.
 
-     Iterating through ``Session.identity_map.values()`` provides
 
-     access to the full set of persistent objects (i.e., those
 
-     that have row identity) currently in the session.
 
-     .. seealso::
 
-         :func:`.identity_key` - helper function to produce the keys used
 
-         in this dictionary.
 
-     """
 
-     @property
 
-     def _dirty_states(self):
 
-         """The set of all persistent states considered dirty.
 
-         This method returns all states that were modified including
 
-         those that were possibly deleted.
 
-         """
 
-         return self.identity_map._dirty_states()
 
-     @property
 
-     def dirty(self):
 
-         """The set of all persistent instances considered dirty.
 
-         E.g.::
 
-             some_mapped_object in session.dirty
 
-         Instances are considered dirty when they were modified but not
 
-         deleted.
 
-         Note that this 'dirty' calculation is 'optimistic'; most
 
-         attribute-setting or collection modification operations will
 
-         mark an instance as 'dirty' and place it in this set, even if
 
-         there is no net change to the attribute's value.  At flush
 
-         time, the value of each attribute is compared to its
 
-         previously saved value, and if there's no net change, no SQL
 
-         operation will occur (this is a more expensive operation so
 
-         it's only done at flush time).
 
-         To check if an instance has actionable net changes to its
 
-         attributes, use the :meth:`.Session.is_modified` method.
 
-         """
 
-         return util.IdentitySet(
 
-             [state.obj()
 
-              for state in self._dirty_states
 
-              if state not in self._deleted])
 
-     @property
 
-     def deleted(self):
 
-         "The set of all instances marked as 'deleted' within this ``Session``"
 
-         return util.IdentitySet(list(self._deleted.values()))
 
-     @property
 
-     def new(self):
 
-         "The set of all instances marked as 'new' within this ``Session``."
 
-         return util.IdentitySet(list(self._new.values()))
 
- class sessionmaker(_SessionClassMethods):
 
-     """A configurable :class:`.Session` factory.
 
-     The :class:`.sessionmaker` factory generates new
 
-     :class:`.Session` objects when called, creating them given
 
-     the configurational arguments established here.
 
-     e.g.::
 
-         # global scope
 
-         Session = sessionmaker(autoflush=False)
 
-         # later, in a local scope, create and use a session:
 
-         sess = Session()
 
-     Any keyword arguments sent to the constructor itself will override the
 
-     "configured" keywords::
 
-         Session = sessionmaker()
 
-         # bind an individual session to a connection
 
-         sess = Session(bind=connection)
 
-     The class also includes a method :meth:`.configure`, which can
 
-     be used to specify additional keyword arguments to the factory, which
 
-     will take effect for subsequent :class:`.Session` objects generated.
 
-     This is usually used to associate one or more :class:`.Engine` objects
 
-     with an existing :class:`.sessionmaker` factory before it is first
 
-     used::
 
-         # application starts
 
-         Session = sessionmaker()
 
-         # ... later
 
-         engine = create_engine('sqlite:///foo.db')
 
-         Session.configure(bind=engine)
 
-         sess = Session()
 
-     .. seealso:
 
-         :ref:`session_getting` - introductory text on creating
 
-         sessions using :class:`.sessionmaker`.
 
-     """
 
-     def __init__(self, bind=None, class_=Session, autoflush=True,
 
-                  autocommit=False,
 
-                  expire_on_commit=True,
 
-                  info=None, **kw):
 
-         r"""Construct a new :class:`.sessionmaker`.
 
-         All arguments here except for ``class_`` correspond to arguments
 
-         accepted by :class:`.Session` directly.  See the
 
-         :meth:`.Session.__init__` docstring for more details on parameters.
 
-         :param bind: a :class:`.Engine` or other :class:`.Connectable` with
 
-          which newly created :class:`.Session` objects will be associated.
 
-         :param class_: class to use in order to create new :class:`.Session`
 
-          objects.  Defaults to :class:`.Session`.
 
-         :param autoflush: The autoflush setting to use with newly created
 
-          :class:`.Session` objects.
 
-         :param autocommit: The autocommit setting to use with newly created
 
-          :class:`.Session` objects.
 
-         :param expire_on_commit=True: the expire_on_commit setting to use
 
-          with newly created :class:`.Session` objects.
 
-         :param info: optional dictionary of information that will be available
 
-          via :attr:`.Session.info`.  Note this dictionary is *updated*, not
 
-          replaced, when the ``info`` parameter is specified to the specific
 
-          :class:`.Session` construction operation.
 
-          .. versionadded:: 0.9.0
 
-         :param \**kw: all other keyword arguments are passed to the
 
-          constructor of newly created :class:`.Session` objects.
 
-         """
 
-         kw['bind'] = bind
 
-         kw['autoflush'] = autoflush
 
-         kw['autocommit'] = autocommit
 
-         kw['expire_on_commit'] = expire_on_commit
 
-         if info is not None:
 
-             kw['info'] = info
 
-         self.kw = kw
 
-         # make our own subclass of the given class, so that
 
-         # events can be associated with it specifically.
 
-         self.class_ = type(class_.__name__, (class_,), {})
 
-     def __call__(self, **local_kw):
 
-         """Produce a new :class:`.Session` object using the configuration
 
-         established in this :class:`.sessionmaker`.
 
-         In Python, the ``__call__`` method is invoked on an object when
 
-         it is "called" in the same way as a function::
 
-             Session = sessionmaker()
 
-             session = Session()  # invokes sessionmaker.__call__()
 
-         """
 
-         for k, v in self.kw.items():
 
-             if k == 'info' and 'info' in local_kw:
 
-                 d = v.copy()
 
-                 d.update(local_kw['info'])
 
-                 local_kw['info'] = d
 
-             else:
 
-                 local_kw.setdefault(k, v)
 
-         return self.class_(**local_kw)
 
-     def configure(self, **new_kw):
 
-         """(Re)configure the arguments for this sessionmaker.
 
-         e.g.::
 
-             Session = sessionmaker()
 
-             Session.configure(bind=create_engine('sqlite://'))
 
-         """
 
-         self.kw.update(new_kw)
 
-     def __repr__(self):
 
-         return "%s(class_=%r,%s)" % (
 
-             self.__class__.__name__,
 
-             self.class_.__name__,
 
-             ", ".join("%s=%r" % (k, v) for k, v in self.kw.items())
 
-         )
 
- def make_transient(instance):
 
-     """Alter the state of the given instance so that it is :term:`transient`.
 
-     .. note::
 
-         :func:`.make_transient` is a special-case function for
 
-         advanced use cases only.
 
-     The given mapped instance is assumed to be in the :term:`persistent` or
 
-     :term:`detached` state.   The function will remove its association with any
 
-     :class:`.Session` as well as its :attr:`.InstanceState.identity`. The
 
-     effect is that the object will behave as though it were newly constructed,
 
-     except retaining any attribute / collection values that were loaded at the
 
-     time of the call.   The :attr:`.InstanceState.deleted` flag is also reset
 
-     if this object had been deleted as a result of using
 
-     :meth:`.Session.delete`.
 
-     .. warning::
 
-         :func:`.make_transient` does **not** "unexpire" or otherwise eagerly
 
-         load ORM-mapped attributes that are not currently loaded at the time
 
-         the function is called.   This includes attributes which:
 
-         * were expired via :meth:`.Session.expire`
 
-         * were expired as the natural effect of committing a session
 
-           transaction, e.g. :meth:`.Session.commit`
 
-         * are normally :term:`lazy loaded` but are not currently loaded
 
-         * are "deferred" via :ref:`deferred` and are not yet loaded
 
-         * were not present in the query which loaded this object, such as that
 
-           which is common in joined table inheritance and other scenarios.
 
-         After :func:`.make_transient` is called, unloaded attributes such
 
-         as those above will normally resolve to the value ``None`` when
 
-         accessed, or an empty collection for a collection-oriented attribute.
 
-         As the object is transient and un-associated with any database
 
-         identity, it will no longer retrieve these values.
 
-     .. seealso::
 
-         :func:`.make_transient_to_detached`
 
-     """
 
-     state = attributes.instance_state(instance)
 
-     s = _state_session(state)
 
-     if s:
 
-         s._expunge_states([state])
 
-     # remove expired state
 
-     state.expired_attributes.clear()
 
-     # remove deferred callables
 
-     if state.callables:
 
-         del state.callables
 
-     if state.key:
 
-         del state.key
 
-     if state._deleted:
 
-         del state._deleted
 
- def make_transient_to_detached(instance):
 
-     """Make the given transient instance :term:`detached`.
 
-     .. note::
 
-         :func:`.make_transient_to_detached` is a special-case function for
 
-         advanced use cases only.
 
-     All attribute history on the given instance
 
-     will be reset as though the instance were freshly loaded
 
-     from a query.  Missing attributes will be marked as expired.
 
-     The primary key attributes of the object, which are required, will be made
 
-     into the "key" of the instance.
 
-     The object can then be added to a session, or merged
 
-     possibly with the load=False flag, at which point it will look
 
-     as if it were loaded that way, without emitting SQL.
 
-     This is a special use case function that differs from a normal
 
-     call to :meth:`.Session.merge` in that a given persistent state
 
-     can be manufactured without any SQL calls.
 
-     .. versionadded:: 0.9.5
 
-     .. seealso::
 
-         :func:`.make_transient`
 
-     """
 
-     state = attributes.instance_state(instance)
 
-     if state.session_id or state.key:
 
-         raise sa_exc.InvalidRequestError(
 
-             "Given object must be transient")
 
-     state.key = state.mapper._identity_key_from_state(state)
 
-     if state._deleted:
 
-         del state._deleted
 
-     state._commit_all(state.dict)
 
-     state._expire_attributes(state.dict, state.unloaded)
 
- def object_session(instance):
 
-     """Return the :class:`.Session` to which the given instance belongs.
 
-     This is essentially the same as the :attr:`.InstanceState.session`
 
-     accessor.  See that attribute for details.
 
-     """
 
-     try:
 
-         state = attributes.instance_state(instance)
 
-     except exc.NO_STATE:
 
-         raise exc.UnmappedInstanceError(instance)
 
-     else:
 
-         return _state_session(state)
 
- _new_sessionid = util.counter()
 
 
  |